数组的下标越界与内存溢出

很相似的两个概念,一不小心就会混淆

首先,对两个名词做一个大概的解释:

  1. 下标越界
    引用数组元素时,使用的下标超过了该数组下标的应有范围,但应注意的是:
    C/C++不对数组做边界检查。 可以重写数组的每一端,并写入一些其他变量的数组或者甚至是写入程序的代码。不检查下标是否越界可以有效提高程序运行的效率,因为如果你检查,那么编译器必须在生成的目标代码中加入额外的代码用于程序运行时检测下标是否越界,这就会导致程序的运行速度下降,所以为了程序的运行效率,C / C++才不检查下标是否越界。发现如果数组下标越界了,那么它会自动接着那块内存往后写。
    关于C/C++为什么不对数组的下标是否越界做检查,可以参考:
    http://www.xuebuyuan.com/967089.html
    因为编译器不会自动检测你的数组下标是否越界,而是把这个任务交给了程序员自己,所以我们在写程序,引用数组元素时,一定注意不要让数组的下标越界。
    还有,初学者一定不能忘了数组的下标是从0开始的,不是常识中的从1开始。
  2. 内存溢出
    初始化数组(给数组元素赋值)时,初始化(赋值)元素的个数超过了数组定义时元素的个数。这里的元素个数就是在定义数组时那个方框框里的数字,对于多维数组来说,元素个数 = 每个方框框里的数字之积。
    当然,求数组元素个数可以用公式:
    数组元素个数 = sizeof(数组名)/sizeof(数组任意一个元素)

用两个具体的例子来看看它们之间的区别:

1、 下标越界

#include <stdio.h>int main()
{int i=10, arr[10];int sz = sizeof(arr) / sizeof(arr[0]);int index = 0;scanf("%d", &index);arr[index] = 20;printf("arr[%d] = %d\n", index,arr[index]);system("pause");return 0;
}

数组定义为arr[10],它的下标范围是 0–9 ,超出这个范围就会发生下标溢出
这里写图片描述

这里写图片描述
以上两张图片是在VS2013里面的运行结果,两次输入的下标都会越界,但为什么第一张图报错了(数组下标越界),而第二张没有。
这是因为VS2013这个编译器在处理数组下标时,只认为当引用的下标等于数组元素个数时下标越界(可能是怕初学者把数组下标当成是以0开始的吧),别的情况别不回去检测和处理(当我输入的值大于等于11,程序都不会报错)。

这里写图片描述

这里写图片描述
以上是在VC6.0的运行结果,VS2013不同,VC6.0里报错出现在输入值为11时(当输入12时也会报错),而输入10时并不会报错。
这是因为VC6.0里认为当引用数组元素时,若数组的下标比数组的元素个数大 1 (或大 2)时下标越界,。而对于其余的情况不予检测。

这里写图片描述

而在Linux(CentOS6.5)里面运行时,就是我们开头说的那种下标越界的情况,不管你下标咋越界,我的编译器都不会对数组下标做边界检查。

2、 内存溢出

#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h>          int main()
{int count[100], i;for (i = 0; i <= 100; i++){count[i] = 1;}system("pause");return 0;
}

数组定义为count[100],则数组共有100个元素。这里初始化时,for循环一共循环了101次,所以是要给数组初始化101个元素的值,而数组只有100个元素,这样就导致了内存溢出。

这里写图片描述

VS2013环境下,编译链接运行都可以,但会抛出一个错误—>>数组内存溢出。

这里写图片描述

这是在VC6.0环境下,编译链接运行都可以,但同样会出错。

这里写图片描述

这是在Linux(CentOS6.5)环境下,编译链接运行都可以,但程序停不下来,关闭终端时可以看到程序仍在进行。

因此,虽然数组在C语言中是个很强大的东西,但在应用时一定要注意,千万不要出现下标越界的情况,因为这样会造成不可想象的错误。比如下标越界那个例子中的 i 我定义为10,当在VS2013环境下,我输入的下标值为12,在输出arr[12] = 20 的同时,会把i的值也改为20(VS中定义的两个变量,分配内存时会在两个变量的内存空间之间隔出两个空间,空间大小为整形大小),这样别处再用到 i 时 会得到一个错误的 i 的值,可能机会导致一连串的错误,致使结果与预期相差甚远。同时,在初始化数组时,要注意不要初始化的元素个数,不要超出了定义时的个数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/526210.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

二分查找(折半查找)

二分查找(折半查找)&#xff1a; 从有序序列中找到给出的要查询的数字。 原理是&#xff1a;首先把一个有序序列中间位置的值与要查找的数比较&#xff0c;若相等则找到了有序序列中的此数&#xff1b;否则比较两者的大小&#xff0c;若前者大&#xff0c;则把有序序列的中间…

C语言实现用星号在屏幕上打印菱形

很多人第一感觉肯定都是&#xff1a;很简单啊&#xff0c;不就是多写几个printf 语句嘛 像这样&#xff1a; #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>int main() {printf(" *\n");printf(" ***\n");printf(" *****\n");p…

多维数组元素的下标引用与指针访问

在这儿值介绍二维数组元素的访问方式&#xff0c;三维、四维……的与之类似。 先用一维数组的相关知识来抛砖 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h>//1、一维数组元素的下标引用与指针访问 int main() {int arr[10] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }…

scanf()函数错误把输入缓存里的回车作为一次字符输入

有时我们会需要连续的从标准输入中多次读入数据时&#xff0c;那么就可能存在连续使用多次scanf()函数的情况。然而在连续使用scanf()函数时可能会出现一些难以预料&#xff0c;不易发现的坑 #include <stdio.h>int main() {char str[20] { 0 };char c 0;scanf("…

