程序员可以通过C的内存管理系统指定变量的作用域和声明周期,实现对程序的控制。
合理使用内存存储数据是程序设计的一个要点
关键概念:
对象可以存储一个或多个值。
一个对象可能并未储存实际的值,但是它在储存适当的值时一定具有相应的大小
说明:
作用域描述程序中可访问标识符的区域。一个C变量的作用域可以是块作用域、函数作用域、函数原型作用域或文件作用域
块是用一对花括号括起来的代码区域
定义在块中的变量具有块作用域(block scope)
块作用域的可见范围是从定义处到包含该定义的块的末尾。
虽然函数的形参,声明在函数的左花括号之前,但是它们也具有块作用域,属于函数体这个块
声明在内层块中的变量,其作用域仅局限于该声明所在的块
函数原型作用域用于函数原型中的形参名(变量名)
函数原型作用域的范围是从形参定义处到原型声明结束
意味着,编译器在处理函数原型中的形参时只关心其类型,而形参名无关紧要。即使有形参名,也不必于函数定义中的形参名相匹配
注意:
void use_a_VLA(int n,int m, arr[n][m]);
上述代码方括号中必须使用在函数原型中已声明的名称
定义在函数外名的变量具有文件作用域
通常源代码(.c文件)中包好一个或多个头文件(.h扩展名)。头文件会一次包含其它文件,所以包含多个单独的物理文件。但是C预处理实际上用包含的头文件替换#include指令。所以编译器源代码文件和所有的头文件都看成是一个包含信息的单独文件。这个文件被称为翻译单元(translation unit)
描述一个具有文件作用域的变量时,它的实际可见范围是整个翻译单元。
C变量有3种链接属性:外部链接、内部链接或无链接
具有块作用域、函数作用域或函数原型作用域的变量都是无链接变量
具有文件作用域的变量可以是外部链接或内部链接。
外部链接变量可以在多个文件程序中使用,内部链接变量只能在一个翻译单元中使用
内部链接的文件作用域 简称文件作用域
外部链接的文件作用域 简称全局作用域或程序作用域
区分文件作用域是内部链接还是外部链接的方式:----static
int giants=5; //文件作用域,外部链接
static int dodgers=3; //文件作用域,内部链接
程序说明:
giants 变量可以在多个翻译单元中使用,而dodgers变量只能在本翻译单元中使用
作用域和链接描述了标识符的可见性。
存储期描述了通过通过这些标识符的对象的生存期
C语言有四种存储期:
静态存储期、线程存储期、自动存储期、动态分配存储期
如果对象具有静态存储期,那么他在程序的执行期间一直存在。
文件作用域变量具有静态存储期
块作用域通常具有自动存储期。当程序进入定义这些变量的块时,为这些变量分配内存;当退出这些块时,释放刚才为变量分配的内存。
对于定义在块作用域的变长数组,他们的存储期从声明处到块的末尾,而不是块
的开始到块的末尾
块作用域也可以具有静态存储期,其实现方式如下(static)
void more( int number)
{
int index;
static int ct=0; //声明一个具有静态存储期的变量
}
1.在块内部定义的静态变量,只有程序其所在函数时才能访问,但是函数可以通过提供该存储区地址的方式使其它函数间接访问该对象
2. 不能给函数形参声明静态变量
3. 静态变量(static variable)中静态的意思是该变量在内存中原地不动
动态分配存储期的内容在后文论述
具有自动存储类别的变量具有自动存储其、块作用域且无连接
关键字auto
用来显示的声明某个变量为自动变量,声明方式如下:
int main()
{
auto int plox;
}
auto关键字属于存储类别说明符(storage-class specifier)
auto在C++中的作用是申请内存,因此为了程序兼容性,组好减少使用auto定义自动变量
说明:
显示的声明也给自动变量的方式:
int main()
{
int tents=5; //显示声明方式1
int ruth=3;
int rance=5*ruth; //显示声明方式2
}
通过程序将变量存储在寄存器中,使用关键字register
,实现方式如下:
int macho(register int n)
{
register int quick;
}
上述程序声明了两个寄存器变量,一个是形参n,另一个是int型变量quick
说明:
register
关键字更像是一种请求,即实际程序执行过程中会根据需求确定是否最终分配在寄存器中外部链接的静态变量具有文件作用域、外部链接和静态存储期。
属于该类别的变量称为外部变量
关键字extern
的作用是指出某函数使用了外部变量
说明:
extern
关键字int all=5;
int main()
{
extern int all;//表示对全局变量all的使用
int all=4;//表示定义一个自动变量all,全局变量all将被屏蔽
}
第一次声明被称为定义式声明(defining declaraton)
第二次声明被称为引用式声明(referencing declaration)
关键字extern
表明该声明不是定义,因为它指示编译器去别处查询其定义
该存储类别的变量具有静态存储期、文件作用域和内部链接。
其声明方式如下:
static int svil=1; //静态变量,内部链接
int main()
{
}
该变量与外部链接的静态变量在作用范围上只能作用在同一个翻译单元,
而外部链接的静态变量可以在多个翻译单元使用
只有当程序由多个翻译单元组成时,才体现区别内部链接和外部连接的重要性
C通过在一个文件中进行定义式声明,然后在其它文件中进行引用式声明来实现共享
如果外部变量定义在一个文件中,其它文件的函数要使用必须用
external
关键字进行声明
extern
由于涉及到多文件操作,在VS中进行多文件的设计步骤是:
#include
对头文件进行引用题目:计算一个数的累加结果,要求每次输入都显示第几次执行,输出当前数的累加结果和所有数的累加结果。并用本博文所用知识实现
程序设计
- 设置全局变量统计执行次数
- 设置全局变量实现历史结果求和
- 设置局部静态变量进行单次结果累加
程序代码
bt1.h 文件
#pragma once
#include
void accumulate(int k);
bt1.c文件
#include
extern int count; //引用式声明,外部链接
static int total = 0; //静态定义,内部链接
void accumulate(int k)
{
static int subtotal = 0; //静态 无连接
if (k <= 0)
{
printf("loop cycle: %d\n", count);
printf("subtotal: %d total: %d\n", subtotal, total);
subtotal = 0;
}
else
{
subtotal += k;
total += k;
}
}
main.c函数文件
#include
#include"bt1.h"
void report_count();
void accumulate(int k);
int count = 0; // file scope external link
int main()
{
int value; //auto variable
register int i;// register variable
printf("enter a positive integer(0 to quit):");
while (scanf("%d", &value) == 1 && value > 0)
{
++count; //use file cope virable
for (i = value; i >= 0; i--)
{
accumulate(i);
}
printf("enter a positive integer(0 to quit):");
}
report_count();
getchar();
getchar();
return 0;
}
void report_count()
{
printf("Loop executed %d times\n", count);
}