1

我正在使用 Code::Blocks 10.05 和 GNU GCC 编译器。

基本上,当尝试在声明的大小之外初始化数组时,我遇到了一个非常奇怪(对我来说,莫名其妙)的问题。简而言之,就是这样:

*有一个大小为 [x][y] 的声明数组。

*还有另一个大小为 [y-1] 的声明数组。

尝试将值放入第二个size [y-1]数组中时会出现问题,该数组超出了[y-1]大小。尝试此操作时,第一个数组[x][y]将不再保留其所有值。我根本不明白为什么破坏(或试图破坏)一个数组会影响另一个数组的内容。这是一些示例代码,可以查看它的发生情况(它的格式已损坏。要查看问题消失,只需更改array2[4]array2[5](从而消除了我指出的问题)。

#include <stdio.h>

int main(void)
{
    //Declare the array/indices
    char array[10][5];
    int array2[4]; //to see it work (and verify the issue), change 4 to 5
    int i, j;

    //Set up use of an input text file to fill the array
    FILE *ifp;
        ifp = fopen("input.txt", "r");

    //Fill the array
    for (i = 0; i <= 9; i++)
    {
        for (j = 0; j <= 5; j++)
        {
            fscanf(ifp, "%c", &array[i][j]);
            //printf("[%d][%d] = %c\n", i, j, array[i][j]);
        }
    }

    for (j = 4; j >= 0; j--)
    {
        for (i = 0; i <= 9; i++)
        {
            printf("[%d][%d] = %c\n", i, j, array[i][j]);
        }
        //PROBLEM LINE*************
        array2[j] = 5;

    }

    fclose(ifp);
    return 0;

}

那么有谁知道这是如何发生或为什么发生的?

4

4 回答 4

4

因为当您在数组边界之外写入时,C 允许您。你只是写到程序中的其他地方。

C被称为最低级别的高级语言。要理解“低级”的含义,请记住,您创建的每个变量都可以认为是生活在物理记忆中。如果整数大小为 4,则长度为 16 的整数数组可能占用 64 个字节。也许它们占用 100-163 字节(不太可能,但我不会编出真实的数字,通常最好用十六进制来考虑这些数字)。什么占用字节 164?也许你程序中的另一个变量。如果您写入超过 16 个整数的数组会发生什么?好吧,它可能会写入该字节。

C 允许你这样做。为什么?如果您想不出任何答案,那么也许您应该切换语言。我不是迂腐——如果这对你没有好处,那么你可能想要用一种语言来编程,这样你就更难犯这样的奇怪错误了。但原因包括:

  • 它更快更小。添加边界检查需要时间和空间,因此如果您正在为微处理器编写代码,或编写 JIT 编译器,速度和大小确实很重要。
  • 如果您想了解机器架构并进入硬件领域,例如,如果您是一名学生,那么它是从编程进入操作系统/硬件/电气工程的良好途径。还有很多计算机科学。
  • 由于接近机器代码,它是许多其他语言和系统必须或可以轻松支持某种程度的兼容性的标准方式。
  • 如果我真的不得不在机器代码附近工作,我可以给出的其他原因。

寓意是:在 C 中,要非常小心。您必须检查自己的数组边界。你必须清理自己的记忆。如果你不这样做,你的程序通常不会崩溃,但会开始做一些非常奇怪的事情,而不告诉你在哪里或为什么。

于 2012-06-22T03:44:47.693 回答
2
  for (j = 0; j <= 5; j++) 

应该

  for (j = 0; j <= 4; j++)

最大array2索引是3这样的

  array2[j] = 5;

也将是一个问题j == 4

C 数组索引从0. 所以一个[X]数组有效索引是 from 0to X-1,因此你总共得到 X 个元素。

您应该使用<运算符而不是<=,以便在数组声明[X]和表达式中显示相同的数字< X。例如

  int array[10];
  ...
  for (i=0 ; i < 10 ; ++i) ... // instead of `<= 9`

这不太容易出错。

于 2012-06-22T03:44:44.057 回答
1

如果您在一个数组的范围之外,那么您总是有可能在另一个数组的范围内。

于 2012-06-22T03:48:50.277 回答
1

array2[j] = 5;- 这是你的溢出问题。

for (j = 0; j <= 5; j++)- 这也是溢出的问题。在这里,您也尝试访问第 5 个索引,您只能访问第 0 到第 4 个索引。

在进程内存中,在调用每个函数时,会创建一个激活记录来保存函数的所有局部变量,并且还会有更多的内存来存储被调用函数的地址位置。在您的函数中有四个局部变量arrayarray2,ij。所有这四个将按顺序排列。因此,如果发生溢出,它将首先尝试覆盖上面或下面声明的变量,这取决于架构。如果溢出发生更多字节,那么它可能会通过覆盖被调用函数的一些局部变量来破坏整个堆栈本身。这也可能导致崩溃,有时它可能不会,但它会像你现在所面对的那样表现得无动于衷。

于 2012-06-22T05:44:26.807 回答