数组溢出引起的运行错误

今天和同学一起调试绘制灰度直方图的一段程序,如下所示:

int m_nRHisto[255];int m_nGHisto[255];int m_nBHisto[255];

unsigned char R,G,B;

int RR,GG,BB;

static int nDx[] = {-1,0,1,0,1,1,-1,-1};static int nDy[] = {0,1,0,-1,1,-1,1,-1};

int k,x,y;int temp;

for ( i = 0; i < 256; i++ )

{

       m_nRHisto[i] = 0;m_nGHisto[i] = 0;m_nBHisto[i] = 0;

}

long lLineBytes = WIDTHBYTES( lWidth * 24 );

for ( i = 0; i < lHeight; i++ )

 {

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

        {

               R = lpDIBbits[ (lHeight-1-i) * lLineBytes + j*3 ];

               G = lpDIBbits[ (lHeight-1-i) * lLineBytes + j*3 + 1 ];

               B = lpDIBbits[ (lHeight-1-i) * lLineBytes + j*3 + 2 ];

               for ( k = 0; k < 8; k++ )     

               {   

                     x = j+nDx[k];y = i+nDy[k];

                     if ((x < lWidth) && (x>=0) && (y<lHeight) && (y>=0))

                     {    

                            RR = lpDIBbits[(lHeight-1-y)*lLineBytes+x*3];temp = abs(R-RR);

                            m_nRHisto[temp]++;

                            GG = lpDIBbits[(lHeight-1-y)*lLineBytes+x*3+1];temp = abs(G-GG);

                            m_nGHisto[temp]++;

                            BB = lpDIBbits[(lHeight-1-y)*lLineBytes+x*3+2];temp = abs(B-BB);

                            m_nBHisto[temp]++;

                     }           

               }

        }

}

该同学是将灰度直方图绘制在一个对话框中,但是点击对话框中的OK按钮时,不仅对话框消失,主程序也随之退出。于是调试之,初步怀疑是这段统计RGB分量的地方有些问题,最后发现是数据类型设置有误造成数组溢出,呵呵,小错误大失误。你看出是那里有问题?没错:

int RR,GG,BB;

就是这里数据类型设置错误。程序的本意RRR都是存储影像的灰度,但是Runsigned char类型的,RRint类型,前者设置成unsigned char型完全没有问题,后者设置成int型好像也说得过去,但是如果两者相减,会出现什么后果,可是大有问题的。那下面我将逐步调试,将这个错误分析一下。

(1)    将断点设置在“R=”这句话处,调试

 

赋值式右边是个负值(这是因为lpstr类型是指向字符串的),而左值R的类型是unsigned char类型,那么这里会出现一个溢出的情况,尽管这个溢出可能引起什么错误,但从逻辑上讲还是有些问题的。unsigned char类型的范围是0~255(8),那么如果将一个负值赋给它,则会首先将该负值对256取模,即-108+256=148.即此时R148,安全的值,此时不会有什么错误,如下:

 

 

(2)    继续调试,在“RR=”处停住,调试

 

此时右值仍然是负值,即:

intsigned int,因为intshortlong类型默认为带符号型,所以当右值为负值,将其赋给左值,那么RR也是负值,如上所示。负值就负值吧,又没招惹谁,程序也没有什么错误。

 

(3)    继续调试,要命的来了,在“temp = abs(R-RR)”处停住,看看temp的结果是什么吧:

oops,对于表达式R-RRRunsigned charRRint,那么在运算的时候,R会自动提升为int型,此时R=148RR保持不变,RR=-112,两者相减,temp=260260260吧,反正tempint型够大,好像还是没有错误,别急,下一句就真的要命了。

 

(4)    F10继续,涉及到数组了,小心:

m_nRHisto[temp]++;

回头看看m_nRHisto的定义: int m_nRHisto[255],那么temp=260,数组明显溢出,这是最根本的错误。但是对于这种溢出,编译器一般是不会报错的,所以要特别小心。

找出错误,那么更改就很方便了,将RR/GG/BB的类型改得和R/G/B一致就可以了,并不需要都是unsigned char,但是从节约角度来讲,用unsigned char来表达灰度是非常合适的。

同时,从逻辑的完备性考虑在给temp赋值之后,可以加一个判断语句:

       if( temp > 255 ) return;

 

找出这个错误,我又回头翻翻几天前看的C++PRIMER4th,在p31上给出的一段建议:

同样的道理,虽然char类型是整型,但是char类型通常用来存储字符而不用于计算。事实上,在某些实现中char类型被当作signed类型,在另外一些实现中则被当作unsigned类型,因此把char类型作为计算类型使用时容易出问题。

 

在大多数机器上,使用int类型进行整型计算不易出错。就技术而言,int类型用16位表示这对大多数应用来说太小了。实际应用中,大多数通用机器都是使用和long类型一样长的32位来表示int类型

更重要的是,C++PRIMER4th整本书都在强调这样一个信息:

与使用标准vector类型的程序相比,依赖于内置数组的程序更容易出错而且难于调试

该书可以说一直都在介绍容器类型,大有让C++程序员摆脱数组和指针,转而用容器和迭代器的想法。下面一段代码可以简单说明这一思想:

const size_t array_size = 10;

int ia[ array_size ];

for( size_t ix = 0; ix != array_size; ++ix )

ia[ix] = ix;

容器和迭代器也在持续学习中,希望能在今后的实践中用到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值