C fscanf向数组添加元素,不应该

Li4*_*ick 2 c

#include <stdio.h>


int main() {

    FILE *input;
    FILE *output;

    input = fopen("algsort.in", "r");
    output = fopen("algsort.out", "w");

    int n = 0;
    fscanf(input, "%d", &n);        // reads n = 7

    int i;
    int a[6] = {1, -1, 0, 33, 6, 5};


    for(i = 0; i < 8; i++) {     // 8 is on purpuse
        printf("%d  ", a[i]);    // the output is [1 -1 0 33 6 5 7 $(Random location in memory)]
    }


    return 0;
}
Run Code Online (Sandbox Code Playgroud)

fscanf在数组末尾附加一个元素.这是一个问题,因为它干扰了排序算法,遗漏了一个大于n的元素.我知道for循环的限制,问题是,"n"元素仍然是数组的一部分.问题:7来自哪里?

das*_*ght 5

fscanf 在数组的末尾附加一个元素.

不,不是的.你的数组仍然是六个数组int.事实上你可以在没有崩溃的情况下超越数组的末尾并不意味着你的数组以某种方式获得了额外的元素 - 这意味着未定义的行为这次不会导致崩溃.

7来自哪里?

从内存中sizeof(int)超过数组末尾的位置a.通过数组访问此位置是未定义的行为,因此可以返回任何值.一个快速的实验表明,至少有一个编译器可以n以直接在数组后面的方式在你的函数内部布局内存a:

FILE *input = NULL;
FILE *output = NULL; 
int n = 0;
scanf("%d", &n); // reads n = 7
int a[6] = {1, -1, 0, 33, 6, 5};
printf("%p\n%p\n", (void*)&n, (void*)&a[6]);
Run Code Online (Sandbox Code Playgroud)

这打印

0xbfabd5e4
0xbfabd5e4
Run Code Online (Sandbox Code Playgroud)

这意味着地址na+6(当你取消引用一个元素超过数组末尾时得到的)指向同一个地址.如果你的编译器做同样的事情,你会看到相同的结果.即使是这种情况,这种行为仍未定义.