下面的代码在第2行接收到seg错误:
char *str = "string";
str[0] = 'z'; // could be also written as *str = 'z'
printf("%s\n", str);
虽然这个方法非常有效:
char str[] = "string";
str[0] = 'z';
printf("%s\n", str);
用MSVC和GCC测试。
下面的代码在第2行接收到seg错误:
char *str = "string";
str[0] = 'z'; // could be also written as *str = 'z'
printf("%s\n", str);
虽然这个方法非常有效:
char str[] = "string";
str[0] = 'z';
printf("%s\n", str);
用MSVC和GCC测试。
当前回答
这些答案大部分都是正确的,但为了更清楚一点……
人们所说的“只读内存”是ASM术语中的文本段。它是内存中加载指令的同一个地方。出于安全等明显的原因,这是只读的。当创建一个初始化为字符串的char*时,字符串数据被编译到文本段中,程序初始化指向文本段的指针。所以如果你想改变它,就死定了。段错误。
当作为数组编写时,编译器将初始化的字符串数据放在数据段中,这与全局变量等存在的位置相同。这个内存是可变的,因为数据段中没有指令。这一次,当编译器初始化字符数组(仍然只是一个char*)时,它指向的是数据段而不是文本段,您可以在运行时安全地更改文本段。
其他回答
char *str = "string";
上面的代码将str设置为指向在程序的二进制映像中硬编码的字面值“string”,它在内存中可能被标记为只读。
因此str[0]=试图写入应用程序的只读代码。我猜这可能依赖于编译器。
这些答案大部分都是正确的,但为了更清楚一点……
人们所说的“只读内存”是ASM术语中的文本段。它是内存中加载指令的同一个地方。出于安全等明显的原因,这是只读的。当创建一个初始化为字符串的char*时,字符串数据被编译到文本段中,程序初始化指向文本段的指针。所以如果你想改变它,就死定了。段错误。
当作为数组编写时,编译器将初始化的字符串数据放在数据段中,这与全局变量等存在的位置相同。这个内存是可变的,因为数据段中没有指令。这一次,当编译器初始化字符数组(仍然只是一个char*)时,它指向的是数据段而不是文本段,您可以在运行时安全地更改文本段。
当您试图访问不可访问的内存时,会导致分割错误。
Char *str是一个指向不可修改的字符串的指针(这是导致segfault的原因)。
而char str[]是一个数组,可以修改。
The C FAQ that @matli linked to mentions it, but no one else here has yet, so for clarification: if a string literal (double-quoted string in your source) is used anywhere other than to initialize a character array (ie: @Mark's second example, which works correctly), that string is stored by the compiler in a special static string table, which is akin to creating a global static variable (read-only, of course) that is essentially anonymous (has no variable "name"). The read-only part is the important part, and is why the @Mark's first code example segfaults.
通常,当程序运行时,字符串字面值存储在只读内存中。这是为了防止您意外地更改字符串常量。在第一个例子中,"string"存储在只读内存中,*str指向第一个字符。当您试图将第一个字符更改为'z'时,会发生段错误。
在第二个例子中,字符串"string"被编译器从其只读母数组复制到str[]数组中。然后允许更改第一个字符。你可以通过打印每个地址来检查:
printf("%p", str);
同样,在第二个例子中打印str的大小会显示编译器已经为它分配了7个字节:
printf("%d", sizeof(str));