【C语言】动态经典试题练习
前言:
在上一章节讲解了动态的常见错误,在上上章节讲解了动态内存的概念。
古人云:
习题一
请大家看下面的习题,试着分析输出结果 / 找出代码错误的地方。
#include <stdio.h>void GetMemory(char* p)
{p = (char*)malloc(100);
}void Test(void)
{char* str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);
}int main()
{Test();return 0;
}
答案:
程序奔溃!!!
没有释放
大家写对了嘛??
分析步骤如下:
1. 在 Test
函数中,char* str = NULL;
声明了一个指向字符的指针 str
,并将其初始化为 NULL
。
2. 然后调用 GetMemory(str);
,(这里有个疑问,传过去的是 值 还是 址 )
是 值 传的是指针变量的本身那个,不是他的地址 &str
3. 在 GetMemory
函数内部,p = (char*)malloc(100);
分配了 100 字节的内存,并将这块内存的地址赋值给局部变量 p
。
但是,这个操作并没有改变 Test
函数中的 str
的值,因为 p
只是 str
的一个副本。
4. 回到 Test
函数,strcpy(str, "hello world");
这一行试图将字符串 "hello world" 复制到 str
指向的内存中。
但是,由于 str
仍然是 NULL
,这将导致未定义行为,通常会导致程序崩溃。
对NULL进行解引用会导致程序奔溃。
习题二
返回栈空间地址问题:
计算输出的结果
#include <stdio.h>
#include <string.h>
char* GetMemory(void)
{char p[] = "hello world";return p;
}void Test(void)
{char* str = NULL;str = GetMemory();printf(str);
}int main()
{Test();return 0;
}
答案如下:
你是否答对了呢?
分析步骤:
1. p[]
是一个局部数组,存储在 栈内存(Stack)中。当函数返回时,栈上的数据会被销毁,因此返回的指针指向的内存可能已经被其他数据覆盖。
PS:在问题一中 p = (char*)malloc(100);
这个是在堆区上申请空间,在堆区上申请有两种方式释放:1. 通过free来释放 2. 在整个程序运行后释放
2. str = GetMemory();
→ str
现在指向已经被销毁的栈内存。
printf(str);
→ 访问无效内存可能导致:程序崩溃
那么该如何修改呢?
法一:动态分配内存
运用到上面的堆区,就可以巧妙的解决这个问题
char* GetMemory(void)
{char* p = (char*)malloc(20); strcpy(p, "hello world"); return p;
}void Test(void)
{char* str = GetMemory();printf("%s\n", str);free(str);
}
法二:直接返回字符串字面量
char* GetMemory(void)
{return "hello world";
}void Test(void)
{char* str = GetMemory();printf("%s\n", str);
}
法三:使用静态存储
char* GetMemory(void)
{static char p[] = "hello world"; // static使p的生命周期延长到程序结束return p;
}
习题三
预测输出结果/寻找代码错误
void GetMemory(char** p, int num)
{*p = (char*)malloc(num);
}void Test(void)
{char* str = NULL;GetMemory(&str, 100);strcpy(str, "hello");printf(str);}int main()
{Test();return 0;
}
公布答案:
hello 未释放
分析步骤:
本题与第一道问题一样的,就不过多分析。
不会的在认真看一下习题一的分析。
修改意见:
free(str);
str = NULL;
习题四
题目如下:分析输出的结果
void Test(void)
{char* str = (char*)malloc(100);strcpy(str, "hello");free(str);if (str != NULL){strcpy(str, "world");printf(str);}
}int main()
{Test();return 0;
}
答案:是野指针。
分析步骤:
1. 释放内存后,str
仍然指向原来的内存地址,变成了一个“野指针”。由于 free
操作后 str
并没有被置为 NULL
,
2. strcpy(str, "world")
: 由于 str
是一个野指针,指向的内存已经被释放,再次写入数据会导致未定义行为。这可能会导致程序崩溃,或者数据被写入到其他程序使用的内存区域,引发难以调试的问题。
printf(str)
: 同样地,由于str
是一个野指针,尝试读取该内存区域的数据也会导致未定义行为。这可能会导致程序崩溃,或者输出不可预测的结果。
总结:
本章节讲解了四道有关内存的练习题目,来供大家练手。
希望对大家有所帮助。
PS:这些题目出自🐟《编写高质量的 C/C++ 程序》(附上链接https://view.officeapps.live.com/op/view.aspx?src=http%3A%2F%2Fstaff.ustc.edu.cn%2F~tongwh%2FCG_2019%2Fmaterials%2FCoding%2520Style.ppt&wdOrigin=BROWSELINK)
大家有兴趣的话可以自行练习。。