打印
[应用方案]

数组越界与溢出

[复制链接]
2057|67
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
eefas|  楼主 | 2024-1-21 21:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
数组越界C语言数组是静态的,不能自动扩容,当下标小于零或大于等于数组长度时,就发生了越界(Out Of Bounds),访问到数组以外的内存。如果下标小于零,就会发生下限越界(Off Normal Lower);如果下标大于等于数组长度,就会发生上限越界(Off Normal Upper)。
C语言为了提高效率,保证操作的灵活性,并不会对越界行为进行检查,即使越界了,也能够正常编译,只有在运行期间才可能会发生问题。请看下面的代码:
#include <stdio.h>
int main()
{
int a[3] = {10, 20, 30}, i;
for(i=-2; i<=4; i++){
printf("a[%d]=%d\n", i, a[ i]);
}
return 0;
}
运行结果:a[-2]=-858993460a[-1]=-858993460a[0]=10a[1]=20a[2]=30a[3]=-858993460a[4]=-858993460
越界访问的数组元素的值都是不确定的,没有实际的含义,因为数组之外的内存我们并不知道是什么,可能是其它变量的值,可能是函数参数,可能是一个地址,这些都是不可控的。
由于C语言的”放任“,我们访问数组时必须非常小心,要确保不会发生越界。每个C语言程序员的生涯中都遇到过越界错误,因为越界错误有时候不容易发现,也不容易复现。
当发生数组越界时,如果我们对该内存有使用权限,那么程序将正常运行,但会出现不可控的结果(如上例所示);如果我们对该内存没有使用权限,或者该内存压根就没有被分配,那么程序将会崩溃。请看下面的例子:
#include <stdio.h>
int main()
{
int a[3];
printf("%d", a[10000]);
return 0;
}
在 VS2010 下运行,会出现运行时错误:


在 C-Free 5.0 下运行,会弹出程序停止工作的对话框:
每个程序能使用的内存都是有限的,该程序要访问 4*10000 字节处的内存,显然太远了,超出了程序的访问范围。这个地方的内存可能没有被分配,可能是系统本身占用的内存,可能是其它数据的内存,如果放任这种行为,将带来非常危险的后果,操作系统只能让程序停止运行。
数组溢出当赋予数组的元素个数超过数组长度时,就会发生溢出(Overflow)。如下所示:int a[3] = {1, 2, 3, 4, 5};数组长度为3,初始化时却赋予5个元素,超出了数组容量,所以只能保存前3个元素,后面的元素被丢弃。
GCC、LLVM/Clang、低版本的 VS(例如 VS2010)发现数组溢出只会给出警告,并不会报错。但是高版本的 VS(例如 VS2015、VS2017)发现数组溢出时会报错,禁止编译通过,微软终于聪明了一次。
一般情况下数组溢出不会有什么问题,顶多是丢失多余的元素。但是当以字符串的形式输出字符数组时,就会产生不可控的情况,请看下面的代码:
#include <stdio.h>
int main()
{
char str[10] = "88888888888888888888";
puts(str);
return 0;
}
在 DEV下的运行结果:


字符串的长度大于数组长度,数组只能容纳字符串的前面一部分,也就是"http://c.b",即使编译器在最后添加了'\0',它也保存不到数组里面,所以 printf() 扫描数组时不会遇到结束符'\0',只能继续向后扫描。而后面内存中的数据我们不知道是什么,字符能否识别,何时遇到'\0',这些都是不确定的。当字符无法识别时,就会出现乱码,显示奇怪的字符。
由此可见,在用字符串给字符数组赋值时,要保证数组长度大于字符串长度,以容纳结束符'\0'。
总结:能够理解数组越界和数组溢出的原因,并且在编程中注意避免。

使用特权

评论回复
沙发
tpgf| | 2024-2-1 08:13 | 只看该作者
在c语言中 有哪种类型是可以自动扩容的呢

使用特权

评论回复
板凳
zljiu| | 2024-2-1 09:17 | 只看该作者
我们可以添加代码对数组越界进行实时检测

使用特权

评论回复
地板
tfqi| | 2024-2-1 21:55 | 只看该作者
在单片机c语言中可以使用链表吗

使用特权

评论回复
5
gwsan| | 2024-2-1 22:29 | 只看该作者
每次操作的时候都限定一下操作的范围就可以了吧

使用特权

评论回复
6
aoyi| | 2024-2-1 23:01 | 只看该作者
如果下标大于数组长度 难道不会报错吗

使用特权

评论回复
7
nawu| | 2024-2-1 23:33 | 只看该作者
数组的越界可以实时进行监测吗

使用特权

评论回复
8
alvpeg| | 2024-2-4 21:26 | 只看该作者
在定义数组时,确保分配了足够的空间来容纳所需的元素。如果不确定数组大小,可以使用动态分配内存的方法,如malloc函数。

使用特权

评论回复
9
pl202| | 2024-2-6 16:02 | 只看该作者
避免数组越界与溢出的关键在于良好的编程实践

使用特权

评论回复
10
eefas|  楼主 | 2024-2-6 20:55 | 只看该作者
可能使用标准库提供的安全版本函数,比如字符串操作使用strncpy()而非strcpy(),以防止缓冲区溢出。

使用特权

评论回复
11
ingramward| | 2024-2-6 23:07 | 只看该作者
指针可以用来绕过数组边界,因此使用指针时必须小心,避免访问不属于数组的内存区域。

使用特权

评论回复
12
houjiakai| | 2024-2-6 23:52 | 只看该作者
使用标准库函数,如memcpy()、memset()等,避免手动操作数组时出现越界或溢出问题。

使用特权

评论回复
13
sesefadou| | 2024-2-7 10:01 | 只看该作者
在使用完数组后正确地释放内存(使用free),并避免访问已释放的内存。

使用特权

评论回复
14
wilhelmina2| | 2024-2-7 10:48 | 只看该作者
当编写处理数组的函数时,除了数组指针外还应传递数组长度,以便内部实现能正确检查边界。

使用特权

评论回复
15
linfelix| | 2024-2-7 11:57 | 只看该作者
定期进行代码审查,提高代码质量,遵循安全编码实践,减少人为错误导致的数组越界问题。

使用特权

评论回复
16
lihuami| | 2024-2-7 15:40 | 只看该作者
在访问数组元素之前,使用循环或条件判断来检查索引是否超出了数组范围。只有在索引合法的情况下才能访问数组元素。

使用特权

评论回复
17
claretttt| | 2024-2-7 15:49 | 只看该作者
在访问数组元素时,检查数组索引是否在有效范围内。如果索引超出范围,可以抛出异常或返回错误信息。

使用特权

评论回复
18
jimmhu| | 2024-2-7 16:09 | 只看该作者
在C99标准中,还允许使用单个指示符为数组的两段“分配”空间。

使用特权

评论回复
19
benjaminka| | 2024-2-7 16:22 | 只看该作者
在处理字符串时,使用strncpy、strncat、strncmp等带有长度参数的函数,而不是strcpy、strcat、strcmp等容易导致缓冲区溢出的函数。

使用特权

评论回复
20
dspmana| | 2024-2-7 16:37 | 只看该作者
正确使用数组下标              

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

50

主题

2589

帖子

2

粉丝