函数的分类:
- 从定义角度分:
- 库函数:随C语言编译器提供的。无须用户定义,只需在程序前包含含有该函数原型的头文件。
- 自定义函数:用户自己定义的函数。
- 从函数返回结果角度分:
- 有返回值函数:函数在执行完需要返回一个值,这个值就是函数的值。
- 无返回值函数:函数只执行任务,不返回任何值。用户在定义时可指定此类函数的返回值 为“空类型”,即void。
- 从函数调用时的数据传递角度分:
- 有参函数:主调函数和被调函数之间有数据的传递。
- 无参函数:主调函数和被调函数之间不进行数据传递。无参函数通常用来执行指定操作。
每个程序有且只有一个main函数。main函数可以调用其它函数,但main函数是不能被调用的。
1 函数的定义与声明
一般形式:
返回值类型 函数名(参数列表)
{
函数体
}
例子:
#include <stdio.h>
void iCompare(int Num1, int Num2);
int Add(int Num1, int Num2)
{
int sum;
sum = Num1 + Num2;
return sum;
}
main()
{
int a, b, sum;
a = 10;
b = 20;
sum = Add(a, b);
printf("%d + %d = %d\n", a, b, sum);
iCompare(a, b);
}
void iCompare(int Num1, int Num2)
{
if (Num1 > Num2)
printf("%d > %d\n", Num1, Num2);
else if (Num1 == Num2)
printf("%d = %d\n", Num1, Num2);
else
printf("%d < %d\n", Num1, Num2);
}
运行结果:
- 无参函数没有参数列表;
- 若自定义函数在调用函数之后定义,需要先进行声明才可使用。上例中,iCompare函数被定义在main函数之后,因此在程序开头的第2行进行了声明:void iCompare(int Num1, int Num2);
- 若自定义函数在调用函数之前定义,无须进行声明。
- 函数的定义是互相平行且独立的,所以不可以在函数中嵌套定义另一个函数,即使是在main函数中也不可以。
声明一个函数:
- 函数的声明格式必须与该函数定义的函数头保持一致。
- 必须以分号";"作为语句的结尾。
定义与声明的区别:
- 定义:是在编译器里创建一个对象,为这个对象分配一块内存,并给对象取一个名字,取的名字就是变量名或对象名。这里为对象分配内存。
- 声明:告诉编译器这个名字已经分配到一块内存了,并且这个名字现在归此声明所用,别的地方不允许再使用这个名字。这里没有为对象分配内存。
2 函数的参数
- 定义或声明函数时,函数参数为形式参数,即形参;
- 调用函数时,函数参数为实际参数,即实参。实参可以是常量、变量、表达式和函数等。
数组也可作为函数参数:
- 可使用数组元素作为函数参数;
- 可使用数组名作为函数。
例子:
#include <stdio.h>
void ShowArrayMember(int iMember);
void ShowArray(int iArray[]);
void EvaluateArray(int iArray[10]);
main()
{
int iArray[10] = { 1,2,3,4,5 };
ShowArray(iArray);
EvaluateArray(iArray);
ShowArray(iArray);
for (int i = 0; i < 10; i++)
ShowArrayMember(iArray[i]);
}
void ShowArrayMember(int iMember)
{
printf("Current array member is: %d\n", iMember);
}
void ShowArray(int iArray[])
{
printf("Current array members are:\n");
for (int i = 0; i < 10; i++)
printf("%d ", iArray[i]);
printf("\n");
}
void EvaluateArray(int iArray[10])
{
printf("Evaluate array...\n");
for (int i = 0; i < 10; i++)
iArray[i] = iArray[i] + 10*i;
}
运行结果:
3 变量与变量的存储
3.1 局部变量与全局变量
变量类型 | 说 明 |
---|---|
局部变量 | 在函数内部定义的变量。无法被别的函数使用。 |
全局变量 | 在所有函数外部定义的变量。属于整个源文件,可以在程序中的任何位置进行访问。如果外部文件要进行调用,需要使用extern进行引用。 |
3.2 变量的存储
变量的存储类别有两种形式:静态存储和动态存储。可以通过存储类修饰符来告诉编译器要处理什么样的类型变量,具体有:自动(auto),静态(static),寄存器(register),外部(extern)。
3.2.1 静态存储与动态存储
从变量的产生时间上可以分为静态存储和动态存储。静态存储是指程序运行时分配固定的存储方式;动态存储是在程序运行期间根据需要进行动态的分配存储空间。
内存中,系统提供给用户的存储空间分为三部分:程序区,静态存储区,动态存储区。程序区用来存放用户要执行的程序段,数据分别放在静态存储区和动态存储区中。
- 静态存储区:储存全局变量。全局变量从程序执行时开始分配存储单元,占据固定的内存空间,直到程序终止时,才释放其所占的存储单元。
- 动态存储区:在调用函数时,其局部变量也被保存到动态存储区中,分配内存空间,当函数结束执行,返回到主调函数时,,该变量所占用的空间将被释放,此时局部变量也将消失。对于形参函数,只有在调用该函数时才能为形参分配内存空间,调用完成后会将所有的空间释放。
3.2.2 auto变量
函数内凡未加存储类型说明的变量均视为自动变量,也就是说自动变量可以省略说明符auto。所以,以下两种变量定义是等价的:
{
int a, b;
...
}
{
auto int a, b;
...
}
自动变量属于动态存储方式。
3.2.3 static变量
3.2.3.1 静态局部变量
- 在函数内定义,属于静态存储类别。它的生存期是整个源程序。
- 静态局部变量的作用域与自动变量相同,即只能在定义该变量的函数内使用该变量。退出该函数后,虽然该变量还存在,但不能使用它,如果再次调用定义它的函数,又可继续使用。
- 对于基本类型的静态局部变量,如果在说明时没有赋以初值,则系统自动赋予0值。而对于自动变量,如果不赋初值,那么它的值是不确定的。
例子:
#include <stdio.h>
int AddStatic(int x)
{
static int i = 0;
i += x;
return i;
}
int AddAuto(int x)
{
int i = 0;
i += x;
return i;
}
main()
{
int i, StaticSum, AutoSum;
for (int i = 1; i < 10; i++)
{
StaticSum = AddStatic(i);
AutoSum = AddAuto(i);
printf("%d: StaticSum = %d, AutoSum = %d\n", i, StaticSum, AutoSum);
}
}
运行结果:
3.2.3.2 静态全局变量
非静态全局变量与静态全局变量在存储方式上是相同的,但作用域是不同的。非静态全局变量的作用域是整个源程序,而静态全局变量的作用域是该变量的源文件,在同一源程序的其它源文件中不能使用它。
3.2.4 register变量
寄存器变量允许将局部变量的值存放在CPU中的寄存器中,使用时不需要访问内存,而直接从寄存器中读写。寄存器变量的说明符是register。
- 用户无法获得寄存器变量的地址。
- 如果想要有效地利用register关键字,必须像汇编语言程序员那样了解处理器的内部结构,知道可用于存放变量的寄存器的数量、种类和工作方式。对于这些细节,不同计算机可能是不同的。因此,对于一个要具备可移植性的程序来说,register的作用是不大的。
3.2.5 extern变量
当一个源文件中的函数想引用其它源文件中的变量,就可以用extern来声明外部变量。声明格式:
extern 数据类型 外部变量表;
- 在函数内的extern变量声明,表示引用本源文件中的外部变量;
- 在函数外的extern变量声明(通常在文件开头),表示引用其它文件中的外部变量。
如果外部变量不在文件的开头定义,其有效的作用范围只限于定义到文件结束处。
4 内部函数与外部函数
函数是C语言程序中的最小单位,通常把一个或多个函数保存为一个文件,这个文件称为源文件。定义一个函数,这个函数就要被另外的函数所调用。但当一个源程序由多个源文件组成时,可以指定函数不能被其它文件调用。
函数类型 | 说 明 |
---|---|
内部函数 | 又称为静态函数。只能被所在的源文件所使用,不能被其它文件调用。 定义时,只需在函数返回值类型前加上关键字static即可,格式如下:
好处:不同的开发者可以分别编写不同的函数,而不必担心所使用的函数是否会与其它源文件中的函数同名。 |
外部函数 | 外部函数是可以被其它源文件调用的函数。 定义时,使用关键字extern进行修饰,extern关键字可以省略; 使用时,需要先用关键字extern声明所用的函数是外部函数。 |