我有一个小问题,我只是想知道。
#include <stdio.h>
int main()
{
char n_string[5];
printf("Please enter your first name: ");
scanf("%s", n_string);
printf("\nYour name is: %s", n_string);
return 0;
}
在第5行,我声明了一个由4个字母组成的字符串。现在这意味着我只能在该字符串中保存4个字符,对吗? 如果我执行我的程序并写下名字:亚历山大,我得到输出:
Your name is Alexander.
我的问题是,为什么我可以将一个包含9个字符的字符串放入一个包含4?
的数组中答案 0 :(得分:3)
你这样做会覆盖程序堆栈的一部分,这通常是一件非常糟糕的事情。在这种情况下,你很幸运,但如果你进一步写作,当segfault
试图返回时,你几乎肯定会得到main
。
恶意演员将此作为缓冲区溢出攻击,以覆盖函数的返回地址。
如果您的问题是&#34;为什么C允许我这样做?&#34;,答案是C
不对数组进行边界检查。它将数组(或多或少)视为指向内存中地址的指针,而scanf
非常乐意写入内存位置而不必担心它实际代表什么。
答案 1 :(得分:3)
您分配了5个字节,但由于您的CPU可能需要16字节对齐,因此编译器可能分配了16个字节。试试这个:
char n_string[5];
volatile int some_int;
some_int= 0;
sscanf(..);
printf("%s %d\n", n_string, some_int);
some_int
仍为0吗?写入n_string
可能导致缓冲区溢出并将错误数据写入some_int
。当然,您的编译器可能知道some_int将保持为零,因此我们将其声明为volatile int some_int;
以阻止其优化。
答案 2 :(得分:2)
您保留4个字母和终止0的内存。你写九个字母和一个零。你超越你的界限5个字节。那5个字节属于别人,你只是摧毁了他的记忆。
最有可能的候选者是接近的变量。测试这个,虽然不能保证,你可能会看到你的剩余字节会发生什么:它们会损坏你的i变量:
#include <stdio.h>
int main()
{
char n_string[5];
int i = 17;
printf("Please enter your first name: ");
scanf("%s", n_string);
printf("\nYour name is: %s", n_string);
printf("\nThe variable i is %d", i);
return 0;
}
答案 3 :(得分:1)
我认为你的进程中恰好是与你的数组相邻的地址的有效内存,这意味着它恰好正常工作。但是,它会通过覆盖它来破坏过程中其他地方的其他内存。
基本上你有一个缓冲区溢出。