0
#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

4 回答 4

2

您只有\0在字符串中的空间,agets()不在乎没有足够的空间。它显然覆盖了导致您的问题的部分内存。而不是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 标准 (2011) 已从gets()其规范中删除。


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

应该scanf("%c",&c);不会影响a

如果您希望通过 using对a进行一些覆盖,您可以尝试使用,但任何此类代码都会调用未定义的行为。cgets(c);char c[1]; int a;

于 2013-12-26T19:57:24.993 回答
2

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

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

于 2013-12-26T19:58:28.817 回答
1

只是为了解决这个问题,永远不要永远不要使用gets:它在你的程序中引入一个故障点。它在 C99 标准中已被弃用,并已从 C2011 标准中删除。这是邪恶的。

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

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

问题gets在于它不知道目标缓冲区有多大。当您将数组作为参数传递时,所有被调用函数接收到的都是指向第一个元素的指针。如果您输入 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
}
于 2013-12-26T21:11:07.340 回答
1

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

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

于 2013-12-26T20:00:13.353 回答