常见的动态内存错误总结(一)+https://developer.aliyun.com/article/1519315?spm=a2c6h.13148508.setting.14.25634f0eqyvtS5
六、动态开辟的内存未释放(内存泄漏)
代码一
void test() { int *p = (int *)malloc(100); if(NULL != p) { *p = 20; } } int main() { test(); while(1); }
如上代码中,在test函数中开辟了动态内存,然而却并没有在其中释放。整个程序中都没有释放动态内存,显然造成了内存泄漏。
代码二
void GetMemory(char **p, int num) { *p = (char *)malloc(num); } void Test(void) { char *str = NULL; GetMemory(&str, 100); strcpy(str, "hello"); printf(str); }
该代码同样没有进行内存释放。应当在程序结束之前,加上free(str); str = NULL;语句,完成“善后”工作。
七、返回栈空间地址的问题与野指针陷阱
代码一
*运行test函数,会有什么结果?能正确输字符串"hello"吗?
//运行test函数,会产生什么结果? char *Get() { char p[] = "hello"; return p; } void test() { char* str = NULL; str = Get(); printf(str); }1.
答案是不能,该代码会运行出错,因为该程序中的str指针,实际上是一个野指针。
在Get()函数中,开辟了一个字符数组p[ ]。char p[ ] 是一个临时的数组空间,里面存放了hello\0这6个字符。它是开辟在栈上的,出了函数就被销毁。
因此,虽然str接收了返回值字符数组的首元素地址p,但函数调用完毕后,由于函数栈空间销毁,数组空间已不存在。
str就成了指向无访问权限空间的野指针,在printf访问时出错。
结论
从函数返回一个指向临时在栈空间开辟的指针,就会有野指针访问的问题。因为在函数栈帧中创建的变量,出了函数,栈帧空间就销毁。空间销毁,而空间的地址还在使用,就会出错。
而若将char p[ ] 用static修饰,将p定义为静态变量,程序就能正常运行:
//ok char *Get() { static char p[] = "hello"; //加了static return p; } void test() { char* str = NULL; str = Get(); printf(str); }
因为在函数局部变量前用static修饰,变量就成了静态变量。
加了static的变量是在静态区开辟的,不是在栈里开辟的,因此p数组的的生命周期延长,在函数调用结束后,空间也未销毁。因此,str没有成为野指针,str中保存的指针p仍然有效。此时能够正常访问,并打印出字符串"hello"。
代码二
*运行test函数,会有什么结果?能正确输字符串"hello"吗?
//运行test函数,结果如何? char *Get() { char *p = "hello"; return p; } void test() { char* str = NULL; str = Get(); printf(str); }
答案是可以。该代码能够正常运行并输出"hello"。
该代码与代码一的区别在于,char* p 指向的是一个常量字符串"hello"。常量字符串是存放在静态区而不是栈区的,因此出了Get函数内存空间也不会销毁。在test函数中仍然可以正常访问。
(注意,由于常量字符串不能被改变,因此它的首元素地址的数据类型是const char* 。p在接收时,最好也把数据类型写成const char*,否则编译器会报警告。)
代码三
*该代码正确吗?
int* test2() { int a = 10; return &a; } int main() { int*p = test2(); printf("%d\n", *p); return 0; }
该代码自然是不正确。和上面的代码一一样,函数返回了局部变量的地址,造成了p的野指针问题。
代码四
*该代码正确吗?
int test2() { int a = 10; return a; } int main() { int p = test2(); printf("%d\n", p); return 0; }
该代码正确。因为返回的并不是变量的地址,而是变量的值。通过寄存器,test2函数能将局部变量的返回值带入main函数的变量p中。
代码五
//运行Test函数,会有什么结果? void Test(void) { char *str = (char *) malloc(100); strcpy(str, "hello"); free(str); //释放str if(str != NULL) { strcpy(str, "world"); printf(str); } }
在释放了str后,str成为野指针。str并未置NULL,进入 if 语句后,strcpy野指针非法访问,运行出错。
注意,free后必须先将指针置NULL。否则使用指针极易出现空指针访问错误!