1

给定一个字符串,比如说,

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'是找到字符串的结尾。

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

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

4

6 回答 6

7

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

此外,“给出一个运行时错误” - 好吧,这取决于你所说的运行时错误是什么意思。C 没有动态运行时 - 如果您希望从异常中得到格式良好的错误消息,那将不会发生。会发生什么很可能是分段错误。

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

于 2012-09-17T16:17:48.710 回答
3

不能保证“崩溃” 。不正确地处理字符串中的空终止符(更普遍地访问缓冲区边界之外的数据)或违反 printf格式字符串的程序可能看起来工作得很好,可以正常运行并且不会导致段错误。但这只是偶然:您的代码的行为是未定义的。

在 C++ 中也是一样的。

于 2012-09-17T16:17:43.473 回答
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 ++ )

正如strlen的定义所暗示的那样,您需要这样做。

于 2012-09-17T16:27:35.860 回答
1

碰巧的是,大多数情况下未初始化的字节newStr恰好0在您的特定情况下。

于 2012-09-17T16:17:45.340 回答
1

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

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

于 2012-09-17T16:19:05.780 回答
0

The behaviour of reading bytes that have not been initialized as characters is undefined in most implementations of C. Sometimes printf may write garbage, sometimes the program may find a null byte \0 after the last character and terminate normally. In some rare cases it may cause a crash. This is why you are seeing variation in what happens when you run the program. It depends on the compiler you are using, and what was in the memory location following that which you are allocating for the array.

(That is, if your program would compile - you've left off a semicolon)

于 2012-09-17T16:21:21.493 回答