时间:2023-02-27 10:34:01 | 栏目:C代码 | 点击:次
当我们用动态内存分配函数来编写程序时,在编写的过程中常常会产生一些不易被察觉,被发现的错误,例如对NULL指针的解引用操作,对动态开辟空间的越界访问,使用free释放非动态开辟的空间,使用free释放动态内存中的一部分,对同一块动态开辟的空间,多次释放,动态开辟空间忘记释放。下面我们挨个来分析,刨析一下这些个常见的动态内存开辟的问题。
代码如下(示例):
错误示例: //动态内存开辟 int main() { int* p = malloc(100000000000); //没有对mollac函数的返回值做判空处理 int i = 0; for (i = 0; i < 10; i++) { *(p + i) = 5; } return 0; } 正确示例: //动态内存开辟 int main() { int* p = malloc(100000000000); if (p == NULL) { return 1; } int i = 0; for (i = 0; i < 10; i++) { *(p + i) = 5; } for (i = 0; i < 10; i++) { printf("%d ", p[i]); } free(p); p = NULL; return 0; }
代码如下(示例):
错误示例: //动态内存开辟 int main() { int* p = (int*)malloc(10*sizeof(int)); if (p == NULL) { return 1; } int i = 0; //越界访问 for (i = 0; i < 40; i++)//malloc函数只是开辟了十个整型的空间,这里却要访问四十个元素。 { *(p + i) = 5; } for (i = 0; i < 40; i++) { printf("%d ", p[i]); } free(p); p = NULL; return 0; } 正确示例: //动态内存开辟 int main() { int* p = (int*)malloc(10*sizeof(int)); if (p == NULL) { return 1; } int i = 0; for (i = 0; i < 10; i++) *(p + i) = 5; } for (i = 0; i < 10; i++) { printf("%d ", p[i]); } free(p); p = NULL; return 0; }
代码如下(示例):
//动态内存开辟 int main() { int arr[10] = { 0 };//栈区 int* p = arr; free(p);//使用free释放非动态开辟的空间 p = NULL; return 0; }
代码如下(示例):
//动态内存开辟 int main() { int* p = malloc(10 * sizeof(int)); if (p == NULL) { return 1; } int i = 0; for (i = 0; i < 5; i++) { *p++ = i;//1:p一直往后走之后没人知道起始空间的位置在哪,2:p释放的只是后面空间的一部分,前面的空间并没有得到释放。 } free(p); p = NULL; return 0; }
代码如下(示例):
//动态内存开辟 int main() { int* p = malloc(10 * sizeof(int)); //使用 //释放 free(p); //再次释放 free(p);//free要是传的是空指针什么事都不会发生。 p = NULL; return 0; }
代码如下(示例):
void test() { int* p = malloc(10 * sizeof(int)); if (p == NULL) { return 1; } //使用 //忘记释放 } //动态内存开辟 int main() { test(); return 0; }
例题分析: 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; }
程序运行结果:
拷贝不成功,程序直接挂掉。
原因分析:
str传给GetMemory函数的时候是值传递,所以GetMemory函数的形参p是str的一份临时拷贝。
在GetMemory函数内部动态申请空间的地址,存放在P中,不会影响外面str,所以当GetMemory函数返回
之后,str任然是NULL指针,所以strcpy会失败。
当GetMemory函数返回之后,形参p销毁,使得动态开辟的100个字节存在内存泄漏。
正确代码:
//第一种改法: char* GetMemory(char* p) { p = (char*)malloc(100); return p; } void test(void) { char* str = NULL; str = GetMemory(str); strcpy(str, "hello world"); printf(str); free(str); str = NULL; } int main() { test(); return 0; } //第二种改法: char* GetMemory(char** p) { *p = (char*)malloc(100); } void test(void) { char* str = NULL; GetMemory(&str); strcpy(str, "hello world"); printf(str); free(str); str = NULL; } int main() { test(); return 0; }
代码如下(示例):
//例题分析: char* GetMemory(void) { char p[] = "hello world"; return p; } void Test(void) { char* str = NULL; str = GetMemory(); printf(str); } int main() { test(); return 0; }
程序运行结果:
打印不成功,打印的都是随机值
原因分析:
GetMemory函数内部创建的数组是在栈区上创建的
出了函数,p的数组的空间就还给了操作系统
返回的地址是没有实际意义的,如果通过返回的地址,去访问内存就是非法访问内存。
正确代码:
char* GetMemory(void) { static char p[] = "hello world"; return p; } void test(void) { char* str = NULL; str = GetMemory(); printf(str); } int main() { test(); return 0; }
代码如下(示例)
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; }
错误分析:
申请的动态内存空间使用完之后没有及时free释放掉。
正确代码:
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; } int main() { test(); return 0; }
代码如下(示例)
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; }
错误分析:
申请的空间已经free释放还给操作系统了,及时str还记得这块空间的起始地址,但是也不能访问,属于非法访问内存空间。
free完之后要及时把str置成NULL指针。
正确代码:
void test(void) { char* str = (char*)malloc(100); strcpy(str, "hello"); free(str); str = NULL; if (str != NULL) { strcpy(str, "world"); printf(str); } } int main() { test(); return 0; }
上述给大家简单介绍了动态内存开辟常见的几种问题,也分析了往年的几道面试题里面的错误,让我们加深了对这一章的理解,后续自己使用的时候可以有效的规避掉这些问题。相信大家都学会了。如果上述文章有任何问题 ,欢迎大佬们提出质疑,我会虚心学习和改正,最重要的是能共同进步,共同成长,学习好编程。