下标访问越界(启用宏检查下标越界错误9)
下标访问越界
除此之外,在使用strncpy等安全函数时,当复制字符串到达指定的长度时,不会在目标字符串结尾添加'\0'字符,必须手工进行添加'\0'字符。当然,可以在申请内存时,将最后一个字节置为'\0'字符;也可以在调用strncpy函数后,紧接着赋'\0'字符。
前面已经阐述过,C语言提供的字符串库函数sprintf、vsprintf、strcpy、strcat与gets等非常危险,很容易导致内存越界,应该尽量使用安全的字符串库函数snprintf、strncpy、strncat与fgets来替换它们。
数组下标取值越界主要是指访问数组时,下标的取值不在已定义好的数组的取值范围,而访问的是无法获取的内存地址。例如inta[10],此数组a的下标取值范围是[0,9]。若取值不在这个范围,就出现越界错误。
其中,“__FILE__”在预编译时,被编译时的目录名和源文件名代替,但目录和文件名的长度可变,很可能超出250字节,从而导致内存越界。因此,应该使用snprintf来替换sprintf函数,指定缓冲区的大小,确保内存不会越界。如下面的示例代码所示:
对于memcpy与memset函数,在使用的时候一定要确保长度不要越界。如下面的示例代码所示:
启用宏检查下标越界错误9
在C语言中,字符串是一个以'\0'字符结尾的字符数组。但是,当使用strlen库函数来获取字符串的长度时,其长度值并不包含'\0'字符。这就导致我们经常因为不小心而忽略了字符串最后的'\0'字符。
除此之外,在设置缓冲区大小时,要考虑各种应用场合,特别是考虑到函数参数的边界条件,按最大的可能分配空间,能够利用程序计算的,尽量自动计算。
上面的示例代码就是一个典型的数组下标取值越界。其中,因为MAX_BUF_SIZE被定义为10,所以inta[MAX_BUF_SIZE]定义了10个元素大小的数组。由于C语言中数组的索引是从0开始的,所以只能访问a[0]到a[9]。当“i=10”时,访问a[10]就造成越界错误。因此,应该修改成如下形式:
读越界,即读了不属于自己的数据。如果所读的内存地址是无效的,程序立刻崩溃;如果所读内存地址是有效的,在读的时候不会马上出现问题,但由于读到的数据是随机的,因此它会造成不可预料的后果。
但如果在“strlen(str)”获取的str真实的字符串长度后再加上1(即包括最后的'\0'字符),情况就不一样了,如下面的示例代码所示:
下标越界怎么恢复
内存越界是软件系统主要错误之一,其后果往往不可预料且非常严重。更麻烦的是,它出现的时机是随机的,表现出来的*是随机的,而且造成的后果也是随机的,这会使程序员很难找出这些Bug的现象和本质之间的联系,从而给Bug的*带来极大的困难。一般情况下,内存越界访问可分如下两种:
指向数组的指针的指向范围越界表示当定义的指针p若指向了数组的首地址时(即p=a),若对其不断进行操作p++,则最后会导致指针p指向大于该数组范围的上界,从而使程序访问了数组以外的存储单元,造成数组越界。
很明显,b的长度是100,而a长度是80,执行语句“memcpy(a,b,sizeof(b))”时,由于a的长度小于b的长度,所以将导致程序内存越界。因此,必须确保a的长度大于b的长度,又或者是a和b的长度保持一致。由于是字符串拷贝,因此还可以改用strncpy函数。如下面的示例代码所示:
增长方向不同。堆的增长方向是向上的,即向着内存地址增加的方向;栈的增长方向是向下的,即向着内存地址减小的方向。
所以,for循环的循环变量一定要使用半开半闭的区间,而且如果不是特殊情况,循环变量尽量从0开始。