文章目录
一、变量定义和声明
1、概念
1)声明:
说明符 声明表达式列表
用于向程序表明变量的类型和名字,不为变量分配内存空间
2)定义:
说明符 定义表达式列表
为变量分配存储空间,一个变量有且只有一个定义
2、抽象理解
有一天我为了在朋友面前装X就很高调的说自己有一辆价值xxx万的顶级跑车,没过几天自己心仪的女生听到这个消息后就跟我说 :“我也想体验一下坐在顶级跑车里是什么感觉”,我听了以后碍于面子又是自己喜欢的女生所以就忍痛花了几千块钱租了一辆跑车,然后让自己心仪的女生体验了一下坐在超跑的感觉,再然后就没有然后了。。。。。。。
我高调说自己又一辆跑车,但实际上我并没有,这里就相当于声明,只是告诉了其他人我有一辆跑车
自己租了一辆跑车满足心仪女生的要求就相当于定义,因为现在的我是有跑车的,那么跑车充当的角色就是变量
重点来咯重点来咯:声明是描述一个对象,而定义是请求创建一个对象,所有定义也都是声明,但反之则不正确
Tips:这里大家就尽量理解把,这个例子也并不是很恰当,以自己的水平只能这样了,如果跟你理解的定义和声明有出入,请先别急着否定自己,万一是我错了呢!!!
二、作用域
标识符的作用域就是程序中该标识符可以被使用的区域;
当变量在程序的某个部分被声明时,它只有在程序的一定区域才能被访问
1、文件作用域
任何在所有代码块之外声明的标识符都具有文件作用域,它表示这些标识符从他们的声明处开始到源文件结尾处都是可以访问的
#include <stdio.h>
int a;
//具有文件作用域
int main(void)
{
return 0;
}
2、函数作用域
函数作用域只适用于语句标签,语句标签用于goto语句,基本上,函数作用域可以简化为一条规则——一个函数中的所有语句标签必须唯一
#include <stdio.h>
void fun1(void)
{
goto s;
printf("Hello World\n");
}
int main(void)
{
s: printf("hello world\n");
//s 具有函数作用域
return 0;
}
3、原型作用域
原型作用域只适用于在函数原型中声明的参数名,在原型中(与函数定义不同),参数名并非必需。
#include <stdio.h>
void fun(int a);
//这个是函数原型(函数声明),a具有原型作用域,参数名并非必需
int mian(void)
{
fun(123);
return 0;
}
void fun(int a)
{
printf("传递进来的参数值为 %d\n",a);
}
4、代码块作用域
位于一个花括号内的所有语句成为一个代码块,声明于内层代码块的标识符的作用域在到达该代码块的尾部便终止,如果内层代码块有一个标识符与外层代码块的一个标识符重名,则内层的标识符将隐藏外层的标识符,在内层中无法通过名字直接访问外层标识符
#include <stdio.h>
int mian(void)
{
int a = 10;
{
int a = 20;
printf("a = %d\n", a);
}
return 0;
}//结果为20,因为内层的a将外层a隐藏了,在内层中是无法通过名字访问外层a的
三、存储类型
存储类型指声明的变量将被存储到什么地方去,并且与其存储周期有关,就是这个变量何时被创建,何时被销毁,保持多久
存储类型有三种: 静态变量(static
) —> 存储于普通内存、自动变量(auto
) —>== 存储于堆栈==、 寄存器变量(register
) —> 存储于寄存器。
静态变量: 凡是在任何代码块之外声明的变量都存储在静态内存(普通内存),这类变量称之为静态变量。静态变量在程序运行之前创建,在程序的整个执行过程中始终存在。
自动变量: 在代码块内部声明的变量在缺省情况下是自动变量,他们存储在堆栈中。**在程序执行到声明变量的代码块时才被创建,当程序的执行流离开该代码块时,该类型变量自动销毁。**如果声明时加上static关键字,则它的存储类型从自动变为静态。
寄存器变量: 关键字register可以用于自动变量的声明,提示它们应该存储在机器的硬件寄存器中而不是内存中,这类变量称为寄存器变量。被register关键字声明的自动变量斌不是百分百会被存放在寄存器中的,是否放在寄存器中,还要看编译器怎么处理。机器并不向你提供寄存器变量的地址。
重点来咯重点来咯:1)修改变量的存储类型不影响变量作用域、2)静态变量将值初始化为0,自动变量若不初始化则是垃圾
四、链接属性
变量的连接属性决定如何处理不同文件中出现的标识符
1、三种链接属性
external(外部)、internal(内部)、none(无)
1)没有链接属性(noen)的标识符总是被当作独立的个体,也就是说该标识符的多个声明被当作独立不同的个体
2)internal链接属性的标识符在同一个源文件内的所有声明都指向同一个实体,但位于不同源文件的多个声明仍被当作不同的实体
3)external链接属性的标识符不论声明多少次、位于几个源文件都表示同一个实体
Tips:声明并非定义,int a是声明也是定义
2、extern、static关键词
extern、static关键字用于在声明中修改标识符的链接属性。
static只对缺省链接属性为extern的声明才有改变标识符链接属性的效果
代码如下:
#include <stdio.h>
static int a;
//标识符a的默认链接属性为extern,当使用static修饰时,链接属性由extern变static
int main(void)
{
static int b;
//static并不会修改标识符b的链接属性,因为标识符b的默认链接属性不是extern
printf("Hello World!\n");
return 0;
}
extern当用于具有文件作用域的声明时,这个关键字才是可选的。当extern用于标识符的第二次声明时不会改变第一次声明时的链接属性
代码如下:
#include <stdio.h>
static int a = 1;
//既是声明也是定义,且链接属性为static,具有文件作用域
int main(void)
{
int a =2;
//这里的变量a覆盖外面的变量a,不具有文件作用域
{
extern int a;
//由于a并不是第一次声明能,所以使用extern不会改变原有的链接属性
//只有变量具有文件作用域时extern才是可选的
//这里只是声明变量a,告诉编译器变量a的定义在别的地方不在这里
printf("%d\n",a);
//输出结果是1;
//如果没有使用extern,则输出结果为2
}
printf("Hello World!\n");
return 0;
}
代码块外部缺省为extern,并且代码块外部使用extern表示被其它源文件访问,代码块内部使用extern表示访问其它文件的外部变量。
总结
本来是想对extern关键字进行总结的,但是感觉有点跑题了,估计是因为自己第一次写文章,思路不怎么清晰。反正写都写了,就i当做一次笔记的记录吧。如果文中有地方写的不对,还烦请大佬们指出,不要因为我对其理解不到位从而导致误导其他人!!!