第 14 章
BIOS 和硬件的接口。
8) 字符串函数:用于字符串cāo作和处理。
9) 内存管理函数:用于内存管理。
10) 数学函数:用于数学函数计算。
11) 日期和时间函数:用于日期,时间转换cāo作。
12) 进程控制函数:用于进程管理和控制。
13) 其它函数:用于其它各种功能。
以上各类函数不仅数量多,而且有的还需要硬件知识才会使用,因此要想全部掌握则需
要一个较长的学习过程。应首先掌握一些最基本、最常用的函数,再逐步深入。由于课时关
系,我们只介绍了很少一部分库函数,其余部分读者可根据需要查阅有关手册。
还应该指出的是,在C语言中,所有的函数定义,包括主函数 main 在内,都是平行的。
也就是说,在一个函数的函数体内,不能再定义另一个函数,即不能嵌套定义。但是函数之
间允许相互调用,也允许嵌套调用。习惯上把调用者称为主调函数。函数还可以自己调用自
己,称为递归调用。
main 函数是主函数,它可以调用其它函数,而不允许被其它函数调用。因此,C程序
的执行总是从 main 函数开始,完成对其它函数的调用后再返回到 main 函数,最后由 main
函数结束整个程序。一个C源程序必须有,也只能有一个主函数 main。
8.2 函数定义的一般形式
1. 无参函数的定义形式
类型标识符 函数名()
{声明部分
语句
}
其中类型标识符和函数名称为函数头。类型标识符指明了本函数的类型,函数的类型实
际上是函数返回值的类型。 该类型标识符与前面介绍的各种说明符相同。函数名是由用户
定义的标识符,函数名后有一个空括号,其中无参数,但括号不可少。
{}中的内容称为函数体。在函数体中声明部分,是对函数体内部所用到的变量的类型说
明。
在很多情况下都不要求无参函数有返回值,此时函数类型符可以写为 void。
我们可以改写一个函数定义:
void Hello()
{
printf ("Hello,world \n");
}
这里,只把 main 改为 Hello 作为函数名,其余不变。Hello 函数是一个无参函数,当
被其它函数调用时,输出 Hello world 字符串。
2. 有参函数定义的一般形式
谭浩强 C 语言程序设计 2001 年 5 月 1 日
类型标识符 函数名(形式参数表列)
{声明部分
语句
}
有参函数比无参函数多了一个内容,即形式参数表列。在形参表中给出的参数称为形式
参数,它们可以是各种类型的变量,各参数之间用逗号间隔。在进行函数调用时,主调函数
将赋予这些形式参数实际的值。形参既然是变量,必须在形参表中给出形参的类型说明。
例如,定义一个函数,用于求两个数中的大数,可写为:
int max(int a, int b)
{
if (a>b) return a;
else return b;
}
第一行说明 max 函数是一个整型函数,其返回的函数值是一个整数。形参为 a,b,均为
整型量。a,b 的具体值是由主调函数在调用时传送过来的。在{}中的函数体内,除形参外没
有使用其它变量,因此只有语句而没有声明部分。在 max 函数体中的 return 语句是把 a(或
b)的值作为函数的值返回给主调函数。有返回值函数中至少应有一个 return 语句。
在C程序中,一个函数的定义可以放在任意位置,既可放在主函数 main 之前,也可放
在 main 之后。
例如:
可把 max 函数置在 main 之后,也可以把它放在 main 之前。修改后的程序如下所示。
【例 8.1】
int max(int a,int b)
{
if(a>b)return a;
else return b;
}
main()
{
int max(int a,int b);
int x,y,z;
printf("input two numbers:\n");
scanf("%d%d",&x,&y);
z=max(x,y);
printf("maxmum=%d",z);
}
现在我们可以从函数定义、函数说明及函数调用的角度来分析整个程序,从中进一步了
解函数的各种特点。
程序的第 1 行至第 5 行为 max 函数定义。进入主函数后,因为准备调用 max 函数,故先
对 max 函数进行说明(程序第 8 行)。函数定义和函数说明并不是一回事,在后面还要专门讨
论。 可以看出函数说明与函数定义中的函数头部分相同,但是末尾要加分号。程序第 12 行
为调用 max 函数,并把 x, y 中的值传送给 max 的形参 a, b。max 函数执行的结果(a 或 b)
谭浩强 C 语言程序设计 2001 年 5 月 1 日
将返回给变量 z。最后由主函数输出 z 的值。
8.3 函数的参数和函数的值
8.3.1 形式参数和实际参数
前面已经介绍过,函数的参数分为形参和实参两种。在本小节中,进一步介绍形参、实
参的特点和两者的关系。形参出现在函数定义中,在整个函数体内都可以使用,离开该函数
则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。形参和实参
的功能是作数据传送。发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实
现主调函数向被调函数的数据传送。
函数的形参和实参具有以下特点:
1. 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。
因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变
量。
2. 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用
时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等
办法使实参获得确定值。
3. 实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配”的错误。
4. 函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的
值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不
会变化。
【例 8.2】可以说明这个问题。
main()
{
int n;
printf("input number\n");
scanf("%d",&n);
s(n);
printf("n=%d\n",n);
}
int s(int n)
{
int i;
for(i=n-1;i>=1;i--)
n=n+i;
printf("n=%d\n",n);
}
谭浩强 C 语言程序设计 2001 年 5 月 1 日
本程序中定义了一个函数s,该函数的功能是求∑ni的值。在主函数中输入n值,并作
为实参,在调用时传送给s 函数的形参量n( 注意,本例的形参变量和实参变量的标识符都
为n,但这是两个不同的量,各自的作用域不同)。在主函数中用printf 语句输出一次n值,
这个n值是实参n的值。在函数s中也用printf 语句输出了一次n值,这个n值是形参最后取得
的n值 0。从运行情况看,输入n值为 100。即实参n的值为 100。把此值传给函数s时,形参n
的初值也为 100,在执行函数过程中,形参n的值变为 5050。返回主函数之后,输出实参n
的值仍为 100。可见实参的值不随形参的变化而变化。
8.3.2 函数的返回值
函数的值是指函数被调用之后,执行函数体中的程序段所取得的并返回给主调函数的
值。如调用正弦函数取得正弦值,调用例 8.1 的 max 函数取得的最大数等。对函数的值(或
称函数返回值)有以下一些说明:
1) 函数的值只能通过 return 语句返回主调函数。
return 语句的一般形式为:
return 表达式;
或者为:
return (表达式);
该语句的功能是计算表达式的值,并返回给主调函数。在函数中允许有多个 return
语句,但每次调用只能有一个 return 语句被执行,因此只能返回一个函数值。
2) 函数值的类型和函数定义中函数的类型应保持一致。如果两者不一致,则以函数类
型为准,自动进行类型转换。
3) 如函数值为整型,在函数定义时可以省去类型说明。
4) 不返回函数值的函数,可以明确定义为“空类型”,类型说明符为“void”。如例
8.2 中函数 s 并不向主函数返函数值,因此可定义为:
void s(int n)
{ ……
}
一旦函数被定义为空类型后,就不能在主调函数中使用被调函数的函数值了。
例如,在定义 s 为空类型后,在主函数中写下述语句
sum=s(n);
就是错误的。
为了使程序有良好的可读xìng并减少出错, 凡不要求返回值的函数都应定义为
空类型。
8.4 函数的调用
谭浩强 C 语言程序设计 2001 年 5 月 1 日
8.4.1 函数调用的一般形式
前面已经说过,在程序中是通过对函数的调用来执行函数体的,其过程与其它语言的子
程序调用相似。
C语言中,函数调用的一般形式为:
函数名(实际参数表)
对无参函数调用时则无实际参数表。实际参数表中的参数可以是常数,变量或其它构造
类型数据及表达式。各实参之间用逗号分隔。
8.4.2 函数调用的方式
在C语言中,可以用以下几种方式调用函数:
1. 函数表达式:函数作为表达式中的一项出现在表达式中,以函数返回值参与表达式的运
算。这种方式要求函数是有返回值的。例如:z=max(x,y)是一个赋值表达式,把 max
的返回值赋予变量 z。
2. 函 数 语 句 : 函 数 调 用 的 一 般 形 式 加 上 分 号 即 构 成 函 数 语 句 。 例 如 : printf
("%d",a);scanf ("%d",&b);都是以函数语句的方式调用函数。
3. 函数实参:函数作为另一个函数调用的实际参数出现。这种情况是把该函数的返回值作
为 实 参 进 行 传 送 , 因 此 要 求 该 函 数 必 须 是 有 返 回 值 的 。 例 如 :
printf("%d",max(x,y)); 即是把 max 调用的返回值又作为 printf 函数的实参来使
用的。在函数调用中还应该注意的一个问题是求值顺序的问题。所谓求值顺序是指对实
参表中各量是自左至右使用呢,还是自右至左使用。对此,各系统的规定不一定相同。
介绍 printf 函数时已提到过,这里从函数调用的角度再强调一下。
【例 8.3】
main()
{
int i=8;
printf("%d\n%d\n%d\n%d\n",++i,--i,i++,i--);
}
如按照从右至左的顺序求值。运行结果应为:
8
7
7
8
如对 printf 语句中的++i,--i,i++,i--从左至右求值,结果应为:
9
8
8
9
谭浩强 C 语言程序设计 2001 年 5 月 1 日
应特别注意的是,无论是从左至右求值, 还是自右至左求值,其输出顺序都是不变的,
即输出顺序总是和实参表中实参的顺序相同。由于 Turbo C 现定是自右至左求值,所以结果
为 8,7,7,8。上述问题如还不理解,上机一试就明白了。
8.4.3 被调用函数的声明和函数原型
在主调函数中调用某函数之前应对该被调函数进行说明(声明),这与使用变量之前要
先进行变量说明是一样的。在主调函数中对被调函数作说明的目的是使编译系统知道被调函
数返回值的类型,以便在主调函数中按此种类型对返回值作相应的处理。
其一般形式为:
类型说明符 被调函数名(类型 形参,类型 形参…);
或为:
类型说明符 被调函数名(类型,类型…);
括号内给出了形参的类型和形参名,或只给出形参类型。这便于编译系统进行检错,以
防止可能出现的错误。
例 8.1 main 函数中对 max 函数的说明为:
int max(int a,int b);
或写为:
int max(int,int);
C语言中又规定在以下几种情况时可以省去主调函数中对被调函数的函数说明。
1) 如果被调函数的返回值是整型或字符型时,可以不对被调函数作说明,而直接调用。
这时系统将自动对被调函数返回值按整型处理。例 8.2 的主函数中未对函数 s 作说
明而直接调用即属此种情形。
2) 当被调函数的函数定义出现在主调函数之前时,在主调函数中也可以不对被调函数
再作说明而直接调用。例如例 8.1 中,函数 max 的定义放在 main 函数之前,因此
可在 main 函数中省去对 max 函数的函数说明 int max(int a,int b)。
3) 如在所有函数定义之前,在函数外预先说明了各个函数的类型,则在以后的各主调
函数中,可不再对被调函数作说明。例如:
char str(int a);
float f(float b);
main()
{
……
}
char str(int a)
{
……
}
float f(float b)
{
……
}
其中第一,二行对 str 函数和 f 函数预先作了说明。因此在以后各函数中无须对
谭浩强 C 语言程序设计 2001 年 5 月 1 日
str 和 f 函数再作说明就可直接调用。
4) 对库函数的调用不需要再作说明,但必须把该函数的头文件用 include 命令包含在
源文件前部。
8.5 函数的嵌套调用
C语言中不允许作嵌套的函数定义。因此各函数之间是平行的,不存在上一级函数和下
一级函数的问题。但是C语言允许在一个函数的定义中出现对另一个函数的调用。这样就出
现了函数的嵌
松语文学免费小说阅读_www.16sy.com
8) 字符串函数:用于字符串cāo作和处理。
9) 内存管理函数:用于内存管理。
10) 数学函数:用于数学函数计算。
11) 日期和时间函数:用于日期,时间转换cāo作。
12) 进程控制函数:用于进程管理和控制。
13) 其它函数:用于其它各种功能。
以上各类函数不仅数量多,而且有的还需要硬件知识才会使用,因此要想全部掌握则需
要一个较长的学习过程。应首先掌握一些最基本、最常用的函数,再逐步深入。由于课时关
系,我们只介绍了很少一部分库函数,其余部分读者可根据需要查阅有关手册。
还应该指出的是,在C语言中,所有的函数定义,包括主函数 main 在内,都是平行的。
也就是说,在一个函数的函数体内,不能再定义另一个函数,即不能嵌套定义。但是函数之
间允许相互调用,也允许嵌套调用。习惯上把调用者称为主调函数。函数还可以自己调用自
己,称为递归调用。
main 函数是主函数,它可以调用其它函数,而不允许被其它函数调用。因此,C程序
的执行总是从 main 函数开始,完成对其它函数的调用后再返回到 main 函数,最后由 main
函数结束整个程序。一个C源程序必须有,也只能有一个主函数 main。
8.2 函数定义的一般形式
1. 无参函数的定义形式
类型标识符 函数名()
{声明部分
语句
}
其中类型标识符和函数名称为函数头。类型标识符指明了本函数的类型,函数的类型实
际上是函数返回值的类型。 该类型标识符与前面介绍的各种说明符相同。函数名是由用户
定义的标识符,函数名后有一个空括号,其中无参数,但括号不可少。
{}中的内容称为函数体。在函数体中声明部分,是对函数体内部所用到的变量的类型说
明。
在很多情况下都不要求无参函数有返回值,此时函数类型符可以写为 void。
我们可以改写一个函数定义:
void Hello()
{
printf ("Hello,world \n");
}
这里,只把 main 改为 Hello 作为函数名,其余不变。Hello 函数是一个无参函数,当
被其它函数调用时,输出 Hello world 字符串。
2. 有参函数定义的一般形式
谭浩强 C 语言程序设计 2001 年 5 月 1 日
类型标识符 函数名(形式参数表列)
{声明部分
语句
}
有参函数比无参函数多了一个内容,即形式参数表列。在形参表中给出的参数称为形式
参数,它们可以是各种类型的变量,各参数之间用逗号间隔。在进行函数调用时,主调函数
将赋予这些形式参数实际的值。形参既然是变量,必须在形参表中给出形参的类型说明。
例如,定义一个函数,用于求两个数中的大数,可写为:
int max(int a, int b)
{
if (a>b) return a;
else return b;
}
第一行说明 max 函数是一个整型函数,其返回的函数值是一个整数。形参为 a,b,均为
整型量。a,b 的具体值是由主调函数在调用时传送过来的。在{}中的函数体内,除形参外没
有使用其它变量,因此只有语句而没有声明部分。在 max 函数体中的 return 语句是把 a(或
b)的值作为函数的值返回给主调函数。有返回值函数中至少应有一个 return 语句。
在C程序中,一个函数的定义可以放在任意位置,既可放在主函数 main 之前,也可放
在 main 之后。
例如:
可把 max 函数置在 main 之后,也可以把它放在 main 之前。修改后的程序如下所示。
【例 8.1】
int max(int a,int b)
{
if(a>b)return a;
else return b;
}
main()
{
int max(int a,int b);
int x,y,z;
printf("input two numbers:\n");
scanf("%d%d",&x,&y);
z=max(x,y);
printf("maxmum=%d",z);
}
现在我们可以从函数定义、函数说明及函数调用的角度来分析整个程序,从中进一步了
解函数的各种特点。
程序的第 1 行至第 5 行为 max 函数定义。进入主函数后,因为准备调用 max 函数,故先
对 max 函数进行说明(程序第 8 行)。函数定义和函数说明并不是一回事,在后面还要专门讨
论。 可以看出函数说明与函数定义中的函数头部分相同,但是末尾要加分号。程序第 12 行
为调用 max 函数,并把 x, y 中的值传送给 max 的形参 a, b。max 函数执行的结果(a 或 b)
谭浩强 C 语言程序设计 2001 年 5 月 1 日
将返回给变量 z。最后由主函数输出 z 的值。
8.3 函数的参数和函数的值
8.3.1 形式参数和实际参数
前面已经介绍过,函数的参数分为形参和实参两种。在本小节中,进一步介绍形参、实
参的特点和两者的关系。形参出现在函数定义中,在整个函数体内都可以使用,离开该函数
则不能使用。实参出现在主调函数中,进入被调函数后,实参变量也不能使用。形参和实参
的功能是作数据传送。发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实
现主调函数向被调函数的数据传送。
函数的形参和实参具有以下特点:
1. 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。
因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变
量。
2. 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用
时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等
办法使实参获得确定值。
3. 实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配”的错误。
4. 函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的
值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不
会变化。
【例 8.2】可以说明这个问题。
main()
{
int n;
printf("input number\n");
scanf("%d",&n);
s(n);
printf("n=%d\n",n);
}
int s(int n)
{
int i;
for(i=n-1;i>=1;i--)
n=n+i;
printf("n=%d\n",n);
}
谭浩强 C 语言程序设计 2001 年 5 月 1 日
本程序中定义了一个函数s,该函数的功能是求∑ni的值。在主函数中输入n值,并作
为实参,在调用时传送给s 函数的形参量n( 注意,本例的形参变量和实参变量的标识符都
为n,但这是两个不同的量,各自的作用域不同)。在主函数中用printf 语句输出一次n值,
这个n值是实参n的值。在函数s中也用printf 语句输出了一次n值,这个n值是形参最后取得
的n值 0。从运行情况看,输入n值为 100。即实参n的值为 100。把此值传给函数s时,形参n
的初值也为 100,在执行函数过程中,形参n的值变为 5050。返回主函数之后,输出实参n
的值仍为 100。可见实参的值不随形参的变化而变化。
8.3.2 函数的返回值
函数的值是指函数被调用之后,执行函数体中的程序段所取得的并返回给主调函数的
值。如调用正弦函数取得正弦值,调用例 8.1 的 max 函数取得的最大数等。对函数的值(或
称函数返回值)有以下一些说明:
1) 函数的值只能通过 return 语句返回主调函数。
return 语句的一般形式为:
return 表达式;
或者为:
return (表达式);
该语句的功能是计算表达式的值,并返回给主调函数。在函数中允许有多个 return
语句,但每次调用只能有一个 return 语句被执行,因此只能返回一个函数值。
2) 函数值的类型和函数定义中函数的类型应保持一致。如果两者不一致,则以函数类
型为准,自动进行类型转换。
3) 如函数值为整型,在函数定义时可以省去类型说明。
4) 不返回函数值的函数,可以明确定义为“空类型”,类型说明符为“void”。如例
8.2 中函数 s 并不向主函数返函数值,因此可定义为:
void s(int n)
{ ……
}
一旦函数被定义为空类型后,就不能在主调函数中使用被调函数的函数值了。
例如,在定义 s 为空类型后,在主函数中写下述语句
sum=s(n);
就是错误的。
为了使程序有良好的可读xìng并减少出错, 凡不要求返回值的函数都应定义为
空类型。
8.4 函数的调用
谭浩强 C 语言程序设计 2001 年 5 月 1 日
8.4.1 函数调用的一般形式
前面已经说过,在程序中是通过对函数的调用来执行函数体的,其过程与其它语言的子
程序调用相似。
C语言中,函数调用的一般形式为:
函数名(实际参数表)
对无参函数调用时则无实际参数表。实际参数表中的参数可以是常数,变量或其它构造
类型数据及表达式。各实参之间用逗号分隔。
8.4.2 函数调用的方式
在C语言中,可以用以下几种方式调用函数:
1. 函数表达式:函数作为表达式中的一项出现在表达式中,以函数返回值参与表达式的运
算。这种方式要求函数是有返回值的。例如:z=max(x,y)是一个赋值表达式,把 max
的返回值赋予变量 z。
2. 函 数 语 句 : 函 数 调 用 的 一 般 形 式 加 上 分 号 即 构 成 函 数 语 句 。 例 如 : printf
("%d",a);scanf ("%d",&b);都是以函数语句的方式调用函数。
3. 函数实参:函数作为另一个函数调用的实际参数出现。这种情况是把该函数的返回值作
为 实 参 进 行 传 送 , 因 此 要 求 该 函 数 必 须 是 有 返 回 值 的 。 例 如 :
printf("%d",max(x,y)); 即是把 max 调用的返回值又作为 printf 函数的实参来使
用的。在函数调用中还应该注意的一个问题是求值顺序的问题。所谓求值顺序是指对实
参表中各量是自左至右使用呢,还是自右至左使用。对此,各系统的规定不一定相同。
介绍 printf 函数时已提到过,这里从函数调用的角度再强调一下。
【例 8.3】
main()
{
int i=8;
printf("%d\n%d\n%d\n%d\n",++i,--i,i++,i--);
}
如按照从右至左的顺序求值。运行结果应为:
8
7
7
8
如对 printf 语句中的++i,--i,i++,i--从左至右求值,结果应为:
9
8
8
9
谭浩强 C 语言程序设计 2001 年 5 月 1 日
应特别注意的是,无论是从左至右求值, 还是自右至左求值,其输出顺序都是不变的,
即输出顺序总是和实参表中实参的顺序相同。由于 Turbo C 现定是自右至左求值,所以结果
为 8,7,7,8。上述问题如还不理解,上机一试就明白了。
8.4.3 被调用函数的声明和函数原型
在主调函数中调用某函数之前应对该被调函数进行说明(声明),这与使用变量之前要
先进行变量说明是一样的。在主调函数中对被调函数作说明的目的是使编译系统知道被调函
数返回值的类型,以便在主调函数中按此种类型对返回值作相应的处理。
其一般形式为:
类型说明符 被调函数名(类型 形参,类型 形参…);
或为:
类型说明符 被调函数名(类型,类型…);
括号内给出了形参的类型和形参名,或只给出形参类型。这便于编译系统进行检错,以
防止可能出现的错误。
例 8.1 main 函数中对 max 函数的说明为:
int max(int a,int b);
或写为:
int max(int,int);
C语言中又规定在以下几种情况时可以省去主调函数中对被调函数的函数说明。
1) 如果被调函数的返回值是整型或字符型时,可以不对被调函数作说明,而直接调用。
这时系统将自动对被调函数返回值按整型处理。例 8.2 的主函数中未对函数 s 作说
明而直接调用即属此种情形。
2) 当被调函数的函数定义出现在主调函数之前时,在主调函数中也可以不对被调函数
再作说明而直接调用。例如例 8.1 中,函数 max 的定义放在 main 函数之前,因此
可在 main 函数中省去对 max 函数的函数说明 int max(int a,int b)。
3) 如在所有函数定义之前,在函数外预先说明了各个函数的类型,则在以后的各主调
函数中,可不再对被调函数作说明。例如:
char str(int a);
float f(float b);
main()
{
……
}
char str(int a)
{
……
}
float f(float b)
{
……
}
其中第一,二行对 str 函数和 f 函数预先作了说明。因此在以后各函数中无须对
谭浩强 C 语言程序设计 2001 年 5 月 1 日
str 和 f 函数再作说明就可直接调用。
4) 对库函数的调用不需要再作说明,但必须把该函数的头文件用 include 命令包含在
源文件前部。
8.5 函数的嵌套调用
C语言中不允许作嵌套的函数定义。因此各函数之间是平行的,不存在上一级函数和下
一级函数的问题。但是C语言允许在一个函数的定义中出现对另一个函数的调用。这样就出
现了函数的嵌
松语文学免费小说阅读_www.16sy.com