给出一个字符串,比方说,
char *str = "Hello,StackOverflow!"
char newStr[30];
int l = strlen(str);
for(int i =0 ; i<l ; i ++ )
newStr[i] = str[i];
printf("%s" , newStr);
现在,我们知道c-string的最后一个字符必须是'\0'
,因为这里我们没有明确地做同样的事情(在字符串newStr的最后一个索引处存储'\ 0'),这个程序应该崩溃,因为printf将找不到字符串的结尾。
但是我注意到它有时工作得很好,有时却没有。可能是什么问题呢 ?它几乎每次都在工作。是不应该崩溃或给出一些运行时错误?
C ++中也会出现同样的情况吗?
答案 0 :(得分:6)
没有。它会调用未定义的行为 - 这意味着它不会崩溃 - 它可以做任何事情,例如nasal demons.
此外,“给出运行时错误” - 这取决于运行时错误的含义。 C没有动态运行时 - 如果您期望异常的格式错误消息,则不会发生。会发生什么情况最有可能是segmentation fault.
总而言之,如果一个人导致/使用未定义的行为,他就不能依赖它崩溃或不崩溃。
答案 1 :(得分:3)
“崩溃”不保证。不正确地处理字符串中的空终止符的程序 - 更通常是访问缓冲区边界之外的数据 - 或者违反printf
格式字符串,可能看起来很好,功能正常,而不是导致段错误。但这只是偶然事件:代码的行为未定义。
在C ++中也是如此。
答案 2 :(得分:2)
我怀疑大多数时候它会继续印刷“!”并继续在内存中,直到它达到NULL。哪个可能导致崩溃,但不必。
这就是为什么最好:
memset(newStr, 0, 30);
或
// This works because string literals guarantee a '\0' is present
// but the strlen returns everything up until the '\0'
int l = strlen(str) + 1;
这也有效,但我觉得它不像在strlen中添加一个那样清楚:
for(i =0 ; i<=l ; i ++ )
正如defination of strlen暗示你需要的那样。
答案 3 :(得分:1)
偶然地,大部分时间 newStr
中未初始化的字节恰好是0
。
答案 4 :(得分:1)
您的程序有未定义的行为,因为您承诺使用指向以null结尾的字符串的指针调用printf
但未能这样做。任何事情都可能发生,但你的程序根本不正确。
具体来说,在逐个读取数组元素以找到空终止符时,程序最终将访问一个未初始化的变量,即UB。
答案 5 :(得分:0)
在C的大多数实现中,读取尚未初始化为字符的字节的行为是 undefined 。有时printf可能写入垃圾,有时程序可能会在最后一个字符后找到空字节\ 0并正常终止。在极少数情况下,它可能会导致崩溃。 这就是为什么你看到运行程序时会发生变化的原因。这取决于您使用的编译器,以及您为该阵列分配的内存位置。
(也就是说,如果你的程序会编译 - 你已经没有分号了)