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

时间:2014-10-15 18:04:12

标签: 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;
}

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

2 个答案:

答案 0 :(得分:5)

  

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

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

  

7来自哪里?

从内存中sizeof(int)的位置越过数组a的末尾。通过数组访问此位置是未定义的行为,因此可以返回任何值。 A quick experiment shows至少有一个编译器可以在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]);

打印

0xbfabd5e4
0xbfabd5e4

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

答案 1 :(得分:3)

您的所有变量都在stack [wiki]上,您的堆栈内存可能如下所示(how to view it in visual studio):

     address  value  variable name
-> 0000 002c  7      n
-> 0000 0018  5      a[6]
-> 0000 0014  6      a[5] 
-> 0000 0010  3      a[4]
-> 0000 000c  33     a[3]
-> 0000 0008  0      a[2]
-> 0000 0004  -1     a[1]
-> 0000 0000  1      a[0]

你只是“幸运a[7]指向与n相同的记忆。

我只是在Linux下使用GCC运行修改过的示例,我得到了这个:

 var   addres   value
n      c6798c   6
a[7]   c6798c   6
a[6]   c67988   4195600
a[5]   c67984   5
a[4]   c67980   6
a[3]   c6797c   33
a[2]   c67978   0
a[1]   c67974   -1
a[0]   c67970   1

我想这是由于内存对齐和64b操作系统。