指针赋值与strcpy
看下面的代码与错误:
char *a;
char *b;
char *c = "learnmore";
// 赋值
a = c;
// segmentation fault
strcpy(b, c);
刚开始学习c的时候总是会犯这个错误,就是分不清什么时候给指针赋值,什么时候需要复制数据。 像上面这种情况,赋值是正常的,strcpy会出现问题,因为strcpy需要目标指针有足够的空间,未经初始化的指针没有合法的空间来存放字符串c。解决这个问题可以将b定义为数组或malloc显示的分配空间即可。
还有一点就是在定义字符串数据的时候最好加上const关键字,因为字符串字面量是存储在常量区的,这样在出现类似于c[1] = 'c';
的修改操作的时候,编译器会提示错误,方便定位错误。
再看一段代码:
void test(char *a){
a = "aaaa";
printf("%p\n", a);
}
int main(){
char *b;
test(b);
printf("%s, %p\n", b, b);
return 0;
}
我们想通过调用test函数给主函数里面的b指针赋一个值,第一感觉这样可能是对的,但是一样会出现"segmentation fault"错误,因为指针b是未经初始化的,地址为nil。
那是不是给b初始化一下就可以了呢?将b的声明改为定义char *b = "b";
,这个b是经过初始化的,这样不会出现报错,但是在主函数打印b的值发现还是b。
c语言的函数参数是按值传递的,当参数为指针的时候,可以在被调用的函数内部修改主函数里面的值,之所以出现上述的情况是因为test函数的参数a其实是主函数b的副本,两个变量的值指向同一块地址,并不能理解成主函数中的b与test的参数a是同一个变量。当我们修改test函数内部a的值,将其设置为"aaaa"的时候,也就是将参数a的值指向了"aaaa"所在的地址。这并不会影响主函数b的值。
可以通过下面的代码解决问题:
char *test(){
return "aaaa";
}
int main(){
char *b;
b = test();
printf("%s, %p\n", b, b);
return 0;
}
这种写法可行是因为字符串字面量地址存储在内存的常量区,不可修改,所以在程序的生命周期内也就不会被回收。 如果将test函数里面的字符串定义为数组,test函数执行结束后,栈空间内的变量会被回收,所以在编译的时候会返回如下错误,行为是不可定义的:
function returns address of local variable
第二种写法:
void test(char *a){
strcpy(a, "aaaa");
}
int main(){
char b[5];
test(b);
printf("%s, %p\n", b, b);
return 0;
}
再看下面这段代码:
int main(){
char *b;
strcpy(b, "aaa");
printf("%s, %p\n", b, &b);
return 0;
}
这段代码应该是报错才对,但是新版本的gcc编译器可能也没有报错。
上面的写法可能并不如使用malloc
优雅,因为总是涉及到栈空间在函数间传递的问题。
总之,在读取或赋值存储器的数据的时候,一定要保证有足够可用的空间。
(完)
- 本文作者:吴泽辉
- 本文链接:https://mutex.top/posts/e609c628/
- 发表日期:2018年6月14日
- 版权声明:本文章为原创,采用《知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议》进行许可