1.函数的定义
函数类型 函数名(类型名 形式参数1,类型名 形式参数2 ...)
{
说明部分
语句部分
}
2.在C语言中,规定函数不允许嵌套定义,即在定义一个函数时,不能在该函数体里包含另一个函数的定义。但是可以嵌套调用,即在一个函数的执行过程中可以调用另一个函数。
3.变量的存储类别及生命周期
从变量值生存周期来分,可以将变量分为静态存储变量和动态存储变量。静态存储变量是指程序运行时固定分配存储空间的变量。动态储存变量是在程序运行时根据需要动态分配储存空间的变量。
程序运行时的内存分配有以下5种:系统区、程序代码区、静态数据区、动态数据区、自由空间。全局变量和静态的局部变量存放在静态数据区,在程序开始时给它们分配内存空间,程序执行完毕就释放。在程序执行过程中它们占据固定的存储单元,它们的生命周期贯穿程序的整个过程。
动态数据存放的数据为自动局部变量、形参变量和中断的现场保护的数据。自动局部变量指的是未加static的局部变量,形式参量指的是函数形式参数,中断的现场保护的数据是指在函数调用的现场保护和返回地址。在函数开始调用是分配动态储存空间,函数结束时释放这些空间,他们的生命周期为函数的整个过程。
因此,变量完整的定义方式为:储存类别 数据类型标识符 变量名;
储存类别共有四种:auto——自动变量;static——静态变量;register——寄存器变量;extern——外部变量。
(1).auto变量(自动变量)
当局部变量定义时使用auto标签或没有指定存储类别时,系统就认为所定义的变量是自动变量。系统对自动变量是动态分配储存空间的,数据存储在动态数据区中。局部变量的定义必须放在函数体或者复合体中所有可执行语句之前。自动变量的作用域是从定义的位置起,到函数体或者复合体结束为止。它的存储单元在进入这些局部变量所在的函数或复合体时生成,退出其所在函数体或复合体时消失,这就是自动变量的生存周期。当再次进入函数体时,系统将为他们另行分配存储单元。
(2).register变量(寄存器变量)
寄存器变量也是自动变量,它与自动变量的区别仅在于:用register说明的变量建议编译程序将变量的值保留在CPU的寄存器中,而不像一般变量那样,占用内存单元。局部变量的定义必须放在函数体或者复合体中所有可执行语句前。
说明:
① 只有函数内定义的变量或者形参可以定义为寄存器变量。寄存器变量的值保存在CPU的中。
② 受寄存器长度的限制,寄存器变量只能是char,int和指针类型的变量;对于占用字节数多的变量(long、float、double等)及数组不宜定义为寄存器变量。
③ 由于寄存器变量值保存在CPU的寄存器中,系统从CPU的寄存器中读写变量比内存要快,所以将使用频率比较高的变量设定为寄存器变量。例如for循环中所用到的变量。
④当今的优化编译系统能够识别使用频率较高的变量,从而自动地将这些变量放在寄存器中,因而一般不需要由程序员指定。
注:寄存器是CPU的一部分,寄存器是有限存储容量的高速存储部件,它们可用来暂存指令、地址和数据。
(3).static变量(静态变量)
a.静态局部变量
在函数体或内部使用static说明的变量,称静态全局变量。它分配在内存的静态数据存储区。它的生存期与作用域是全局寿命,局部可见。即只有在编译时可以赋值,以后每次调用时不再分配内存单元和初始化,只是保留上一次函数调用结束的值,直到程序运行结束,对应的内存单元才释放,而其作用域仅仅只限于所定义的函数和复合体。
注:变量没有赋初值时,auto变量是个随机值,static变量是0。
例:
void f1()
{
auto int x = 1;
printf("x=%d",x);
}
void f2()
{
static int x = 1;
x++;
printf("x=%d",x);
}
int main()
{
f1(); f2();
f1(); f2();
}
结果为 x=1 x=2
x=1 x=3
b.静态全局变量
在所有函数(包括主函数)之外的用static说明的变量,称为静态全局变量。它分配在内存的静态数据存储区,它的生存期与作用域是全局寿命,局部可见。即在整个程序运行期间都存在;但它与外部变量(即全局变量)不同,静态全局变量只能在所定义的文件中使用,具有局部可见性(与静态局部变量的局部可见性不同),而外部变量可在其他文件中使用。
(4).extern变量(外部变量)
外部变量(即全局变量)是在所有函数(包括主函数)外部定义的变量,它的作用域为从变量定义处开始,到本程序文件的末尾。如果外部末尾不在文件开头定义,其有效的作用范围只限于定义处到文件终了。如果定义点之前的函数想引用该外部变量,则应该引用之前用关键字extern对该变量作"外部变量声明"。表示该变量是一个已经定义的外部变量。有了此声明,就可以从"声明"处起,合法地使用该外部变量。
4.外部函数和内部函数
a.外部函数
(1).不作任何标示的函数,允许被其他源程序文件中的函数调用;但必须在调用的源文件中做外部函数声明,即在声明时加上extern关键字。
extern 函数类型 函数名(数据类型 形式参数1,数据类型 形式参数2,...)
(2).在定义函数时,在函数的首位加上extern关键字,表示该函数是外部函数,可以被其他的文件调用。
extern 函数类型 函数名(数据类型 形式参数1,数据类型 形式参数2,... )
{
函数体
}
外部函数的调用方式
file1.c file2.c
extern int function1() a = function1();
或
int function1() extern int function1();
a = function1();
b.内部函数
如果在一个源文件中定义的函数只能被本文件中的函数调用,而不能被同一源程序其他文件中的函数调用,这种函数称为内部函数。
内部函数是用static标示的函数,只能被本源程序文件中的函数调用,定义形式为:
static 函数类型 函数名(数据类型 形式参数1,数据类型 形式参数2,... )
{
函数体
}
5.编译预处理
编译预处理对源程序编译之前做一些处理:生成扩展C源程序。
1.编译预处理种类
宏定义 #define
文件包含 #include
条件编译 #if-#else-#endif
2.带参的宏定义
#define POWER(x) x*x
带参宏 | 函数 | |
---|---|---|
处理时间 | 编译时 | 程序运行时 |
参数类型 | 无类型问题 | 定义实参,形参类型 |
处理过程 | 不分配内存 简单的字符置换 |
分配内存先求实参值 再代入形参 |
程序长度 | 变长 | 不变 |
运行速度 | 不占运行时间 | 调用和返回占时间 |
6.注:
① 每个函数都有堆栈区。堆栈区是计算机的内存用来储存函数的变量和参数。
② 递归函数必须定义出口,否则会导致系统死机