C语言注释与C++注释的相互转换

做此项目的经历主要的收获是熟悉了状态机这一方法的使用&#xff0c;还有就是对每实现一个功能就尽量封装一个函数这一概念把握的更为精到。 状态机&#xff1a;关于状态机的一个极度确切的描述是它是一个有向图形&#xff0c;由一组节点和一组相应的转移函数组成。状态机通过…

运算符优先级与结合性

在编程中经常会有遇到运算符的地方&#xff0c;而每个运算符都有不同的优先级&#xff0c;错误的使用运算符&#xff0c;可能会发生难以预料而又不易发现的错误&#xff0c;因此我们需要掌握运算符的优先级。 优先级的序号越小&#xff0c;优先级越高。

switch()语句块的出口:break;

switch()语句块里的case:相当于一个开关&#xff0c;只要满足case的条件&#xff0c;开关就打开&#xff0c;从而执行case语句块的内容&#xff0c;而break就相当于一个出口&#xff0c;只要碰到了break&#xff0c;就跳出switch语句块&#xff0c;否则就继续执行下一条语句&am…

函数声明

对C缺陷与陷阱里第二章第一节里面的函数声明的一些段落的理解

字符变量存放多个字符

在我们的认知中&#xff0c;不会有字符变量中存放多个字符的情况&#xff08;不要说\n、\t等&#xff0c;这些本来就被C语言标准定义为是一个字符&#xff09;&#xff0c;因为一个字符变量就只占1个字节空间&#xff0c;只能存放一个字符&#xff0c;但往下看&#xff0c;你会…

不同类型的变量与零值比较的方法

在if()、while()等语句块中&#xff0c;我们经常会遇到变量与零值比较的情况&#xff0c;然而不同的类型的变量与零值的比较方法是有一定标准的&#xff0c;编程时最好遵守这些标准&#xff0c;否则会发生一些难以预料的错误。

测试机器大小端的方法

首先&#xff0c;给出一些大小端相关概念。 大小端的由来&#xff1a; 在乔纳森斯威夫特的著名讽刺小说《格列夫游记》中&#xff0c;小人国内部分裂成Big-endian和Little-endian两派&#xff0c;区别在于一派要求从鸡蛋的大头把鸡蛋打破&#xff0c;另一派要求从鸡蛋的小头把…

main()函数参数

很多人学了很长时间的C语言&#xff0c;可能还不知道mian()函数也是有参数的&#xff0c;甚至会说&#xff0c;main()函数哪来的参数&#xff0c;我从来都没见到过&#xff0c;更没有使用过&#xff0c;然而&#xff0c;不得不说&#xff0c;main()函数确实是有参数的。 main函…

运算符求值顺序

&&与||两个运算符的求值顺序是非常重要的&#xff0c;因为很多判断语句都是基于它们拥有一定的求值顺序才能正确进行的。 eg: if((num1 ! 0) && (num2 / num1 \ > num2 - num1)) 上面的if()判断语句合理的运用了&&运算符&#xff0c;使之不会出现…

CentOS设置

我的CentOS是在VMware Workstation里面装的虚拟机&#xff0c;但操作都是一样的 1、设置系统语言 许多人在安装CentOS系统时&#xff0c;可能在开始阶段选择区域及语言时选择了非中文&#xff0c;而却想在中文环境下使用系统&#xff0c;却苦于不知道如何切换到中文系统&…

printf函数的格式修饰符

本文介绍printf函数的一些特殊的格式控制修饰符 1、域宽修饰符 –> 数字 对所有格式控制符都有效&#xff0c;即便是%%也不例外 宽度修饰符出现在%和格式控制符之间的数字&#xff0c;使数据在固定区域打印。如果待打印的数值不能填满位置&#xff0c;它的左侧会被天上空…

线性表之顺序表与单链表的区别及优缺点

这里比较的是基于C语言实现的顺序表与单链表&#xff0c;与其他语言的实现可能会有差异&#xff0c;但我相信语言是相通的&#xff0c;它们的实现机制应该也差不多。 1、What 什么是顺序表和单链表 ①顺序表&#xff1a; 顺序表是在计算机内存中以数组的形式保存的线性表&a…

前置++与后置++之一道简单的题目引发的思考

引言 昨晚一时兴起&#xff0c;我脑子就问自己下面的代码会输出什么&#xff0c;也不知道我脑子为什么有这个代码模型&#xff0c;只是模糊的有些印象&#xff1a; #include <stdio.h> #include <stdlib.h>int main(int argc,char** argv) {int i3,j;j(i)(i)(i);…

有趣的for循环

#include <stdio.h> int main() {int i 0;for(i 0, printf(" First %d", i);i<10, printf(" Second %d", i);i, printf(" Third %d", i)){printf(" Fourth %d", i);}system("pause");return 0; } 这段代码会…

重载函数编译后的新名字

我们都知道很多语言都支持函数重载&#xff0c;那么编译器是怎么处理编译后它们的命名冲突的呢&#xff1f; 1、先给出几个正确的重载函数&#xff1a; #include <iostream> using namespace std;int Add(int a, int b) {return a b; }double Add(double a, double b)…

乱入的'\0'

看这个题之前&#xff0c;先来回忆一下strlen函数的工作机制&#xff1a; strlen所作的仅仅是一个计数器的工作&#xff0c;它从内存的某个位置&#xff08;可以是字符串开头&#xff0c;中间某个位置&#xff0c;甚至是某个不确定的内存区域&#xff09;开始扫描&#xff0c;…