| 1 复习函数函数(function)是完成特定任务的独立程序代码单元。首先,使用函数可以省去编写重复代码的苦差。其次,即使程序只完成某项任务一次,也值得使用函数。因为函数让程序更加模块化,从而提高了程序代码的可读性,更方便后期修改、完善。 1.1 创建并使用简单函数这里我们创建一个在一行打印40个星号的函数,并在一个打印表头的程序中使用该函数。如程序清单9.1所示,该程序由mian和startbar组成。 
#include <stdio.h>
#define NAME "GIGATHINK, INC."
#define ADDRESS "101 Megabuck Plaza"
#define PLACE "Megapolis, CA 94904"
#define WIDTH 40
void starbar(void); 
int main(void){
 	starbar();
 	printf("%s\n", NAME);
 	printf("%s\n", ADDRESS);
 	printf("%s\n", PLACE);
 	starbar(); 
 	return 0;
}
 
void starbar(void){ 
 	int count;
 	for (count = 1; count <= WIDTH; count++)
 	putchar('*');
 	putchar('\n');
}
 该程序的输出如下: ****************************************
GIGATHINK, INC.
101 Megabuck Plaza
Megapolis, CA 94904
**************************************** 
 1.2 分析程序使用该程序时注意以下几点: 程序共有3处使用了starbar标识符:函数原型(function prototype)告诉编译器函数starbar的类型;函数调用(function call)表明在此处执行函数;函数定义(function definition)明确地指定了函数要做什么。函数和变量不一样,有多种类型。任何程序在使用函数之前都要声明该函数的类型。因此,在main函数定义的前面出现了下面的ANSI C风格的函数原型:
 void starbar(void);圆括号表明starbar是一个函数名。第一个void是函数类型,表明函数没有返回值。第二个void(在圆括号中)表明该函数不带参数。分号表明这是在声明函数,不是定义函数。也就是说,这行声明了程序将使用一个名为starbar,没有返回值,没有参数的函数,并告诉编译器在别处查找该函数的定义。对于不识别ANSI C风格原型的编译器,只需声明函数的类型,如下所示:
 
 void starbar();注意,一些老版本的编译器甚至连void都识别不了。如果使用这种编译器,就要把没有返回值的函数声明为int类型。当然,最好还是换一个新的编译器。
一般而言,函数原型指明了函数的返回值类型和函数接受的参数类型。这些信息称为该函数的签名(signature)。对于starbar函数而言,其签名是该函数没有返回值,没有参数。程序把starbar原型置于main的前面,当然也可以放在main里面的声明变量处。在main中,执行到下面的语句时调用了starbar函数:
 starbar();这是调用void类型函数的一种形式。当计算机执行到
 starbar();语句时,会找到该函数的定义并执行其中的内容。执行完starbar中的代码后,计算机返回主调函数(calling function)继续执行下一行(本例中,主调函数是mian),如图9.1所示
 程序中starbar和main的定义形式相同。首先函数头包括函数类型、函数名和圆括号,接着是左花括号、变量声明、函数表达式语句,最后以右花括号(如图9.2)结束。
 main中的右花括号告诉编译器main函数结束的位置,后面的starbar函数头告诉编译器starbar是一个函数。starbar函数中的变量count是局部变量(local variable)。我们可以在程序中的其他地方(包括main中)使用count,这不会引起名称冲突,它们是同名的不同变量。
 1.3 函数参数
  
  程序9.2 lethead2.c
 
#include <stdio.h>
#include <string.h> 
#define NAME "GIGATHINK, INC."
#define ADDRESS "101 Megabuck Plaza"
#define PLACE "Megapolis, CA 94904"
#define WIDTH 40
#define SPACE ' '
void show_n_char(char ch, int num);
int main(void){
 	int spaces;
 	
 	show_n_char('*', WIDTH); 
 	putchar('\n');
 	show_n_char(SPACE, 12); 
 	printf("%s\n", NAME);
 	spaces = (WIDTH - strlen(ADDRESS)) / 2;
 	
 	
 	show_n_char(SPACE, spaces);
 	printf("%s\n", ADDRESS);
 	show_n_char(SPACE, (WIDTH - strlen(PLACE)) / 2);
 	
 	printf("%s\n", PLACE);
 	show_n_char('*', WIDTH);
 	putchar('\n');
 	return 0;
}
void show_n_char(char ch, int num){
 	int count;
 	for (count = 1; count <= num; count++)
 		putchar(ch);
}
 函数运行结果如下: ****************************************
 			  GIGATHINK, INC.
 		    101 Megabuck Plaza		
 		    Megapolis, CA 94904
****************************************
 1.4 定义带形式参数的函数 
  
  
 
 1.5 声明带形式参数函数的原型
 1.6 调用带实际参数的函数 
  待补充 270
 2 ANSI C 函数原型
 2.1 问题所在2.2 ANSI的解决方案针对参数不匹配的问题,ANSI C标准要求在函数声明时还要声明变量的类型,即使用函数原型(function prototype)来声明函数的返回类型、参数的数量和每个参数的类型。以下是两种函数原型: int imax(int, int);
int imax(int a, int b); 
 第一种形式使用以逗号分隔的类型列表,第二种形式在类型后面添加了变量名。注意,这里的变量名是假名,不必与函数定义的形式参数一致。 有了这些信息后,编译器可以检查函数调用是否与函数原型匹配,函数的数量是否正确,参数的类型是否匹配。以imax函数为例,如果两个参数都是数字,但是类型不匹配,编译器会把实际参数的类型转换成形式参数的类型。例如,imax(3.0, 5.0)会被转换成imax(3, 5)。用函数原型替换程序9.4 中的函数声明,如程序9.5所示: 程序9.5 proto.c 
#include <stdio.h>
int imax(int, int); 
int main(void){
 	printf("The maximum of %d and %d is %d.\n", 3, 5, imax(3));
 	printf("The maximum of %d and %d is %d.\n", 3, 5, imax(3.0, 5.0));
 	return 0;
}
int imax(int n, int m){
 	return (n > m ? n : m);
} 
 编译程序清单9.5时,编译器会给出调用的imax函数参数太少的错误信息。 如果类型不匹配又会怎样,为了探究这个问题,我们使用imax(3, 5)替换imax(3),然后再次编译该程序。这次编译器没有给出任何错误信息,程序的输出如下: The maximum of 3 and 5 is 5.
The maximum of 3 and 5 is 5. 
 
 2.3 无参数和未指定参数 
 
 2.4 函数原型的优点
 |