关于gets的非常奇怪的错误(字符串)

时间:2013-12-26 19:53:31

标签: c string gets string.h

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
   int a;
   char c[1];
   printf("\n%d\n", a);
   gets(c);
   printf("\n%d\n", a);
   return 0;
}

使用c阅读gets时,之前打印的a的值打印为具有值0;当使用scanf("%c", &c);替代gets(c);时,a的值在整个代码中保持不变。

我似乎无法弄清楚为什么会这样,有人可以解释一下这是怎么回事吗?

4 个答案:

答案 0 :(得分:2)

您只能在字符串\0中有a的空间,而gets()并不关心空间不足。它显然覆盖了部分内存导致您的问题。而不是gets(),请使用fgets()

char c[100];
if (fgets(c, sizeof c, stdin) == NULL) Handle_EOForIOError();
size_t len = strlen(c);
if (len && c[len-1] == '\n') c[--len] = '\0';

C standard(2011)已从其规范中删除了gets()


OP:...当使用scanf("%c",&c);替代gets(c);时,a的值在整个代码中保持不变。

这是,因为scanf("%c",&c);不应影响a

如果您希望使用a覆盖cgets(c);而导致char c[1]; int a;被覆盖,则可以尝试{{1}},但任何此类代码都会调用未定义的行为。

答案 1 :(得分:2)

您可能遇到了堆栈损坏。 gets()将输入字符写入您传入的内存地址(指向c的第一个元素的指针)。但是,您只分配了1个字符,这对于空字符串(包括空终止符)来说已足够了。

这就是永远不应该使用gets()的原因。它不安全,因为它可以覆盖其目标数组的末尾。请改用更安全的功能,例如fgets()

答案 2 :(得分:1)

您的程序正在调用未定义的行为
1.除非你没有传递一个空字符串(\n) 2. a未初始化。

在这种情况下,任何事情都可能发生。您可能会得到预期或意外的结果,分段错误甚至程序崩溃。

答案 3 :(得分:1)

只是为了解决这个问题,永远不会永远使用gets 会在您的计划中引入失败点。它在C99标准中已弃用,已从C2011标准中删除。这是邪恶

说了这么多,让我们来看看代码中的所有问题。

请记住,在C中, string 是由0值字节终止的字符序列。这意味着要存储N字符字符串,您必须留出N + 1 char个存储元素。您的c数组的大小可以容纳1个元素,这意味着它可以存储的唯一字符串是空字符串。

gets的问题在于它不知道目标缓冲区有多大;当您将数组作为参数传递时,所有被调用函数receive都是指向第一个元素的指针。如果您键入10个非空白字符,或100或1000,gets将很快将多余的内容存储在数组后面的内存中;这就是你的a变量被覆盖的原因。这也是gets最终从语言标准中删除的原因;该行为启用了批次恶意软件攻击。

scanf调用导致问题的原因是因为您使用了%c转换说明符,它只读取输入流中的单个字符。如果您使用%s转换说明符,则会看到与gets调用相同的结果。

所以,你需要做两件事:首先,你需要声明c足够大以容纳你期望的最大字符串加上0终结符的1:

#define MAX_SIZE 10 // or however large the string needs to be
...
char c[MAX_SIZE+1];

然后您需要使用fgets来阅读输入:

if ( fgets( c, sizeof c, stdin ) != NULL )
{
  // work with c
}