(本文年代久远,请谨慎阅读)现有如下程序段:

1
2
3
4
5
6
7
8
9
10
11
void getmem(char **p,int n){
*p=(char *)malloc(n);
}
int main(void) {
// your code goes here
char *str;
getmem(&str,100);
strcpy(str,"hello");
printf("%s",str);free(str);
return 0;
}

执行无误,输出hello,没有问题;
修改之后如下:

1
2
3
4
5
6
7
8
9
10
11
void getmem(char *p,int n){ //一开始认为是多余的
p=(char *)malloc(n);
}
int main(void) {
// your code goes here
char *str;
getmem(str,100); //相应改为str
strcpy(str,"hello");
printf("%s",str);free(str);
return 0;
}

代码分析

上述输出为null,其实不小心犯了个低级错误,那就是:
调用getmem时是值传递,str本身在getmem之后并没有获得相应空间,原因即getmem中的*p 作为局部变量并不能将p返回到main函数,即它只让局部的p指向了一段空间,没有意义。

而如果形参改为开始的

1
getmem(char **p,int n)

调用时使用

1
getmem(&str,100);

其意思是:char *p即指向指针的指针,意为“p指向一个变量,此变量存放的不是具体数据,而是一个指针的地址”,p 即表示其所指的地址变量,显然,此处被指向的指针即str,那么getmem中的

1
*p=(char *)malloc(n);

即表示此“被指向的指针”,即str指向一段空间,而区别于值传递的是此处实参为&str,其结束调用后会改变其指向。

此处会改变的原因:本质仍为值传递,但是传递的不是此指针(不同于前面的getmem(str,100)),而是指针所存放的地址,其被 p所指向,然后在函数中通过p修改了p指向内容的值,即修改了str的地址,即调用后str指向发生改变。

注意

char *str中,str是一个地址,printf(str)中str也是个地址,只不过格式控制类型为%s,这样的print即从str地址开始一直输出,直到’\0’为止(终结符是系统自动加上的),这样便实现打印字符串的工作,好像str真作为一个变量存放了这个串,其实不然。

另外,不用函数的方式来开辟空间确实就不需要**p这么麻烦:

1
2
3
4
5
6
7
8
int main(void) {
// your code goes here
char *str;
str=(char *)malloc(100);
strcpy(str,"hello");
printf("%s",str);free(str);
return 0;
}

上述即可以完成对char *str开辟空间的工作,此外,除了用malloc手动申请空间,也可以用数组赋值的方式:

1
2
3
4
5
6
7
8
9
10
int main(void) {
// your code goes here
char *str;
char a[100];//利用系统自动为数组分配空间的特点
str=a; //这样也可以实现str指向一片连续空间
//str=(char *)malloc(100);
strcpy(str,"hello");
printf("%s",str);free(str);
return 0;
}