为什么我在写“a”时会出现分段错误;char*s";用字符串文字初始化,但不是;字符s[]”;?
以下代码接收到线路2上的seg故障:为什么我在写“a”时会出现分段错误;char*s";用字符串文字初始化,但不是;字符s[]”;?,c,segmentation-fault,c-strings,C,Segmentation Fault,C Strings,以下代码接收到线路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进行测试。,因为在第一个示例的上下文中,“whatever”的类型是常量字符*(即使您将其分配给非常量字符
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进行测试。,因为在第一个示例的上下文中,“whatever”
的类型是常量字符*
(即使您将其分配给非常量字符*),这意味着您不应该尝试对其进行写入
编译器通过将字符串放入内存的只读部分来实现这一点,因此写入该字符串会生成一个segfault。因为在第一个示例的上下文中,“whatever”
的类型是const char*
(即使您将其分配给非const char*),这意味着您不应该尝试写入它
编译器通过将字符串放入内存的只读部分来实现这一点,因此写入它会生成segfault。通常,当程序运行时,字符串文本存储在只读内存中。这是为了防止意外更改字符串常量。在第一个示例中,
“string”
存储在只读内存中,*str
指向第一个字符。当您尝试将第一个字符更改为'z'
时,会发生SEGFULT
在第二个示例中,编译器将字符串“string”
从其只读主目录复制到str[]
数组。然后允许更改第一个字符。您可以通过打印以下地址来检查:
printf("%p", str);
此外,在第二个示例中打印str
的大小将显示编译器已为其分配了7个字节:
printf("%d", sizeof(str));
通常,当程序运行时,字符串文本存储在只读内存中。这是为了防止意外更改字符串常量。在第一个示例中,
“string”
存储在只读内存中,*str
指向第一个字符。当您尝试将第一个字符更改为'z'
时,会发生SEGFULT
在第二个示例中,编译器将字符串“string”
从其只读主目录复制到str[]
数组。然后允许更改第一个字符。您可以通过打印以下地址来检查:
printf("%p", str);
此外,在第二个示例中打印str
的大小将显示编译器已为其分配了7个字节:
printf("%d", sizeof(str));
上述设置将str
指向文本值“string”
,该值在程序的二进制图像中硬编码,在内存中可能标记为只读
因此,str[0]=
正在尝试写入应用程序的只读代码。我想这可能是编译器依赖的
上述设置将str
指向文本值“string”
,该值在程序的二进制图像中硬编码,在内存中可能标记为只读
因此,str[0]=
正在尝试写入应用程序的只读代码。不过,我想这可能与编译器有关。在第一段代码中,“string”是一个字符串常量,字符串常量永远不应该被修改,因为它们通常被放在只读内存中。“str”是用于修改常量的指针
在第二段代码中,“string”是数组初始值设定项,有点像
char str[7] = { 's', 't', 'r', 'i', 'n', 'g', '\0' };
“str”是在堆栈上分配的数组,可以自由修改。在第一个代码中,“string”是一个字符串常量,字符串常量永远不应该修改,因为它们经常被放入只读内存中。“str”是用于修改常量的指针
char *str = "string";
在第二段代码中,“string”是数组初始值设定项,有点像
char str[7] = { 's', 't', 'r', 'i', 'n', 'g', '\0' };
“str”是在堆栈上分配的数组,可以自由修改
char *str = "string";
分配一个指向字符串文字的指针,编译器将其放入可执行文件的不可修改部分
char str[] = "string";
分配并初始化可修改的本地数组
分配一个指向字符串文字的指针,编译器将其放入可执行文件的不可修改部分
char str[] = "string";
分配和初始化可修改的本地数组字符串文字(如“String”)可能作为只读数据分配到可执行文件的地址空间中(给或取编译器)。当你去触摸它时,它会因为你在它的泳衣区而感到惊慌失措,并让你知道它有seg故障
在第一个示例中,您将获得指向该常量数据的指针。在第二个示例中,您正在使用常量数据的副本初始化一个由7个字符组成的数组。字符串文字(如“String”)可能作为只读数据分配到可执行文件的地址空间中(给出或获取编译器)。当你去触摸它时,它会因为你在它的泳衣区而感到惊慌失措,并让你知道它有seg故障
在第一个示例中,您将获得指向该常量数据的指针。在第二个示例中,您正在使用常量数据的副本初始化一个由7个字符组成的数组。
char *str = "string";
行定义指针并将其指向文字字符串。文字字符串不可写,因此执行以下操作时:
str[0] = 'z';
你有seg故障。在某些平台上,文字可能位于可写内存中,因此您不会看到segfault,但无论如何它都是无效代码(导致未定义的行为)
该行:
char str[] = "string";
分配一个字符数组并将文本字符串复制到该数组中,该数组是完全可写的,因此后续更新没有问题。
char *str = "string";
行定义指针并将其指向文字字符串。文字字符串不可写,因此执行以下操作时:
str[0] = 'z';
你有seg故障。在某些平台上,文字可能位于可写内存中,因此您不会看到segfault,但无论如何它都是无效代码(导致未定义的行为)
该行:
char str[] = "string";
分配一个字符数组并char *c = "abc";
/* __unnamed is magic because modifying it gives UB. */
static char __unnamed[] = "abc";
char *c = __unnamed;
char s[] = "abc", t[3] = "abc";
char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };
char *p = "abc";
#include <stdio.h>
int main(void) {
char *s = "abc";
printf("%s\n", s);
return 0;
}
gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o
char *s = "abc";
8: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp)
f: 00
c: R_X86_64_32S .rodata
char s[] = "abc";
17: c7 45 f0 61 62 63 00 movl $0x636261,-0x10(%rbp)
readelf -l a.out
Section to Segment mapping:
Segment Sections...
02 .text .rodata
char a[] = "string literal copied to stack";
char *p = "string literal referenced by p";