C语言:从内存出发,理解变量

简介: C语言:从内存出发,理解变量

前言

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创建时就暂时停止了,那我们画张图来表示下它们作用域

可以用非常明显的看到,并非生命周期和作用域是完全重合的。

相关文章
|
19天前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
30 3
|
4天前
|
C语言
【c语言】动态内存管理
本文介绍了C语言中的动态内存管理,包括其必要性及相关的四个函数:`malloc`、``calloc``、`realloc`和`free`。`malloc`用于申请内存,`calloc`申请并初始化内存,`realloc`调整内存大小,`free`释放内存。文章还列举了常见的动态内存管理错误,如空指针解引用、越界访问、错误释放等,并提供了示例代码帮助理解。
12 3
|
11天前
|
存储 C语言
【c语言】数据类型和变量
本文介绍了C语言中的数据类型和变量。数据类型分为内置类型和自定义类型,内置类型包括字符型、整型、浮点型等,每种类型有不同的内存大小和取值范围。变量分为全局变量和局部变量,它们在内存中的存储位置也有所不同,分别位于静态区和栈区。通过示例代码和图解,详细阐述了这些概念及其应用。
32 1
|
13天前
|
存储 C语言
C语言指针与指针变量的区别指针
指针是C语言中的重要概念,用于存储内存地址。指针变量是一种特殊的变量,用于存放其他变量的内存地址,通过指针可以间接访问和修改该变量的值。指针与指针变量的主要区别在于:指针是一个泛指的概念,而指针变量是具体的实现形式。
|
19天前
|
编译器 程序员 C语言
深入C语言:动态内存管理魔法
深入C语言:动态内存管理魔法
|
22天前
|
存储 C语言
C语言:设置地址为 0x67a9 的整型变量的值为 0xaa66
在C语言中,可以通过指针操作来实现对特定地址的访问和赋值。要将地址为 0x67a9 的整型变量值设为 0xaa66,可以先定义一个指向该地址的指针,并通过该指针对该内存位置进行赋值操作。需要注意的是,直接操作内存地址具有一定风险,必须确保地址合法且可写。代码示例应考虑字节序及内存对齐问题。
|
24天前
|
存储 程序员 编译器
C语言——动态内存管理与内存操作函数
C语言——动态内存管理与内存操作函数
|
26天前
|
C++
析构造函数就是为了释放内存,就是在局部指针消失前释放内存,拷贝构造函数就是以构造函数为模块,在堆里面新开一块,同一个变量在堆里面的地址
本文讨论了C++中构造函数和析构函数的作用,特别是它们在管理动态内存分配和释放中的重要性,以及如何正确地实现拷贝构造函数以避免内存泄漏。
32 2
|
6天前
|
存储 C语言
【c语言】字符串函数和内存函数
本文介绍了C语言中常用的字符串函数和内存函数,包括`strlen`、`strcpy`、`strcat`、`strcmp`、`strstr`、`strncpy`、`strncat`、`strncmp`、`strtok`、`memcpy`、`memmove`和`memset`等函数的使用方法及模拟实现。文章详细讲解了每个函数的功能、参数、返回值,并提供了具体的代码示例,帮助读者更好地理解和掌握这些函数的应用。
9 0
|
15天前
|
C语言
保姆级教学 - C语言 之 动态内存管理
保姆级教学 - C语言 之 动态内存管理
13 0