今天来聊一聊数据在内存中的储存方式,这些内容比较偏向底层,在c语言中简单讲解可以让大家更加了解编程。对于编程来说,我们所学的不应该是语言,过了十年,甚至二十年之后,可能在这样发展迅速的时代中,语言已经被淘汰,但是我们所学习的编程思想不会淘汰。
接下来开始今天的正题,来看下面的一段代码
#define _CRT_SECURE_NO_WARNINGS 1//取消警告
#include<stdio.h>
int main() {
int i = 0;
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
for (i = 0; i < 12; i++) {
arr[i] = 0;
printf("数组遍历\n");
}
return 0;
}
这段代码非常简单,这段代码有明显的错误,越界访问了
在执行程序的国政中,vs2022直接报错,现在让我们了解一下报错的更加深层次的原因。
这个数组是作为一个局部变量储存在计算机的栈区(计算机的内存的一块区域),栈区通常是存放局部变量的
现在华哥图为大家进行更详细的解释
假设这个长方形计算机的储存空间,其中每一个小块都是计算机的储存单元,其中位于上方的地址的十六进制序列比较大,所以被称为高地址,而下方的序列比较小,也就被称作低地址。
局部变量是被创建于栈区上的,即当前的i和arr是储存于栈区。栈区的使用习惯是:先使用高地址,再使用低地址。所以再创建变量之后大概就是这样
数组随着下标的增长地址由低到高变化,所以再栈中数组的储存应该是这样的
看刚才那段代码,如果i=10,11的时候,就开始越界访问了
他就访问到下标为10,下标为11的位置,接下来我们将编译器调整成release版本
再次运行,发现编译器并没有报错,这是因为 release版本是为程序做过优化的。这里我们再次深入了解一下release版本和debug版本的差别。
这里我们观察一下arr这个数组和变量i在计算机中储存的地址
#define _CRT_SECURE_NO_WARNINGS 1//取消警告
#include<stdio.h>
int main() {
int i = 0;
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%p,%p", &i, &arr[9]);
// for (i = 0; i < 12; i++) {
// arr[i] = 0;
// printf("数组遍历\n");
// }
return 0;
}
这是debug版本下的储存位置
这是release版本下的储存位置
大家可以仔细观察一下,在release版本中i的地址是要小于arr所在的地址,这也就是release版本为程序所做的优化。也就是说,在栈中debug版本i是储存于arr的上方的,而在release版本中,i是存储于arr下方的。这样就算arr再怎么越界访问,也只会访问到高地址处,并不会覆盖到i。
debug其实是作为调试版本,它包含了调试信息,并且不会做任何优化,便于程序员的调试
release版本被称作发布版本,它通常及进行了各种优化,让程序在大小和速度上是最好的,方便于用户去使用