一、例题
试问该段代码能打印什么,或者不能打印什么,说出理由
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<string.h> #include<stdlib.h> void getmemory( char *p) { p = ( char *)malloc( 100 ); } void test() { char *str = NULL; getmemory(str); strcpy(str, "hello world" ); printf( "%s" ,str); } int main() { test(); return 0 ; } |
这段代码乍一看好像没有啥问题,test函数进去创建一个str嘛,然后str传给getmemory函数,开辟一块空间,然后hello world这字符串放进开辟的空间里,然后打印str也就是hello world嘛。
但是,上面的思路是完全错误的,代码完全无法运行,解释如下:
-
第一:你str传到getmemory函数里,p开辟一个空间,被开辟的空间和str没有关系
(传值调用和传址调用的区别) - 第二:你getmemory函数出来之后,开辟的空间没有释放掉,而且你p由于函数的结束已经销毁了,p销毁之后再也无法找到开辟的空间,造成内存泄漏
就比如p是一个警察头子,开辟的空间是卧底,只有p知道那个卧底,你现在警察头子死了,再也没法证明卧底是卧底了
也就是说p消失后,没办法再对开辟的空间进行释放,这时就会造成内存泄露
二、2种改进方法
法1:二级指针(传址调用)
代码如下(示例):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
void getmemory( char **p) { *p = ( char *) malloc (100); //p是str地址,*p是str } void test() { char *str = NULL; getmemory(&str); strcpy (str, "hello world" ); printf ( "%s" ,str); free (str); str = NULL; } int main() { test(); return 0; } |
因为之前的传值调用没法让p和str建立联系,那我们就传地址,开辟一块空间出来赋给*p
要注意的是,p是str地址嘛,*p也就是str,到这里,str掌握了新开辟空间的控制权。然后getmemory函数出来,进行strcpy和printf操作,最后不要忘记free掉原先的空间。
法2:返回指针
代码如下(示例):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
char * getmemory( char *p) { p = ( char *) malloc (100); return p; } void test() { char *str = NULL; str=getmemory(str); strcpy (str, "hello world" ); printf ( "%s" , str); free (str); str = NULL; } int main() { test(); return 0; } |
因为这里是开辟了一块空间给指针p管理嘛,str和p没有建立联系,那你直接函数返回p这个指针然后赋值给str即可,随后操作和方法1一样
总结
本文介绍了动态内存分配的常见例题及两种改进方法,读者需要理解为何会发生内存泄露和传值与传址调用的区别就可以熟练解决这类问题。以上,祝读者学习愉快~希望大家以后多多支持服务器之家!
原文链接:https://blog.csdn.net/m0_57180439/article/details/120652651