【问题标题】:puts and printf in C在 C 中放置和 printf
【发布时间】:2016-02-23 22:04:58
【问题描述】:

我是 C 新手。我在 C 的 puts 和 printf 中发现了一些问题。

char str[10];
printf("Input a string.\n");
gets(str);
printf("The string you input is: %s",str);

如果我输入超过 10 个字符,输出就是这些

1ang:lab lang$ ./exercise 
Input a string.
warning: this program uses gets(), which is unsafe.
0123456789
Abort trap: 6

但是当我在 printf 的末尾添加\n 时,printf("The string you input is: %s\n",str); 的输出是不同的。

1ang:lab lang$ ./exercise 
Input a string.
warning: this program uses gets(), which is unsafe.
0123456789
The string you input is: 0123456789
Abort trap: 6

它将首先打印字符串,然后发生错误。 谁能解释一下?

【问题讨论】:

  • 'gets()' 已弃用,请改用 fgets()。
  • 不 - 我们不在这里解释 UB。
  • 我很确定这是一个缓冲问题。尝试在 %s 之后使用另一个 printf("\n") 。并尽量避免得到,因为它是不保存的,正如你的 libc 所建议的那样。
  • 请注意,即使对于“0123456789”,'char str[10]' 也太小了
  • 无法解释未定义的行为。它只是未定义。使用fgets 而不是gets

标签: c string


【解决方案1】:

您没有为字符串保留足够的空间。

请记住,对于添加到字符数组的空终止符 (\0),您需要一个额外的元素。 str[10] 不够大。

由于printfstr 参数不包含\0,它会以未定义 结果溢出缓冲区。

解决此问题的一种方法是考虑改用fgets。在当前形式下,即使为您的测试字符串保留足够的内存,您也可以轻松提供更长的内存,这将再次使您的程序崩溃。

另外,考虑将\n 附加到您的printf 字符串:此换行符会刷新输出缓冲区,这将有助于及时回写到您的控制台。

【讨论】:

    【解决方案2】:

    gets 不安全,在您的代码中,我认为它会覆盖您的堆栈的一部分,可能是返回指针寄存器(我不确定名称)。

    现在,为什么您在一个案例中有消息,而在另一个案例中没有?

    因为在printf 中打印"\n" 将强制刷新到目前为止已缓冲的内容。

    在第一种情况下,崩溃发生在文本显示在控制台上之前,但如果您使用调试器,将看到它发生在同一点。

    【讨论】:

      【解决方案3】:

      你的编译器告诉你,“warning: this program usesgets(), which is unsafe.”但你还是继续了。然后你读取了足够的数据来溢出你的数组,可能会破坏其他存储。

      接下来发生的是未定义的行为,因此任何事情都可能发生。在您的情况下,printf 似乎成功了,但损坏导致后来的代码(可能是函数的返回)崩溃。如果您刷新了stdout(如果stdout 是终端,则在打印\n 时隐式发生),那么您将看到输出。如果你不这样做,当进程被销毁时,缓冲的输出就会丢失。

      【讨论】:

        【解决方案4】:

        您所拥有的是未定义行为的一个很好的例子。如果超出数组的缓冲大小,未定义会发生什么。正如其他人指出的那样,您真的不应该使用gets。该功能不被视为无缘无故弃用。最好使用fgetsfscanf

        我还建议您使用scanf 的返回值编写一个“安全”输入函数。或者您可以使用fgetssscanf 的组合从输入中读取整行,然后使用sscanf 操作读取的字符串,如this 答案。

        【讨论】:

          猜你喜欢
          • 2020-05-23
          • 2017-03-21
          • 2015-05-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-21
          • 2021-12-16
          • 1970-01-01
          相关资源
          最近更新 更多