指针参数在内存中的传递
代码一
View Code
void GetMemory(char *p , int num) { p = (char *)malloc(sizeof(char) *num); } int main() { char *str = NULL; GetMemory(str,100); //str 还是 NULL strcpy(str,"hello"); //运行出错 }
分析:编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是 _p,编译器使 _p = p。如果函数体内的程序修改了_p的内容,就导致参数p的内容作相应的修改。这就是指针可以用作输出参数的原因。在本例中,_p申请了新的内存,只是把_p所指的内存地址改变了,但是p丝毫未变。所以函数GetMemory并不能输出任何东西。事实上,每执行一次GetMemory就会泄露一块内存,因为没有用free释放内存。
如果非得要用指针参数去申请内存,那么应该改用“指向指针的指针”。
代码二
View Code
void GetMemory(char **p, int num) { *p = (char *)malloc(sizeof(char) * num); } int main() { char *str = NULL; GetMemory(&str,100); //看清传入的参数 strcpy(str,"hello"); prinf("%s",str); //顺利输出 free(str); //记得释放内存 }
对于理解“指向指针的指针”概念困难的同学,可以用函数返回值来传递内存。但是我似乎没有看出这种方法比代码而简单多少。
代码三
View Code
char* GetMemory(int num) { char *p = (char *)malloc(sizeof(char) * num); return p; } int main() { char *str = NULL; str = GetMemory(100); strcpy(str,"hello"); printf("%s",str); free(str); //记得释放内存呀 }
在写函数返回值来传递内存时,有人会不小心把return语句写错。比如返回“栈内存”的指针。(用人话讲 就是返回一个 在函数体内的局部变量,之所以不能这么干是因为函数执行结束时,这些局部变量所存储的空间会被释放)比如你不能这么写:
代码四
View Code
1 char* GetString(void) 2 { 3 char p[] = "hello world"; 4 return p; 5 } 6 7 int main() 8 { 9 char *str = NULL; 10 str = GetString(); 11 strcpy(str,"hello"); 12 printf("%s",str); 13 }
运行出来会打印出奇怪的东西,反正不是我们要的结果。编译的时候第4行会有警告,function returns address of local variable(函数返回了一个局部变量的地址) 。调试会发现执行str = GetString()后str不是NULL指针,也不是“hello world”。如果改成下面这段代码呢?
代码五
View Code
char* GetString(void) { char *p = "hello world"; return p; } int main() { char *str = NULL; str = GetString(); printf("%s",str); }
运行是可以的,但是这么写代码是有问题的,GetString函数里面的“hello world”是一个常量字符串,位于静态存储区域,它在程序生命期间恒定不变,无论什么时候调用这个函数,它返回的都是“hello world”。
最后整理 如何预防野指针
“野指针”不是NULL指针,是指向“垃圾”内存的指针。人们一般不会错用NULL指针,因为用if语句很容易判断。但是“野指针”是很危险的,if语句对它不起作用。
(1)指针变量没有被初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。所以,指针变量在创建的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。例如
char *p = NULL;
char *str = (char *) malloc(100);
char *p = NULL;
char *str = (char *) malloc(100);
(2)指针p被free或者delete之后,没有置为NULL,让人误以为p是个合法的指针。
(3)指针操作超越了变量的作用范围。这种情况让人防不胜防。