数组值自动更改为0

Aki*_*lan 0 c++ linux gcc

今天我遇到了与gcc的奇怪遭遇.考虑以下代码:

float len[ELEM+1];
len[1]=1.0; len[2]=2.0; len[3]=3.0;                                 //length

nod[1][1] = 1;
nod[1][2] = 2;
nod[2][1] = 2;
nod[2][2] = 3;
nod[3][1] = 3;
nod[3][2] = 4;                //CONNECTIVITY


for(i=1;i<nnod;i++)
  for(j=1;j<nfree;j++)
/* blah blah.........*/
Run Code Online (Sandbox Code Playgroud)

一个变化:

float len[ELEM+1];
len[1]=1.0; len[2]=2.0; len[3]=3.0;                                 //length

nod[1][1] = 1;
nod[1][2] = 2;
nod[2][1] = 2;
nod[2][2] = 3;
nod[3][1] = 3;
nod[3][2] = 4;                //CONNECTIVITY
Run Code Online (Sandbox Code Playgroud)

LEN [1] = 1.0; LEN [2] = 2.0;

for(i=1;i<=nnod;i++)
  for(j=1;j<=nfree;j++)
/* blah blah.........*/
Run Code Online (Sandbox Code Playgroud)

唯一的区别是以粗体突出显示.问题是:当稍后打印长度时,第一个代码打印len [1]和len [2](并在表达式中使用它们)为0.0000,而第二个代码打印并使用这些变量的正确值.

怎么了?我完全糊涂了.: -

注意:len不会在其他地方修改.

pax*_*blo 8

您需要向我们展示其定义nod.你有一个很好的机会(基于你在1,而不是0开始数组的事实),你正在覆盖内存.

例如,如果将nod定义为:

int nod[3][2];
Run Code Online (Sandbox Code Playgroud)

可能的数组下标是0-20-1,而不是 1-31-2:

nod[0][0]   nod[1][0]   nod[2][0]
nod[0][1]   nod[1][1]   nod[2][1]
Run Code Online (Sandbox Code Playgroud)

如果这种情况,你的记忆几乎肯定会被覆盖,在这种情况下所有的赌注都会被取消.你可能会破坏任何其他数据.

如果len紧跟在内存中nod,这个内存溢出将解释为什么它会被更改.下图将(尝试)说明这一点.假设你的nod定义是:

int nod[3][2];
Run Code Online (Sandbox Code Playgroud)

但你试图设置nod[1-3][1-2]而不是nod[0-2][0-1]:

      +-----------+
+0000 | nod[0][0] |
      +-----------+
+0004 | nod[0][1] |
      +-----------+
+0008 | nod[1][0] |
      +-----------+
+000c | nod[1][1] |
      +-----------+
+0010 | nod[2][0] |
      +-----------+
+0014 | nod[2][1] |
      +-----------+
+0018 |   len[0]  | and nod[3][0], should you be foolish enough to try :-)
      +-----------+
+001c |   len[1]  | and nod[3][1] *
      +-----------+
+0020 |   len[2]  | and nod[3][2] *
      +-----------+
Run Code Online (Sandbox Code Playgroud)

C/C++不会检查常规数组边界是否有溢出.所以,如果你试图设置nod[3][something-or-other],你会发现自己遇到的麻烦与你的问题所描述的非常相似.

您正在使用的位模式(3和4)分别等同于IEEE754单精度4.2x10 -45和5.6x10 -45,因此它们0.0000在打印时肯定会给出(因为您似乎没有使用格式字符串会给你更准确的价值).

测试该理论的一个好方法是len在设置相关nod变量之前和之后立即输出变量,如:

printf ("before: len1 = %f, len2 = %f\n", len[1], len[2]);
nod[3][1] = 3;
nod[3][2] = 4;
printf ("after : len1 = %f, len2 = %f\n", len[1], len[2]);
Run Code Online (Sandbox Code Playgroud)

关于如何在存储器中布置变量的实际细节可能与上面描述的不同,但理论仍然成立.

如果事实证明是两个可能的解决方案.

  • 使用零基数组作为C/C++; 要么
  • 定义它们有足够的空间来处理您的异常使用,例如int nod[4][3].