繁体   English   中英

数组值自动更改为0

[英]Array values changed automatically to 0

今天,我与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.........*/

还有一个变化:

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

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

for(i=1;i<=nnod;i++)
  for(j=1;j<=nfree;j++)
/* blah blah.........*/

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

怎么了? 我完全感到困惑。

注意:len在其他任何地方均未修改。

您需要向我们展示nod的定义。 基于内存从1开始而不是从0开始的事实,很有可能覆盖内存。

例如,如果nod定义为:

int nod[3][2];

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

nod[0][0]   nod[1][0]   nod[2][0]
nod[0][1]   nod[1][1]   nod[2][1]

如果是这样的话,你的内存几乎可以肯定是被过度写的,在这种情况下,所有的赌注都关闭。 您可能会破坏其他任何数据。

如果lennod立即放入内存中,则此内存溢出将说明为什么要更改它。 下图将(试图)说明这一点。 假设您的nod定义为:

int nod[3][2];

但您尝试设置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] *
      +-----------+

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

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

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

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]);

有关如何在内存中布置变量的实际细节可能与上述内容有所不同,但该理论仍然成立。

事实证明这是两个可能的解决方案。

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

您当然有缓冲区覆盖。 检查您的边界,示例中未提供任何数组大小,这使我们无话可说。

如果您使用的是C ++,请尝试使用std :: tr1 :: array或boost :: array(它们相同)替换数组,这将为您提供一些线索。

您可以尝试在gdb中设置观察点 ,以查看len何时被修改。 确保使用调试信息( -g )而不进行优化( -O0 )编译程序。 然后,在len声明附近设置一个断点,使用watch len[0]添加一个观察点,然后运行。 只要修改len[0] ,gdb就会中断,它将告诉您新值和旧值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM