C语言中的作用域与储存期(包含局部变量、全局变量、auto、register、static、extern)

作用域

通常来说,一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域
作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少名字冲突。
相同的作用域内不可同时定义多个同名的变量,否则编译器会因为无法准确使用而报错。

具体理解可根据以下代码:

#include <stdio.h>

int x = 10;//A位置

void print_x()
{
	printf("x=%d\n", x);
}

int main()
{
	int x = 20;//B位置
	print_x();
	printf("x=%d\n", x);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		int x = i * 10;//C位置
		printf("x=%d ", x);
	}
	printf("\n");
	return 0;
}

上面的代码中一共出现了三个定义 x 变量的位置,分别是A、B、C。

首先我们看一下 A 位置的 x ,该变量初始化为10,因为它定义的位置并不属于某个函数而是属于整个文件中,所以 A 处的 x 的作用域是整个文件,属于全局变量
当我们调用 print_x(); 函数时,函数内部并没有定义变量 x ,此时则会使用全局变量 x ,所以调用 print_x();函数的结果是x=10.

对于 B 处位置 x 的声明,他是在 main 函数的程序块中声明的,所以它的使用范围就是在 main 函数的内部,即在遇到 main 函数的 } 之前都是可用的。属于局部变量
所以在13行代码 printf("x=%d\n",x); 打印 x 的值的结果是x=20

如果两个同名变量分别拥有文件作用域和块作用域,那么只有拥有块作用域的变量会被使用,而拥有文件作用域的变量则会被“隐藏”。
当同名变量被赋予了块作用域时,内层变量是可以正常使用的,而外部变量则会被“隐藏”起来。

对于 C 处位置 x 的声明,因为 C 处位置的作用域在 for 循环内部。所以当 for 循环内部遇到代码 printf("x=%d\n",x); 打印 x 的值的时候,此时的值是由 for 循环内部的 x 值决定的。属于局部变量
所以五次打印的结果为x=0 x=10 x=20 x=30 x=40

局部变量

局部变量,也称内部变量,是指在一个函数内部或复合语句内部定义的变量 。局部变量的作用域是定义该变量的函数或定义该变量的复合语句。局部变量的生存期是从函数被调用的时刻算起到函数返回调用处的时刻结束。也就是说,局部变量只在定义它的函数或复合语句范围内有效,只能在定义它的函数或复合语句内才能使用它们。

全局变量

全局变量也称外部变量,它是在函数外部定义的变量。它不属于哪一个函数,而是属于一个源程序文件,其作用域是整个源程序。
当全局没有进行初始化的时候,编译器会自动初始化为0

注意事项:
1,使用全局变量会占用更多的内存(因为其生命期长),不过在计算机配置很高的今天,这个不应该算什么问题,除非使用的是巨大对象的全局变量,能避免就一定要避免
2,使用全局变量程序运行时速度更快一些(因为内存不需要再分配),同样也快不了多少。
3,对于局部变量的名字空间污染,这个在不使用太多变量时是可以避免的。
4,当全局变量与局部变量重名的时候,起作用的是局部变量,全局变量被屏蔽掉。
5,还可以用extern在函数外对全局变量声明,使全局变量的作用域从声明处到文件的结束。
总之,全局变量可以使用,但是全局变量使用时应注意的是尽可能使其名字易于理解,而且不能太短,避免名字空间的污染;避免使用巨大对象的全局变量。

储存期

在函数中声明的变量,并不是从程序开始到程序结束始终都是有用的/有效的,变量在程序中有属于他的生存期(寿命),他们的寿命就被成为储存期

自动储存期

在函数执行到对象声明的时候就创建出相应的对象,当程序执行到包含该声明的程序块结尾(遇到他所在的 } )的时候,该对象就会被销毁。
如果声明的对象没有进行初始化,则编译器会将其初始化为随机值

auto

auto是在C++中较为常用的的一个关键字,但是C语言中也有关键字 auto,其作用是声明定义的变量所在的区域为自动储存期
但是当声明变量时编译器会默认使用自动储存期,所以在程序中加不加 auto 的效果是相同的。
所以在程序中,auto 并没有太大大意义。

register

使用 register 关键字进行声明,在编译的时候,编译器会将对象储存在更为快速的寄存器中,而不是内存中。
但是由于寄存器的空间较小,当内容较多时,则会储存在内存中,所以对象并不一定会存储到寄存器中。
由于现在的编译器为了执行循序的效率进行了优化,所以即使已经存储到寄存器中,但是当编译器认为此操作对程序没有帮助时,保存在寄存器中的值就有可能发生改变。
所以在现在的程序中,register 对程序也没有了太大的意义。

静态储存期

在程序执行之前,或者说是在 main 函数执行之前的准备阶段就已经被创建。在程序结束之后才会被销毁。该对象拥有的储存期是整个程序。
当该对象没有进行初始化的时候,编译器会自动初始化为0
在函数中使用 static 定义出来的对象,或者在函数外声明定义出来的对象的储存期都是静态储存期。

static

使用 static 声明定义的变量,其在程序的准备阶段就被创建,并储存在静态区
当没有初始化的时候,编译器会进行默认初始化。

当类型为整形,例如 int 时,初始化为0;
当类型为浮点形,例如 double 时,初始化为0.0;
数组中的每个元素也会被初始化为0(或者0.0);

示例

对比

自动储存期静态储存期
生成程序执行到对象声明的时候创建出相应的对象在程序开始执行的时候创建出来
初始化如果没有初始化,编译器会初始化为随机值如果没有初始化,编译器会初始化为0
销毁在执行到声明所在的程序块结尾时销毁在程序结束时销毁

extern

如果外部变量不在文件的开头定义,其有效作用范围只限于定义处到文件结束,在定义点之前的函数不能使用该全局变量。如果在定义点之前的函数要使用该全局变量,要用extern关键字对该外部变量声明,表示把该变量的作用域扩展到此处,有了此声明,就可以从“声明”处起,合法的使用该外部变量。
被extern修饰的全局变量,在编译期不会分配空间,而是在链接的时候通过索引去别的文件中查找索引对应的地址。

  • 50
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雾里看山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值