#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
的值在整个代码中保持不变。
我似乎无法弄清楚为什么会这样,有人可以解释一下这是怎么回事吗?
答案 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
覆盖c
因gets(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
}