首页 > 系统相关 >C语言数组越界和内存分配

C语言数组越界和内存分配

时间:2022-11-13 22:25:21浏览次数:45  
标签:10 200 堆区 C语言 越界 内存 数组

事情经过

11月3日晚,今天遇到了一个神奇的现象,一个大小为10的数组可以容纳200个数据,直接震惊我了!

今天发11月2日的参考代码,有一个同学给我看他的代码,大概是这样的

int main(){
   int a[10];
  ....
   for(int i = 0 ; i < n; i++){
       scanf("%d",&a[i]);
  }
  ....
}

问我为什么过不了测试数据,我告诉他把数组开大一点,因为测试数据会有200个数据。

但是他又告诉我,为什么他室友定义的数组大小是10,却可以通过样例,他给我看了室友的代码

int a[10];

int main(){
  ....
   for(int i = 0 ; i< n; i ++){
       scanf("%d",&a[i]);
  }
  ...
}

我不信,然后我就拿去洛谷平台试了一下,果然通过测试了!

然后我又在本地的DEV中运行,我丢,200个数据果然通过可以正常运行并输出结果。

通过对比两者的代码,我发现,他室友将数组定义为全局数组,他定义为局部数组,为什么定义为局部数组不能通过测试数据?

我当时想:是不是全局数组在动态运行的过程中,进行了扩容?然后我又在程序的末尾检测了一下数组的容量大小。

printf("%d",sizeof(a)/sizeof(a[0]));//
//输出10

又震惊了我一下,数组的容量是10 ,竟然可以容量200个数据。

然后我又打印a[0]a[200]的地址

printf("%d %d",&a[0],&a[200]);
// 4223040 4223840
// 打印发现两者的地址相差 800
// 也就是200*4,因为一个int占4个字节

数组元素的地址是正确的,但是数组的容量却是小的,我似乎有了一些思路。

解释

通过在网上的搜索,我了解到C/C++是不会对数组的越界做出判断的,也就是说可以对数组进行越界访问和操作

数组在定义时,规定了数组的大小是10,在程序运行的过程中,对数组进行赋值操作,当下标大于等于10以后,此时继续进行存取操作是越界的,但是C/C++没有数组越界的判断,所以可以对数组之外的内存区域进行了操作

那样这就容易解释了为什么容量为10 的数组能够存200个数据。

那么还有一个问题没有解决:同样是数组越界?为什么全局数组可以存取200个数据且得到正常的结果,局部数组就不能呢?

image-20221103230428706

此时得到的运行结果是这样的:数据都是正常的。

image-20221103230515292

此时再换成局部数组,继续同样的操作

image-20221103230659793

得到的结果是这样的

image-20221103230640549

 

发现打印出了错误的数据。

 

说明程序对于局部数组的越界是不稳定的操作,但是对于全局数组的越界操作缺失稳定的

 

至于为什么会这样?那就需要用C语言的不同的内存区域来解释了。

 

C语言内存管理

11月10日,终于有空来整理我的笔记了。

在C/C++ 的内存中有5个分区,分别是堆区、栈区、全局/静态存储区、常量存储区、代码区

20210319215715539

 

  • 栈区:程序运行时由编译器自动分配,当我们的代码在编译时,就会为局部变量、形参、返回值分配内存,这段内存属于栈区,当程序结束时由编译器自动释放。栈的特点是先进后出,在内存中由高地址向低地址扩展。栈的空间比较小,一般是几M,所以一般数组开的太大,就会有爆栈

  • 堆区:堆区是我们自己可以手动分配的区域,平时我们用malloc、calloc、new、free等控制的就是堆区内存,堆区的地址是由低地址向高地址扩展,我们在使用堆内存时,一定要牢记释放不用的内存区域,防止内存泄漏

  • 全局区:也叫静态区,这一段内存也是在编译时由编译器分配的,全局变量和静态变量都是存储到这一块区域,程序结束后自动释放

  • 常量区:存放常量类型,例如常量字符创

  • 代码区:我们写的代码的二进制形式就存储到代码区,一般我们不用关心

 

通过上面的分析,我们重新回到刚开头的位置,由于局部数组分配到栈区,栈区较小,所以数组越界之后的内容不会稳定,会被其他的变量覆盖掉。

全局数组分配到堆区,但是堆区比较大,数组虽然越界了,但是其他的变量的分配对越界部分的内存影响的概率较小。

总结数组大小根据实际的要求开,题目要求最大数据量是多少,尽量就开到多少,尽量将数组定义为全局数组。无论是全局数组还是局部数组,都不要数组越界,容易产生莫名其妙的错误

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

标签:10,200,堆区,C语言,越界,内存,数组
From: https://www.cnblogs.com/itkkk/p/16887177.html

相关文章

  • c语言第二例题
    题目:企业发放的奖金根据利润提成。利润(I)低于或等于10万元时,奖金可提10%;利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可提成7.5%;20万到40万之间......
  • C语言 #define 和 typedef 区别
    在C语言编程中,typedef和 #define是最常用语句,可能很多工作过几年的工程师都没有去深究过它们的一些用法和区别。typedef的用法在C/C++语言中,typedef常用来定义一个标识......
  • 面试常问的16个C语言问题
    1.用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)#defineSEC_YEAR(365*24*60*60)UL考察点:1) #define 语法的基本知识(例如:不能以分号结束,......
  • C语言中的volatile
    volatile的定义:Indicatesthatavariablecanbechangedbyabackgroundroutine.Keywordvolatileisanextremeoppositeofconst.It indicatesthatavariable......
  • 现代操作系统(第3章 内存管理)
    目录3.1无存储器抽象3.2一种存储器抽象:地址空间3.2.1地址空间的概念基址寄存器与界限寄存器3.2.2交换技术3.2.3空闲内存管理1.使用位图的存储管理2.使用链表的存储管......
  • c语言数据统计
    #include<stdio.h>intmain(){intcount=0;intn,k,i;scanf("%d%d",&n,&k);for(i=n;i<=k;i++){intj=i;while(j>0)......
  • C语言学习--练习--合并两个字符串
    将两个字符串合并追加在一起,类似于python的str1+str2 #include<stdio.h>#include<string.h>#include<stdlib.h>//字符串追加,将两个字符串结合在一起intmain(......
  • 1.举例说明常用的7中数据寻址方式和3中内存地址的寻址方式, 2.总结16、32和64位CPU的
    数据寻址方式:(1)立即寻址,MOVAX,1234H(2)寄存器寻址,寄存器寻址的特点是操作数在CPU内部的寄存器中,在指令中指定寄存器号(3)直接寻址,MOVES:[5678H],BL(4)寄存器间接寻址,MOV[......
  • 扫雷游戏(C语言版)
    1.test.c#define_CRT_SECURE_NO_WARNINGS1#include"game.h"voidmenu(){printf("******************************\n");printf("*******1.play*******\n");......
  • 计算机等级考试二级C语言程序设计专项训练题——素数及应用
        素数(primenumber)又称质数,有无限个。一个大于1的自然数,除了1和它本身外,不能被其他自然数整除,这样的数就是素数,也就是说一个素数除了1和它本身以外不再有其他的......