前言
在C语言学习中,内存的运用是最重要的部分。不论是后续学习的指针,亦或者是动态内存管理都是离不开对内存的理解。拥有对内存的理解,不论在前期的基础学习或是在后期难题突破都有极大作用,在此我从内存的角度带大家理解数据类型与变量。
博客大纲
内存
什么是内存
内存指的并非一个计算机的储存容量,内存是一种用来存储临时数据的物理硬件,其最大特点就是直接与CPU交互,可以极快地把数据传给CPU,从而提高计算机的效率。而我们写代码的时候,比如int a= 10;这样一个代码,就是为a开辟一定大小的内存,并把10这个数据存入。
内存的分区
在人体中,有专门用于消化的肠胃,专门用于呼吸的肺,一个器官只干一类事情,可以极大提高生命活动的效率。
计算机的内存也是如此,由于内存需要传输的数据种类太多了,于是设计者将内存进行了分区,并为它们赋予专门的作用。
内存分为五大区,我们在C语言学习中最常用的就是:栈区,堆区,静态区。
栈区: 此区域用于存放一些并非整个程序都能使用的数据,即局部变量
静态区: 此区域用于存放一些整个程序都能使用的数据,即全局变量
堆区: 此区域用于动态内存管理,这是后续学习动态内存会使用到的区域,可以理解为,这块区域是易于程序员利用代码操控的。
接下来用一串代码来展示:
变量
什么是变量
变量代表一个有名字的、具有特定属性的一个存储单元,变量用来存放数据,也就是存放变量的值。
比如说int a = 10;从表面上来说,是创建一个名为a的数据,并为a赋值为10,
本质上来说,就是在内存中分出一块区域,把这个区域命名为a,然后往这个区域中存入数字10这个数据。
变量的生命周期
从刚刚变量的本质,可以发现变量就是一个用于存放数据的,有名字的内存块。那么一个变量能被创建,就能被销毁,一个变量从创建到销毁这个时间段,就是它的生命周期。
比如一个函数:
int Add(int x,int y) { int num = x + y; return num; }
这个Add函数中,有三个变量x,y,num。x和y是伴随着函数创建而一起创建的,当调用函数结束,x和y也会一起销毁。那么x和y的生命周期就是从这个Add函数的调用到Add函数执行结束。
而对于num,它是在函数调用后创建的变量,也就是说,num的生命周期是Add函数开始后一会,到Add函数执行结束。
我们再用一个图来理解:(注意,函数在调用的时候,内存会为整个函数分配一个空间,函数内部的所有局部变量都在这个分配的空间中),上方的红色框里的代码,指当前正在执行的代码。
从上图可以非常直观地感受到,一个变量的生命周期就是这个变量从内存为其分配空间到其空间的释放。
变量的作用域
变量的作用域就是指这个变量在什么区域可以使用,有不少人认为:变量的生命周期和作用域是一样的。这是一个完全错误的观点。局部变量的作用域一般是创建这个变量到变量所在的函数结束,而全局变量的作用域是:整个程序减去有同名局部变量的函数内部的区域。接下来我们一一解释两种变量的作用域。
局部变量的作用域
局部变量的作用域是创建这个变量到变量所在的函数结束
我们有如下代码:
int Add(int x,int y) { int num = x + y; return num; } int main() { int a = 1;; int b = 2; Add(a, b); }
请问a,b,x,y,num的作用域是什么?
我们靠图片分析:
在图片1中:
a和b是在下方绿色区块的main函数内创建的,那么a和b的作用域就是这个main函数内。那main函数调用了Add函数,Add函数内部是不是a和b的作用域呢?
要回答上述问题,不妨先回答:在Add函数内能不能完成int num = a + b;很明显是不行的,也就是说,a和b这两个变量,是无法在Add函数内使用,那么Add函数内部也就不是a和b的作用域了。
对x和y来说,它们是伴随Add函数创建的,它们的作用域就是这个Add函数内部,当这个Add函数调用结束,我们就不能使用这里的x和y了。对于num来说,它的创建略晚于a和b,所以它的作用域就是从num创建到这个Add调用结束。
接下来我们转到图片2:
相比于图片1,图片2我们在main函数内创建了x,y,然后调用Add函数,Add函数又创建了x,y。这里出现了同名的变量,请问最后完成的是1+2还是3+4?
这就涉及到了同名变量的问题。当一个函数内创建的变量与外部创建的变量重名时,优先使用函数内创建的变量。
又图1的分析,我们知道,a,b的作用域并不包括Add函数内,在这也是一样的,main函数内创建的x和y只能供main函数使用,Add函数创建的x,y也只能供Add函数使用,最后函数完成的是传入的a和b的加法,即1+2。
图片分析:
上图中,我用蓝色与绿色的框区分了两个函数内的x与y。这就像在地球上有很多人叫做张三,但是当一个老师在班上点名让张三回答问题时,点的一定是班上那个叫做张三的人。
全局变量的作用域
全局变量的作用域情况和刚刚讨论的重名问题十分相似,也就是说,我们定义一个全局变量后在后续任然可以用这个变量来命名新的变量。但是在命名新变量的函数中,原先的
以以下代码为例:
int x = 5; int y = 6; int main() { printf("%d\n", (x + y)); int x = 3; int y = 4; printf("%d\n", (x + y)); }
此代码中,我们正在函数外部定义了x和y,又在main函数内定义了x和y。
提问:main函数中两个printf的输出结果分别是什么?
又上图可知,第一次printf时,新的xy还没有创建,使用的就是全局变量xy。第二次printf时,由于main函数内创建了新的xy,那么printf使用的就是局部变量xy。
那么全局变量xy的作用域是什么?
从上述分析得出,全局变量在局部的xy创建时就暂时停止了,那我们画张图来表示下它们作用域
可以用非常明显的看到,并非生命周期和作用域是完全重合的。