关于动态内存传递的一些知识

动态内存传递一直都是一个难点,稍不留神就会掉到陷阱中去,最近正好学到动态内存传递的知识,就记下来了。首先看看下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<cstring>
#include<malloc.h>

using namespace std;

void GetMemory(char *p,int num)
{
p = (char *)malloc(sizeof(char)*num);
};

int main(void)
{
char *str = NULL;
GetMemory(str,100);
strcpy(str,"hello");
return 0;
}

咋一看,好像没有什么错误,其实这个程序是不能编译通过的,它是有错误的:
问题出在函数GetMemory中,void GetMemory(char *p,int num)中的*p实际上是主函数中的str的一个副本,编译器总是要为函数的每一个参数制作临时副本。在本例中,p申请了新的内存,只是把p所指的内存地址改变了,但是str丝毫没有改变,还是指向NULL 的地址,因为函数GetMemory没有返回值,因此str并不指向p所申请的那段内存,所以函数GetMemory 并不能输出任何东西,最终会造成内存泄漏

如果一定要用指针参数去申请内存,那么应该采用指向指针的指针,传str的地址给函数GetMemory函数。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<cstring>
#include<malloc.h>

using namespace std;

void GetMemory(char **p,int num)
{
*p = (char *)malloc(sizeof(char)*num);
};

int main(void)
{
char *str = NULL;
GetMemory(&str,100);
strcpy(str,"hello");
return 0;
}

此时是将指向NULL地址的指针传递给了参数char **p那么*p也就可以表示NULL的地址了,对于的str也就是字符串的值,这样才可以真正意义上实现地址的同步改变。

我们再看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<iostream>
#include<cstring>
void GetMemory2(int *z)
{
*z=5;
};
int main()
{
int v;
GetMemory2(&v);
cout<<v<<endl;
return 0;
}

GetMemory2把v的地址传了进来,*z是地址里的值,是v的副本,通过直接修改地址里面的值,不需要有返回值,也把v给修改了,因为v所指向地址的值发生了改变。
其实第一个函数只是改的p的值,并未影响str,而第三个改变的是传递进来的指针指向的值,其实还可以通过返回值来用第一个函数。而第二个函数使用指向指针的指针作为参数,修改的是*p也就是传递进来的str的地址。所以可以更改成功。原理同第三个函数。
小结:动态传递这类问题比较复杂,具体还需要大家平时多注意,多揣摩,多实践。