文章目录[隐藏]
9.1 复习函数
函数(function)是完成特定任务的独立程序代码单元。
语法规则定义了函数的结构和使用方式。
为什么使用函数?
使用函数可以省去编写重复代码的苦差。
9.1.1 创建并使用简单的函数
问题:创建一个在一行打印40个星号的函数,并在一个打印表头的程序中使用该函数。
#include<stdio.h>
#define NAME "GA,CHINA"
#define ADDRESS "419177984@qq.com"
#define PHONE "18740972318"
#define WIDTH 40
void starbar(void); //函数原型
int main(void)
{
starbar();
printf("%s\n", NAME);
printf("%s\n", ADDRESS);
printf("%s\n", PHONE);
starbar();
return 0;
}
void starbar(void) //定义函数
{
int count;
for(count = 1;count <= WIDTH;count++)
{
putchar('*');
}
putchar('\n');
}
9.1.2 分析程序
该程序要注意以下几点。
*程序3处使用了starbar标识符:函数原型(function prototype)告诉编译器函数starbar()的类型;函数调用(function call)表明在此处执行函数;函数定义(function definition)明确的制定了函数要做什么。
*函数和变量一样,有多种类型,任何程序在使用函数之前都要声明该函数的类型。
void starbar(void);
圆括号表明starbar是一个函数名。第一个void是函数类型,void类型表明函数没有返回值。第二个void(在圆括号里面)表明函数不带参数。分号表明是在声明函数,不是定义函数。
也就是说,这行声明了程序将使用一个名为starbar()、没有返回值、没有参数的函数,并告诉编译器在别处查找该函数的定义。
*一般而言,函数原型指明了函数的返回值类型和接受的参数类型。这类信息称为该函数的签名(signature)。对于starbar()函数而言,其签名是没有返回值,没有参数。
*程序把starbar()原型置于main()的前面。当然也可以放在main()里面声明变量处。
*在main()中,执行到下面的语句时调用了starbar()函数
starbar();
这是调用void类型函数的一种形式。当计算机执行到starbar();语句时,会找到该函数的定义并执行其中的内容。执行完starbar()中的代码以后,计算机返回主调函数(calling function)继续执行下一行。
*程序中starbar()和main()的定义形式相同。首先函数头包括函数类型、函数名和圆括号,接着是做花括号、变量声明、函数表达式语句,最后以右花括号结束。
注意,函数头中的starbar()后面没有分号,告诉编译器这是定义starbar(),而不是调用函数或声明函数原型。
*程序把starbar()和main()放在一个文件夹中。当然,也可以把他们分别放在两个文件中。把函数都放在一个文件中的单文件形式比较容易编译,而使用多个文件方便在不同的程序中使用同一个函数。如果把函数放在一个单独的文件中,要把#define和#include指令也放入该文件
starbar()函数中的变量是count的局部变量(local variable),意思是该变量只属于starbar()函数。可以在程序中的其他地方(包括main()中)使用count,这不会引起名称冲突,他们是同名的不同变量。
如果把starbar()看作是一个黑盒,那么它的行为是打印一行星号。不用给该函数提供任何的输入,因为调用它不需要其他信息。而且,它没有返回值,所以也不给main()提供任何信息。
9.1.3 函数参数
问题:(接上)让文字居中~
#include<stdio.h>
#define NAME "GA,CHINA"
#define ADDRESS "419177984@qq.com"
#define PHONE "18740972318"
#define WIDTH 40
#define SPACE ' '
void show_n_char(char ch,int num); //函数原型
int main(void)
{
//void starbar(void);
show_n_char('*',40);
printf("%s\n", NAME);
printf("%s\n", ADDRESS);
show_n_char(SPACE,10);
printf("%s\n", PHONE);
return 0;
}
void show_n_char(char ch,int num) //定义函数
{
int count;
for(count = 1;count <= num;count++)
{
putchar(ch);
}
putchar('\n');
}
9.1.4 定义带形式参数的函数
void show_n_char(char ch, int num)
改行告诉编译器这个函数数用两个参数ch和num,这两个变量称为形式参数(farmal argument),简称形参。
和定义在函数中的变量一样,形式参数也是局部变量,属该函数私有。每次调用函数,就会给这些变量辅助。
void dibs(int x,y,z); //无效的函数头
void dubs(int x,int y, int z); //有效的函数头
//ANSI C也接受ANSI C之前的形式,但是将其视为废弃不用的形式
void show_n_char(ch,num)
char ch;
int num;
//有效但不用
void dibs(x,y,z)
int x,y,z;
虽然show_n_char()接受来自main()的值,但是他没有返回值,因此,show_n_char()的类型是void。
9.1.5 声明带形式参数函数的原型
在使用函数之前,要用ANSI C 形式声明函数原型:
void show_n_char(char ch,int num);
当函数接受参数时,函数原型用逗号分隔的列表指明参数的数量和类型。根据个人喜好,你也可以省略变量名:
void show_n_char(char,int);
在原型中使用变量名并没有实际创建变量,char仅代表一个char类型的变量,以此类推。
ANSI C 也接受过去的声明函数形式,即圆括号内没有参数列表:
void show_n_char();
9.1.6 调用带实际参数的函数
在函数调用中,实际参数(actual argument,实参)提供了ch和num的值。
形式参数是被调函数中的变量,实际参数是主调函数赋给被调函数的具体值。
实际参数可以是常量、变量,或甚至更复杂的表达式。无论实际参数是任何形式都要被求值,然后拷贝给调函数相应的形式参数。
9.1.7 黑盒视角
从黑盒的视角看show_n_char(),待显示的字符和显示的次数是输入。执行后的结果是打印指定数量的字符。输入以参数的形式被传递给函数。这些信息清楚地表明了如何在main()中使用该函数。而且,这也可以作为编写该函数的设计说明。
9.1.8 使用return从函数中返回值
创建一个返回两个参数中较小值的函数。由于函数被设计来处理int类型的值,所以被命名为imin()。另外还要创建一个简单的main(),用来检查imin()是否正常工作。这类被设计用于测试函数的程序有时被称为驱动程序(driver),该驱动程序调用一个函数。如果函数成功通过了测试,就可以安装在一个更重要的程序中使用
#include<stdio.h>
int imin(int a,int b);
int main(void)
{
int evill1,evill2;
printf("Enter a pair of integers(q to quit):\n");
while(scanf("%d %d",&evill1,&evill2) == 2)
{
printf("The lesser of %d and %d is %d\n",evill1,evill2,imin(evill1,evill2));
printf("Enter a pair of integers(q to quit):\n");
}
printf("Bye!\n");
return 0;
}
int imin(int a,int b)
{
if(a<b){
return a;
}
else {
return b;
}
}
9.1.9 函数类型
类型声明是函数定义的一部分.
double klink(int a, int b)
定义了一个带两个int类型参数的函数,返回值是double类型。
程序在第一次使用函数之前必须知道函数的类型。方法之一是,把完整的函数定义放在第一次调用函数的前面。
叨叨几句... NOTHING