0

有些事情困扰着我,我真的无法通过互联网找到任何答案(或者至少我不知道如何搜索它)。我一直认为,在将矩阵的大小声明为 SIZE 时,矩阵的第一个元素是 0,最后一个元素是 SIZE-1。但是,在编译时:

#include<cstdio>
#include<cstdlib>
int main()
{
   double *r;
   r = new double[10];
   double dr=0.1;
   for(int i=0;i<=10;i++) r[i]=(double)i*dr;
   for(int i=0;i<=10;i++) printf("%lf\n",r[i]);
   delete [] r; r=0;
   return 0;
}

没有错误通知(到目前为止,我已经用 3 个编译器尝试了这个,gnu、dev 和 c-free),即使我运行 exe 也没有发生错误。结果是:

0.000000
0.100000
0.200000
0.300000
0.400000
0.500000
0.600000
0.700000
0.800000
0.900000
1.000000---> element SIZE, which means 11, while I have declared 10 elements.

所以,问题是:这怎么可能?!?!!?以下是打印地址时的结果:

006E0F88
006E0F90
006E0F98
006E0FA0
006E0FA8
006E0FB0
006E0FB8
006E0FC0
006E0FC8
006E0FD0
006E0FD8---> 11th element

先感谢您。

4

3 回答 3

4

你是对的,一个大小数组的索引N范围从0N-1包含。

您通过访问超出其边界的数组来调用未定义的行为。这不是编译错误,但运行这样的代码会产生不可预知的结果。

于 2013-05-26T14:54:00.887 回答
3

在 C 和 C++ 中,理解“未定义行为”的概念非常重要。

这两种语言的主要假设是程序员不会出错。他们永远不会越过一个数组,他们永远不会删除一个对象两次,他们永远不会对有符号整数进行计算以溢出等等。

这意味着编译器和标准库生成的代码可以忽略这种可能性,无论发生什么。

可能是您的代码在做坏事时会出现段错误(即操作系统本身会阻止无意义的操作),但这仅在您幸运时才会发生。在大多数情况下,什么都没有发生。更好地说,没有任何明显的事情发生……但是稍后执行的一百万条指令可能是一些完全有效的代码会表现得很疯狂。

在 C 和 C++ 中很常见的是,触发段错误的代码只是很久以前发生的一些错误的无辜受害者。

因此,在使用 C 和 C++ 进行编码时,请记住永远不要犯错误 ;-)

于 2013-05-26T15:01:33.490 回答
0

0到的循环<=10将访问/打印 11 个元素。

这是UB。超出数组边界的访问是 UB。

这应该修复您的代码:

#include<cstdio>
#include<cstdlib>
int main()
{
   double *r;
   r = new double[10];
   double dr=0.1;
   for(int i=0;i<10;i++) r[i]=(double)i*dr;
   for(int i=0;i<10;i++) printf("%lf\n",r[i]);
   delete [] r; r=0;
   return 0;
}

您的代码没有语法错误,也没有未解析的引用,因此编译器将信任程序员并让此 UB 通过。LINT工具可能会发现这个错误,不确定。

于 2013-05-26T14:54:28.537 回答