简体   繁体   English

数组值自动更改为0

[英]Array values changed automatically to 0

Today I had a strange encounter with gcc. 今天,我与gcc发生了一次奇怪的相遇。 consider the following code: 考虑以下代码:

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.........*/

And a variation: 还有一个变化:

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 [1] = 1.0; len[2]=2.0; len [2] = 2.0;

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

The only difference is highlighted in bold.The problem is this: When length is later printed, the first code prints len[1] and len[2] (and uses them in expressions) as 0.0000 while the second code is printing and using the correct values of those variables. 唯一的区别是用粗体突出显示。问题是:稍后打印长度时,第一个代码打印len [1]和len [2](并在表达式中使用它们)为0.0000,而第二个代码打印并使用这些变量的正确值。

What's wrong? 怎么了? I'm utterly confused.:-o 我完全感到困惑。

Note: len is not modified anywhere else. 注意:len在其他任何地方均未修改。

You need to show us the definitions for nod . 您需要向我们展示nod的定义。 There's a good chance (based on the fact you're starting arrays at 1, not 0) that you're overwriting memory. 基于内存从1开始而不是从0开始的事实,很有可能覆盖内存。

For example, if nod is defined as: 例如,如果nod定义为:

int nod[3][2];

the possible array subscripts are 0-2 and 0-1 , not 1-3 and 1-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]

If that is the case, you're memory is almost certainly being over-written, in which case all bets are off. 如果是这样的话,你的内存几乎可以肯定是被过度写的,在这种情况下,所有的赌注都关闭。 You could be corrupting any other piece of data. 您可能会破坏其他任何数据。

If len is placed in memory immediately following nod , this memory overflow would explain why it's being changed. 如果lennod立即放入内存中,则此内存溢出将说明为什么要更改它。 The following diagram will (attempt to) illustrate this. 下图将(试图)说明这一点。 Let's say your nod definition is: 假设您的nod定义为:

int nod[3][2];

but you attempt to set nod[1-3][1-2] instead of nod[0-2][0-1] : 但您尝试设置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++ will not check regular array bounds for overflow. C / C ++不会检查常规数组边界是否溢出。 So, if you attempt to set nod[3][something-or-other] , you'll find yourself in trouble very similar to what your question describes. 因此,如果您尝试设置nod[3][something-or-other] ,则会发现自己遇到的麻烦与问题所描述的非常相似。

The bit patterns you're using (3 and 4) equate to IEEE754 single-precision 4.2x10 -45 and 5.6x10 -45 respectively so they'd certainly give 0.0000 when printing (since you don't appear to be using a format string which would give you the more precise value). 您使用的位模式(3和4)分别相当于IEEE754单精度4.2x10 -45和5.6x10 -45,因此在打印时它们肯定会给出0.0000 (因为您似乎没有使用格式字符串)这将为您提供更精确的价值)。

A good way to test this theory would be to output the len variables immediately before and after setting the relevant nod variables, something like: 检验该理论的一个好方法是在设置相关的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]);

Actual details as to how the variables are laid out in memory may be different to that described above but the theory still holds. 有关如何在内存中布置变量的实际细节可能与上述内容有所不同,但该理论仍然成立。

Two possible solutions if that turns out to be the problem. 事实证明这是两个可能的解决方案。

  • Use zero-base arrays as C/C++ intended; 使用零基数组作为C / C ++的目标; or 要么
  • Define them with enough space to handle your unusual use, such as int nod[4][3] . 为它们定义足够的空间以处理您的异常使用,例如int nod[4][3]

You certainly have a buffer overwrite. 您当然有缓冲区覆盖。 Check your boundaries, you don't provide any array size in your example, making us unable to say more than that. 检查您的边界,示例中未提供任何数组大小,这使我们无话可说。

If you'using C++, try to replace your arrays by std::tr1::array or boost::array (they are the same), that will give you some clues. 如果您使用的是C ++,请尝试使用std :: tr1 :: array或boost :: array(它们相同)替换数组,这将为您提供一些线索。

You can try setting a watchpoint in gdb to see when len is being modified. 您可以尝试在gdb中设置观察点 ,以查看len何时被修改。 Make sure to compile your program with debug information ( -g ) and no optimization ( -O0 ). 确保使用调试信息( -g )而不进行优化( -O0 )编译程序。 Then, set a breakpoint near the declaration of len , add a watchpoint with watch len[0] , and run. 然后,在len声明附近设置一个断点,使用watch len[0]添加一个观察点,然后运行。 gdb will break whenever len[0] is modified, and it will tell you the new and the old value. 只要修改len[0] ,gdb就会中断,它将告诉您新值和旧值。

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

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