鉴于以下计划。
int main() {
char *str = "hello word";
str[0] = 'a';
return 0;
}
上述程序会引发分段错误。我知道它会抛出,因为只读段包含hello世界,并且无法修改。如果在L1缓存(处理器内部)中完成从“h”变为“a”的存储指令,并且仅当页面从L3刷新到主存时MMU才会进入图像,几乎立即抛出分段故障。
以下代码实际上做同样的事情,不会导致任何分段错误。为什么呢?
int main() {
char str[] = {'h','e','l','l','o',' ','w','o','r','l','d','\0'};
str[0] = 'a';
return 0;
}
答案 0 :(得分:3)
处理器缓存具有与每个缓存行关联的标记,这些标记告诉它应用于当前在该缓存行中保存的内存的权限。因此,在尝试写入高速缓存时,(通常)将立即捕获写入只读存储器的尝试;它不会等到该缓存行被刷新到主存储器。
就两个例子之间的差异而言,它非常简单:第一个定义了一个静态分配的字符串文字。尝试修改该字符串文字会导致未定义的行为。第二个定义了一个初始化为特定值的char数组 - 但在初始化之后,它几乎与任何其他数组一样。特别是,修改数组内容的结果已经明确定义。
答案 1 :(得分:2)
在第二部分,你正在复制。虽然在第一个你不是。
char str[] = {'h','e','l','l','o',' ','w','o','r','l','d','\0'};
这里str
是在堆栈上创建的数组。要str
,正在复制内容。怎么进 -
char *str = "hello word";
str
指向驻留在不可修改部分的数据。所以,你不能和尝试时的结果分段错误。
评论说明
我不认为,原始数据类型C和C ++会改变它的规则。来自ISO / IEC 14882:2003(E),第8.5.2节
1. A char array (whether plain char, signed char, or unsigned char) can be
initialized by a string- literal (optionally enclosed in braces); a wchar_t
array can be initialized by a wide string-literal (option- ally enclosed in
braces); successive characters of the string-literal initialize the members of
the array.
[Example:
char msg[] = "Syntax error on line %s\n"; shows a character array
whose members are initialized with a string-literal. Note that because
’\n’ is a single character and because a trailing ’\0’ is appended,
sizeof(msg) is 25.
]
2. There shall not be more initializers than there are array elements.
[Example:
char cv[4] = "asdf" ;// error is ill-formed since there is no space for the implied trailing ’\0’.
]
因此,示例2清除了疑问。