输入对于数组来说太大了

时间:2014-04-06 08:41:24

标签: c string

我有一个小问题,我只是想知道。

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

的数组中

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)

我认为你的进程中恰好是与你的数组相邻的地址的有效内存,这意味着它恰好正常工作。但是,它会通过覆盖它来破坏过程中其他地方的其他内存。

基本上你有一个缓冲区溢出。