第十二次课----全局变量、局部变量和存储类别
一、作用域
1.文件作用域
2.函数作用域
3.语句块
demo1:
int main(void)
{
int a = 0;
{
int i = 0;
}
i = 10;//错误,i超出了它的作用域范围
return 0;
}
demo2:
int main(void)
{
int a = 0;
for(int i = 0;i < 5;i++)//i是语句块作用域
{
}
i = 10;//错误,i超出了它的作用域范围,
return 0;
}
注意:
1>同一个作用域中不能出现相同的标识符(黑色单词,如变量名,函数名)
demo:
void foo(int a)
{
int a = 0;//错误,a重定义
}
void foo(void)//错误,foo重定义
{
int foo= 0;//正确
}
2>函数作用域嵌套在文件作用域内,语句块作用域嵌套在函数作用域内。
demo:
//文件作用域
void foo(void)//函数作用域
{
int a = 0;
for(int i = 1; i < 10; i++)//语句块作用域
{
}
}
3>判定标识符属于哪一个作用域的原则是:就近原则
标识符不能同时属于两种作用域!
demo
void foo(void)
{
int i = 0;
for(i = 1; i < 10; i++)//语句块作用域
{
int i = 10;
printf("%d\n", i);
}
printf("%d\n", i);
int foo = 10;
printf("%d", foo);//是函数名还是变量名??
}
demo2分析下面变量的作用域
float f1(int a)
{
int b = 0,c = 0;//a,b,c在f1中有效
}
float f2(int x,int y)
{
int i = 0,j = 0;//x,y,i,j在f2有效
}
int main()
{
int m = 0,n = 0;//m,n只在main 函数中有效
return 0;
}
4>
局部变量:就是在函数作用域或者是语句块作用域中定义的变量
全局变量:就是在文件作用域中定义的变量(实际开发中尽量不要使用全局变量)
demo识别以下变量是局部变量还是全局变量
int g_a = 0;
void foo(void)
{
int i = 0;
for(i = 1; i < 10; i++)
{
int i = 10;
printf("%d\n", i);
}
printf("%d\n", i);
int foo = 10;
printf("%d", foo);
}
int foo = 0;//error
总结:
作用域解决的是标识符的使用范围,是空间的问题
5>全局变量和函数都属于文件作用域内的标识符,文件作用域内的标识符是可以通过extern扩展作用域的!
demo1 指出下面程序的错误
int main(void)
{
foo();//error
printf("%d", g_a);//error
return 0;
}
void foo(void){}
int g_a = 0;
改进如下
extern void foo(void);
extern int g_a = 0;
int main(void)
{
foo();//error
printf("%d", g_a);//error
return 0;
}
void foo(void){}
int g_a = 0;
二、存储类别
1.存储类别解决的是标识符的“生命周期”或者变量内存的开辟时间和销毁时间
2.学习存储类别时不要去考虑作用域,两者没有关系!
void foo(int a)
{
int b = 0;
}//a内存销毁
int main(void)
{
foo(10);//a内存开辟
return 0;
}
三、栈变量:auto声明的变量
变量内存开辟时间:栈变量是在执行到变量定义语句时开辟内存
变量内存销毁时间:所在作用域结束后销毁
void foo(int a)
{
int b = 0;//b开辟内存
{
int i = 0;//i开辟内存
}//i内存销毁
i = 10;//错误,i内存已经销毁
}//b内存销毁,a内存销毁
int main(void)
{
foo(10);//a开辟内存
foo(20);//a重新开辟内存
return 0;
}
注意:只有局部变量可以用auto修饰,全局变量不行,默认情况下是可以省略。
demo:
auto int a = 0;//错误,a是全局变量不能用auto修饰
int main(void)
{
auto int i = 0;
int b = 0;
}
四、全局区变量:用static声明的变量
变量内存开辟时间:编译时
变量内存销毁时间:主函数结束时
void foo(int a)
{
static int b = 0;//b编译时开辟内存,该语句只在编译时执行一次,后面不再执行
{
int i = 0;//i开辟内存
}//i内存销毁
b++;
printf("%d\n",b);
}//a内存销毁
int main(void)
{
foo(1);//a开辟内存
foo(2);//a重新开辟内存
return 0;//主函数结束时b销毁内存
}
注意:1>并非所有的变量都可以声明为static,形式参数不能声明为static,只能声明 为auto.
void foo(static int a);//错误,形参a不能用static声明
void foo(auto int a);//正确
2>变量声明为static时,不赋初值时默认为0.
void foo(void)
{
static int count;//默认是0
count++;
printf("%d", count);
}
int main(void)
{
foo();
foo();
foo();
return 0;
}
3>全局标识符如果用static修饰,并不是表示在全局区而是表示该标识符只能在本文件内被扩展使用。
demo1:
main.c:
extern int g_a;//正确
static int g_a;
fun.c
extern int g_a;//错误
demo2.
main.c:
extern void foo(void);//正确
static void foo(void){};
fun.c
extern void foo(void);//错误