过去几个小时我遇到了一个问题,虽然我明白了。这是我的麻烦:
void cut_str(char* entry, int offset) {
strcpy(entry, entry + offset);
}
char works[128] = "example1\0";
char* doesnt = "example2\0";
printf("output:\n");
cut_str(works, 2);
printf("%s\n", works);
cut_str(doesnt, 2);
printf("%s\n", doesnt);
// output:
// ample1
// Segmentation: fault
我觉得char * / char []有一些重要的东西,我没有来到这里。
答案 0 :(得分:11)
区别在于doesnt
指向属于字符串常量的内存,因此不可写。
当你这样做时
char works[128] = "example1\0";
编译器将不可写字符串的内容复制到可写数组中。顺便说一下,\0
不是必需的。
但是,当你这样做时,
char* doesnt = "example2\0";
编译器使指针指向不可写的内存区域。同样,编译器将插入\0
。
如果您使用gcc
,可以让它警告您使用字符串文字初始化可写char *
。选项为-Wwrite-strings
。您将收到如下警告:
warning: initialization discards qualifiers from pointer target type
声明doesnt
指针的正确方法如下:
const char* doesnt = "example2\0";
答案 1 :(得分:4)
类型char[]
和char *
非常相似,所以你是对的。不同之处在于初始化类型的对象时会发生什么。类型为works
的对象char[]
在堆栈上为其分配了128个字节的变量存储空间。您的对象doesnt
,类型为char *
,在堆栈中没有存储空间。
C标准未指定存储doesnt
字符串的确切位置,但很可能它存储在加载程序执行时加载的不可修改数据段中。这不是变量存储。因此,当您尝试改变它时会出现段错误。
答案 2 :(得分:3)
这会在堆栈上分配128个字节,并使用名称works
来引用其地址:
char works[128];
所以works
是指向可写内存的指针。
这会创建一个字符串文字,它位于只读内存中,并使用名称doesnt
来引用其地址:
char * doesnt = "example2\0";
您可以将数据写入works
,因为它指向可写内存。您无法将数据写入doesnt
,因为它指向只读内存。
另外,请注意,您不必使用"\0"
结束字符串文字,因为所有字符串文字都会隐式地在字符串末尾添加零字节。