5

在过去的几个小时里,我在一个我理解的问题上遇到了麻烦。这是我的麻烦:

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[] 有一些重要的东西我没有说到这里。

4

3 回答 3

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";
于 2012-06-29T01:20:02.230 回答
4

类型char[]char *非常相似,所以你是对的。不同之处在于初始化类型的对象时会发生什么。您的 objectworks类型char[],在堆栈上为其分配了 128 字节的变量存储空间。您的 object doesnt, type char *在堆栈上没有存储空间。

C 标准没有指定字符串的确切doesnt存储位置,但很可能它存储在加载程序以执行时加载的不可修改数据段中。这不是变量存储。因此,当您尝试改变它时会出现段错误。

于 2012-06-29T01:25:24.333 回答
3

这会在堆栈上分配 128 个字节,并使用名称works来引用其地址:

char works[128];

works指向可写内存的指针也是如此。

这将创建一个字符串文字,它位于只读内存中,并使用名称doesnt来引用其地址:

char * doesnt = "example2\0";

您可以将数据写入works,因为它指向可写内存。您不能将数据写入doesnt,因为它指向只读内存。

另外,请注意,您不必以 结束字符串文字"\0",因为所有字符串文字都会在字符串末尾隐式添加一个零字节。

于 2012-06-29T01:23:43.563 回答