对于为什么program1会分段错误而program2不会这样做,我无法理解这一点。
program1:
void cpy(char* p, char* q) {
while(*p++ = *q++);
}
int main() {
char* p;
char* q = "Bhargava";
cpy(p, q);
std::cout << "p = " << &p << std::endl;
}Program2:
void cpy(char* p, char* q) {
while(*p++ = *q++);
}
int main() {
char* p;
char* q = "Bhargava";
cpy(p, q);
std::cout << "p = " << p << std::endl;
}在program1中打印变量'p‘的地址有什么害处?
发布于 2020-04-09 18:56:35
这两个程序都已经调用了。
cpy(p, q);因为p是char*类型的,默认初始化为自动存储持续时间,这意味着它的值是不确定的。复制非std::byte类型或无符号窄字符类型的不确定值(此处为函数参数)已经具有未定义的行为。
然后,在cpy中对这个不确定值的算法和取消引用将继续导致具有未定义行为的操作,这可能比上面提到的未定义行为更有实际意义,因为很明显,如果p被认为具有一些随机值,操作系统不应该允许访问该随机地址的内存(造成分段错误的原因)。
未定义的行为意味着您无法保证程序行为。程序可能因错误而失败,也可能没有,它可能产生看似正确的输出,也可能没有。
在实践中,编译器可能正在优化其中一个程序中的p取消引用,而不是另一个程序,这样编译后的程序中永远不会有导致分段错误的内存访问,但如上所述,您没有任何保证,编译器可以输出任何内容。
线
char* q = "Bhargava";是不允许的,因为C++11至少应该产生这样的编译器诊断。甚至在C++11之前,标准C++就一直反对使用它。"Bhargava"对某些N具有const char[N]类型,因此可以将其分配给const char*,但不能分配给char*。后者最初被语言允许是出于向后兼容的原因。
发布于 2020-04-09 19:01:17
这两个程序都显示未定义的行为,因为p没有指向任何有效内存,其值未初始化,因此不确定,因此调用以p为目标的cpy()将写入随机内存,如果不是完全崩溃的话。
尽管如此,<< &p工作的原因是因为&p是p变量本身的地址,这是一个有效的地址。&p返回的类型是char**,operator<<没有特定的重载,但对void*有重载,char**是隐式可转换的。这个过载只是打印出了地址。
<< p不能工作的原因是operator<<对char*确实有一个特定的重载。该重载将地址视为C样式以空结尾的字符串的开始,并将打印从该地址开始的字符,直到到达'\0'字符为止。但是,由于p没有指向有效的C字符串,所以行为是未定义的。
要使这两个程序正常工作,您需要这样做:
Program1:
void cpy(char* p, const char* q) {
while(*p++ = *q++);
}
int main() {
char buffer[10];
char* p = buffer;
const char* q = "Bhargava";
cpy(p, q);
std::cout << "p = " << &p << std::endl;
}Program2:
void cpy(char* p, const char* q) {
while(*p++ = *q++);
}
int main() {
char buffer[10];
char* p = buffer;
const char* q = "Bhargava";
cpy(p, q);
std::cout << "p = " << p << std::endl;
}https://stackoverflow.com/questions/61128157
复制相似问题