第九章 函数

发布于 2021-08-19  510 次阅读


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');
 }

file

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指令也放入该文件

file

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的值。
形式参数是被调函数中的变量,实际参数是主调函数赋给被调函数的具体值。
实际参数可以是常量、变量,或甚至更复杂的表达式。无论实际参数是任何形式都要被求值,然后拷贝给调函数相应的形式参数。

file

9.1.7 黑盒视角

从黑盒的视角看show_n_char(),待显示的字符和显示的次数是输入。执行后的结果是打印指定数量的字符。输入以参数的形式被传递给函数。这些信息清楚地表明了如何在main()中使用该函数。而且,这也可以作为编写该函数的设计说明。

file

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;       
    }
}

file

9.1.9 函数类型

类型声明是函数定义的一部分.
double klink(int a, int b)
定义了一个带两个int类型参数的函数,返回值是double类型。
程序在第一次使用函数之前必须知道函数的类型。方法之一是,把完整的函数定义放在第一次调用函数的前面。

擦肩而过的概率