数组越界问题
在 C 语言中,数组必须是静态的。换而言之,数组的大小必须在程序运行前就确定下来。
然而,在 C 语言中,为了提高运行效率,给程序员更大的空间,为指针操作带来更多的方便,C 不检查数组下标的取值是否在合法范围内,也不检查数组指针是否移出了数组的合法区域。
因此,在编程中使用数组时就必须格外谨慎,在对数组进行读写操作时都应当进行相应的检查,以免对数组的操作超过数组的边界,从而发生缓冲区溢出漏洞。(当然VS等现代编译器会警告数组越界,但是不会报错)
最近在做题时遇到了两个数组越界相关的问题,做一个整理。
1,粗心引起的越界
这道题写错的数组的长度(5写成6)导致输出出错。
#include<stdio.h>
int main()
{
int a[5] = { 1,2,3,4,5 };
for (int i = 0; i < 6; ++i)//写错了数组的长度
{
printf("%d ", a[i]);
}
return 0;
}
2,sizeof引起的越界
从表面看,sizeof(a) / sizeof(a[0])计算数组的长度,代码的输出结果应该是“0,1,2,3,4”,但实际结果却出乎我们的意料,如下图。
#include<stdio.h>
void test(int a[])
{
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
{
a[i]=i;
}
}
int main()
{
int a[5];
test(a);
for (int i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
{
printf("%d ", a[i]);
}
return 0;
}
在main函数中定义了int a[5];a代表的是整个数组(int a[5]);因此sizeof(a)=sizeof(int*)=20,在main函数中是可以计算出数组的长度。
然而用数组名作函数参数时,不是进行值传送而是地址传送,编译器传入的是数组的指针,它是一个int型指针(int * ),因此sizeof(a)=sizeof(int*)=4;而sizeof(a[0])=4,导致sizeof(a) / sizeof(a[0])=1。
这样test函数执行后在main函数中就出现了数组越界。
如何避免
显式地指定数组的边界
可以使用宏的形式来显式指定数组的边界
#define MAX 10
int a[MAX]={1,2,3,4,5,6,7,8,9,10};
for (int i = 0; i < MAX; ++i)//避免了错误
{
printf("%d ", a[i]);
}
不用sizeof计算指针长度
可以通过传入数组的长度的方式来解决这个问题
利用动态数组根据需要分配内存
在 C 语言中,数组必须是静态的。换而言之,数组的大小必须在程序运行前就确定下来。无法直接输入常数来分配数组内存。
printf("请输入数组长度:");
scanf_s("%d", &size);
int a[size];
动态数组提供了一种解决思路
动态数组可以·在程序运行阶段根据实际需要来分配内存空间的,而不是在编译阶段确定数组内存。这样做能够做到按需分配,而不浪费系统资源。主要应用在事先不知道数组的元素的情况下,需要在程序运行阶段按照实际的外部输入的数据才能确定数组大小的情况。
printf("请输入数组长度:");
scanf("%d", &size);
arr = (int*)malloc(size * sizeof(int));
//以一维数组为例,展示动态数组的建立
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
void test(int* arr,int size)
{
for (int i = 0; i < size; i++) {
arr[i] = i;
}
printf("\n打印数组元素:\n");
for (int i = 0; i < size; i++)
printf("%d\t", arr[i]);
}
int main() {
int* arr = NULL, size;
printf("请输入数组长度:");
scanf_s("%d", &size);
arr = (int*)malloc(size * sizeof(int));
if (arr == NULL) {
printf("内存申请失败!");
exit(1);
}
test(arr, size);
free(arr);
arr = (int*)malloc(2 * size * sizeof(int));
if (arr == NULL) {
printf("内存申请失败!");
exit(1);
}
test(arr, 2 * size);
free(arr);
return 0;
}
参考:
https://www.cnblogs.com/linxw-blog/p/10907557.html.
http://c.biancheng.net/view/366.html.