不为null终止C样式字符串

给一个字符串,比方说,

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' ,因为这里我们没有明确地做同样的事情(在字符串newStr的最后一个索引处存储’\ 0’),这个程序应该崩溃,因为printf将找不到字符串的结尾。

但是我注意到它有时很好用,有时它不是。 可能是什么问题呢 ? 它实际上几乎每次都在工作。 是不应该崩溃或给出一些运行时错误?

在C ++中也会出现同样的情况吗?

不会。它会调用未定义的行为 – 这意味着它不会崩溃 – 它可以做任何事情,比如鼻子恶魔。

此外,“给出运行时错误” – 这取决于运行时错误的含义。 C没有动态运行时 – 如果您期望从exception中获得格式良好的错误消息,则不会发生这种情况。 会发生什么最有可能是分段错误。

总而言之,如果一个导致/使用未定义的行为,他不能依赖它崩溃或不崩溃。

“碰撞” 无法保证。 不正确地处理字符串中的空终止符的程序 – 更通常是访问缓冲区边界之外的数据 – 或者违反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 ++ ) 

由于strlen的定义意味着你需要。

偶然的是, 大多数情况下newStr未初始化的字节在您的特定情况下恰好为0

您的程序具有未定义的行为,因为您承诺使用指向以null结尾的字符串的指针调用printf但是未能这样做。 任何事情都可能发生,但你的程序根本不正确。

具体来说,在逐个读取数组元素以找到空终止符时,程序最终将访问未初始化的变量,即UB。

在C的大多数实现中,读取尚未初始化为字符的字节的行为是未定义的。有时printf可能写入垃圾,有时程序可能在最后一个字符之后找到空字节\ 0并正常终止。 在极少数情况下,它可能会导致崩溃。 这就是为什么你看到运行程序时发生的变化的原因。 这取决于您使用的编译器,以及您为arrays分配的内存位置。

(也就是说,如果你的程序会编译 – 你已经不用分号了)