分析:全局变量,局部变量,自动变量,静态变量

时间:2022-10-25 15:37:17

分析:全局变量,局部变量,自动变量,静态变量

标签:C语言 变量

by 小威威


1.全局变量&&局部变量

全局变量指在函数体之外定义的变量;
局部变量指在函数体内部定义的变量。

想必大家应该能分清这两个变量,我就不再阐述了。下面首先我要分析全局变量与局部变量出现名称相同的情况。

(1)全局变量与局部变量出现名称相同的情况

直接上例子:

# include <stdio.h>
void SomeFunc(float);
const int a = 17; // 定义一个全局常量a
int c; // 定义一个全局变量C
int b; // 定义一个全局变量b
int main(void) {
int e = 10; // 定义一个main函数的局部变量e
b = 4; // 给全局变量赋值
c = 6; // 给全局变量赋值
SomeFunc(42.8);
printf("In Function main\n");
printf("e = %d\n", e);
printf("b = %d\n", b);
printf("c = %d\n", c);
return 0;
}
void SomeFunc(float c) {
float b; // 定义SomeFun函数的局部变量b
float e = 3.14; // 定义SomeFun函数的局部变量e
b = 2.3; // 给局部变量b赋值
printf("In function SomeFunc\n");
printf("a = %d\n", a);
printf("b = %f\n", b);
printf("e = %f\n", e);
printf("c = %f\n", c);
}

输出结果:

In function SomeFunc
a = 17
b = 2.300000
e = 3.140000
c = 42.799999
In Function main
e = 10
b = 4
c = 6

也许你看出了这个代码定义变量的诡异,如在main函数外定义了一个c全局变量,而在SomeFunc中又定义了一个c局部变量。

你可能会问这样是否会导致编译出错?其实并不会。编译器在这方面还是挺聪明的。

当你定义了一个全局变量c时,编译器就会自动将这个变量名c改成global_c;当你定义了一个局部变量时,如本代码中在SomeFunc函数中定义的c,编译器会自动将变量名改为SomeFunc_c。换句话说,其实就是两个不同的变量,在内存中的位置是不同的,不会导致编译错误。

那么什么情况下才会出错呢?
1.定义两个相同名称的全局变量;
2.定义两个相同名称的局部变量。

对于第二点,我要补充说明下:这里的局部变量的范围并不是指函数体,而是花括号。下面我用例子说明:

int main() {
int i;
int j;
while( ) {
int i;
int j;
}
return 0;
}

如本代码,虽然在main中定义了相同名称局部变量,但还是不会出现编译错误,原因是:在出现花括号嵌套的情况下,每一对花括号类似一个小小的区室,将其中定义的变量与其它区室中的变量隔离开来。每个区室就类似于一个函数体,在其内部定义的变量与其它函数没有关联。

(2)全局变量的作用域

代码实例一:

# include <stdio.h>
void f (void);
int number = 0;
int main(void) {
printf("%d\n", number);
return 0;
}
void f(void) {
return;
}

代码实例二:

# include <stdio.h>
void f (void);
int main(void) {
extern int number;
printf("%d\n", number);
return 0;
}
int number = 0;
void f(void) {
return;
}

对比两代码,我们发现第一个代码将全局变量定义在main函数之前,第二个代码将全局变量定义在main函数之后。前者定义的全局变量的作用域在定义该变量语句之下直到代码结束,包含了main函数,而后者定义的全局变量的作用域也是在定义该变量语句之下直到代码结束但并不包括main函数。对于第二个代码,我在main函数中加了extern int number。该语句的作用是提醒编译器去寻找该语句之下的全局变量number,也就是说extern扩大了全局变量的作用域。

extern int number;这个语句是一个声明,不能起到定义全局变量的作用,倘若该语句下的全局变量定义语句不存在的话,编译器是会报错的。

这种情况类似于函数。当你把子函数定义在main函数前时就无需声明,在main函数之后定义就要声明,全局变量也是如此。

注意:代码实例二虽然没有语法错误,但不推荐大家这样写,这个代码只是为了说明全局变量作用域这一问题。

其实,extern扩大作用域并不局限于一个文件中,它可以用于将全局变量的作用域扩大到另一文件中去。而后者才是extern的主要应用。
例如:

// onefile.c
# include <stdio.h>
void f (void);
int main(void) {
extern int number;
printf("%d\n", number);
return 0;
}
// twofile.c
int number = 0;
void f(void) {
return;
}

如上面的代码,它是由两个.c文件构成的,onefile.c中的extern语句可以使得全局变量number的作用域扩大到twofile.c,即可以从twofile.c中将number的值传到one file.c。

2.自动变量&&静态变量

自动变量:一般以数据类型加上变量名的方式定义变量得到的是自动变量;
静态变量:定义变量时,在数据类型之前加上static得到的便是静态变量。

(1)自动变量的生命周期是由函数的生命周期所决定,即函数执行完毕自动变量便销毁;
(2)静态变量的生命周期是由整个程序所决定,即程序执行完毕时静态变量才销毁。因为静态变量储存在静态数据区,而函数是储存在栈中,函数执行完毕后栈销毁,不会影响到静态变量的值。

一般在全局变量前加上static是为了防止该变量被其他文件调用。

还是用刚才的例子,在全局变量前加上static。

// onefile.c
# include <stdio.h>
void f (void);
int number = 0;
int main(void) {
extern int number;
printf("%d\n", number);
return 0;
}
// twofile.c
static int number = 0;
void f(void) {
return;
}

因为加上了static,onefile.c无法调用twofile.c中的全局变量。因此,编译器会显示错误:Unresolve external。

下面来总结一下自动变量与静态变量的知识点:
1.定义局部变量时没有static,是自动变量;
2.定义局部变量时加static,是静态变量。局部静态变量的初始化语句在第一次进入该block时执行一次,以后再进入不再执行该初始化语句;
3.全局变量是静态变量(无论有没有加static);
4.定义全局变量时加static,是限制它不会被别的文件引用;
5.定义局部自动变量时,若没有初始化,则它的初始值是不确定的;定义静态变量(全局变量、局部静态变量)没有初始化,则其初始值为0.

3.总结

(1)提倡定义全局常量,尽量避免定义全局变量;
(2)编译器采用就近原则,当有两个变量的名称相同时(一个全局变量一个局部变量)取最接近的变量进行处理。即当全局变量与局部变量冲突时,全局变量服从局部变量;
(3)定义自动变量时要注意初始化,而静态变量会自动初始化为0且只初始化一次,即使在运行到该初始化语句,也不会改变其值;
(4)要调用其他文件中的全局变量,可加入extern的声明;
(5)要防止其它文件调用本文件的全局变量,要在本文件的全局变量的数据类型之前加上static。


以上内容皆为本人观点,欢迎大家提出意见,我们一起探讨!