众所周知,C语言中有两种函数参数传递方式:值传递和地址传递。
指针常用来分配空间,其意义是指向一个有意义的地址。我们也通常用指针做参数来进行地址传递。
However,指针做参数都是地址传递吗?
请大家先看这样的一段程序:
#include <stdio.h> #include <string.h> #include <stdlib.h> void test(char*p) { p = (char*)malloc(sizeof (char) * 10); } int main() { char *ts = NULL; test(ts); strcpy(ts, "Succeed !"); puts(ts); return 0; }
以上程序当然是错误的:
1.不能达到为ts分配内存的目的。
2.造成内存泄露。
究其原因:错把test函数的参数传递当成了地址传递。
其实,真相是这样的:
1.栈上分配4字节给了ts,将其指向空地址。
2.调用test函数,将ts作为实参传递给形参p,即将test中的参数副本_p指向空地址。这其实是“值传递”,ts的值(即空地址)传递给了形参p,ts和p指向同一地址。
3.在堆上开辟一段空间,并将p的值修改为当前开辟空间的首地址。由值传递的单向性可知,ts本身的值并未改变,仍为空地址。故在strcpy()时出错。
知道了出错的原因,我们就能对其进行改正。
改正1.
可以改变ts指向,将其与p指向同一块地址。利用函数的返回值。
1.不能达到为ts分配内存的目的。
2.造成内存泄露。
究其原因:错把test函数的参数传递当成了地址传递。
其实,真相是这样的:
1.栈上分配4字节给了ts,将其指向空地址。
2.调用test函数,将ts作为实参传递给形参p,即将test中的参数副本_p指向空地址。这其实是“值传递”,ts的值(即空地址)传递给了形参p,ts和p指向同一地址。
3.在堆上开辟一段空间,并将p的值修改为当前开辟空间的首地址。由值传递的单向性可知,ts本身的值并未改变,仍为空地址。故在strcpy()时出错。
知道了出错的原因,我们就能对其进行改正。
改正1.
可以改变ts指向,将其与p指向同一块地址。利用函数的返回值。
char* test(char*p)
{
p = (char*)malloc(sizeof (char) * 10);
return p; // 切记:别返回栈内指针。
}
那么在main函数中调用test函数时:
改正2.
改变ts自身地址。这一招真绝。使用双重指针。
void test(char**p) { *p = (char*)malloc(sizeof (char) * 10); }
main函数中就这样调用test:
test(&ts); // 这传的才是ts自己的地址,而不是其保存的内容。地址传递。 free(ts);