[英]Not null-terminating a C-style string
给定一个字符串,说,
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字符串的最后一个字符必须为'\\0'
,因为在这里我们没有明确地执行相同的操作(将'\\ 0'存储在字符串newStr的最后一个索引中),所以该程序应该崩溃,因为printf找不到字符串的结尾。
但是我注意到它有时工作正常,有时却不行。 可能是什么问题呢 ? 实际上,它几乎每次都在工作。 它不是应该崩溃还是给出一些运行时错误?
在C ++中也会一样吗?
不能保证“崩溃”。 一个不正确地处理字符串中的空终止符的程序-更普遍地访问缓冲区边界之外的数据-或违反了printf
格式的字符串,该程序似乎可以正常运行,正常运行,并且不会引起例如段错误。 但这只是偶然:代码的行为是不确定的。
在C ++中将是相同的。
我怀疑大多数情况下它会一直打印超过“!” 并继续进入内存,直到它达到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 ++ )
偶然地,在您的特定情况下, 大多数时候 newStr
的未初始化字节碰巧是0
。
您的程序具有未定义的行为,因为您答应使用指向以null终止的字符串的指针来调用printf
,但是这样做失败。 可能发生任何事情,但是您的程序根本不正确。
具体来说,在逐一读取数组元素以找到空终止符的同时,程序最终将访问未初始化的变量UB。
在大多数C的实现中,尚未读取未初始化为字符的字节的行为是不确定的。有时printf可能会写入垃圾,有时程序可能会在最后一个字符之后找到一个空字节\\ 0并正常终止。 在极少数情况下,它可能会导致崩溃。 这就是为什么您看到运行程序时会发生变化的原因。 这取决于您使用的编译器,以及在该数组中分配的内存位置之后的内存位置。
(也就是说,如果您的程序可以编译-您就不用分号了)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.