C语言基础篇3:函数

1 函数简介

C源程序是由函数组成的,一个程序往往由多个函数组成,函数是程序实现模块化变成的基本的单元,一般是为了完成某一个特定的功能,相当于其他语言中的子程序。一个较大程序的各项功能都是由各个子程序共同完成的,或者说C程序的全部工作都是由各式各样的函数完成的。

1.1 概述

一个完整的C程序是通过函数之间互相调用实现的。通过对函数模块的调用,可以实现相应的功能。在进行程序设计时,会将一些常用的功能模块编写成函数,放在函数库中供公共使用。有些函数是按照ANSI C的要求随C语言编译器提供的,这种函数称为库函数。像printf、scanf等,都属于库函数。

每个程序的入口和出口都是位于main函数中。编写程序时,并不是将所有的内容都放在main方法中。为了方便规划、组织、编写和调试,一般的做法是将一个程序划分为若干个程序模块,每个程序模块都完成一部分功能。这样不同的程序模块可以由不同的人来完成,从而提高软件开发效率。

也就是说,main函数可以调用其他的函数,其他函数也可以互相调用。在main函数中调用其他的函数,这些函数执行完毕后又返回到man函数中。通常把这些被调用的函数称为下层函数。函数调用发生时,立即执行被调用的函数,而调用者则进入等待的状态,直到被调用函数执行完毕。函数可以由参数和返回值。

【注意】C程序中所有的函数都是平行的,即在定义函数时是互相独立的,在一个函数中不能嵌套定义另一个函数,函数间可以互相调用,但main函数是不能被调用的。

【示例1.1】在主函数中调用其他函数

cpp 复制代码
#include <stdio.h>
void Move();
void Build();
void Paint();
int main(){
    Move();
    Build();
    Paint();
    return 0;
}
void Move(){
    printf("=============================\n");
    printf("==========执行move函数===================\n");
    printf("=============================\n");
}
void Build(){
    printf("=============================\n");
    printf("==========执行Build函数===================\n");
    printf("=============================\n");
}
void Paint(){
    printf("=============================\n");
    printf("==========执行Paint函数===================\n");
    printf("=============================\n");
}

下面分析一下这个程序:

首先,一个源文件是由一个或多个函数组成。一个源程序文件是一个编译单位,即以源程序为单位进行编译,而不是以函数为单位进行编译。

函数库由C系统提供,用户无须定义,在调用函数之前也不必再程序中作类型说明,只需在程序前包含有该函数原型的头文件即可在程序中直接调用。例如,在上面的程序中用于控制台显示信息的printf函数,之前应在程序开始部分包含stdio.h头文件;又如,要使用其他字符串操作函数strlen、 strcmp等时,也应在程序开始部分包含string.h。

用于自定义函数,就是用户自己编写的用来实现特定功能的函数,如上面程序中的Move函数等。

在该程序中,要是printf函数首先要包含stdio.h头文件,之后声明3个自定义函数,最后在主函数中调用3个函数。

1.2 函数的定义与声明

1、函数的定义形式

在程序中编写函数时,函数的定义是让编译器知道函数的功能。函数一般包括用户自己定义和系统提供的标准函数两种。如果是系统提供的标准函数,那么不需要进行定义即可使用,如果是用户自己定义的函数,那么必须遵守"先定义,后使用"的原则。函数的定义分两部分:函数头和函数体。函数的定义语法:

函数返回值的类型名 函数名(形式参数列表) --函数头

{

声明部分

语句部分 --函数体

return 表达式

}

函数头分三个部分:

返回值类型:返回值可以是某个C数据类型。

函数名:函数名也就是函数的标识符,函数名在程序中必须是唯一的。

参数列表:形式参数列表简称为形参,可以没有变量也可以有多个变量,在进行函数调用时,实际参数将被复制到这些变量中。有时,函数定义中没有形参,叫做无参函数,无参函数一般不用写返回值类型。

函数体:

函数体位于函数头下方,由一对大括号括起来,大括号决定了函数体的范围。函数体包括局部变量和函数的可执行代码。声明部分包括函数声明、变量定义和变量声明,函数要实现的特定功能,都是在函数体部分通过代码完成。最后通过return返回函数执行的结果。

2、函数的定义与声明

在程序中编写函数时,要先对函数进行声明,然后再对函数进行定义。函数的声明是让编译器知道函数的名称、参数、返回值类型等信息。函数的定义是让编译器知道函数的功能。

函数的声明格式由函数返回值类型、函数名、参数列表和分号4部分组成。例如:

返回值类型 函数名(参数列表);

【注意】如果将函数的定义放在调用函数之前,那么就不需要进行函数的声明。此时函数的定义就包含了函数的声明。

定义:实在编译器内创建了一个对象,为这个对象分配一块内存,并且给对象取一个名字,取得名字就是经常说的变量名或对象名。

声明:告诉编译器这个名字已经分配到一块内存里,并且这个名字现在归此声明所用,其他地方不允许再用这个名字。

定义和声明的最大区别:定义创建了对象,并给对象分配内存;声明没有为对象分配内存。

【示例2.1】计算任意两个整数的积

cpp 复制代码
#include <stdio.h>
int mul(int x,int y){
    int z;
    z = x * y;
    return z;
}
int main(){
    int a,b,c;
    printf("请输入a和b :\n");
    scanf("%d,%d",&a,&b);
    c = mul(a,b);
    printf("a 和 b 的乘积是:%d\n",c);
    return 0;
}

2 函数参数

在调用函数时,大多数情况下,主调函数和被调用函数之间有数据传递关系,这就是前面提到的函数形式。函数参数的作用是传递数据给函数使用,函数利用接收的数据进行具体的操作处理

2.1 形式参数和实际参数

在使用函数时,通常会涉及两种参数,形式参数和实际参数,两者之间既有联系又有区别。

形式参数:在定义函数时,函数名后面括号中的变量名称为"形式参数"。在函数调用之前,传递给函数的值将被复制到这些形参中。

实际参数:在调用一个函数时,也就是真正使用一个函数时,函数后面括号中的参数为"实际参数"。

在通常情况下,形式参数简称为形参,实际参数简称为实参。

形参和实参的特点和注意事项如下:

形参变量只有在被调用时才分配内存单元,在调用结束时,会释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能在使用该形参变量。

实参可以是常量、变量、表达式和函数等,不论是什么类型的数据,只要是实参,再到用进行调用时,这个类型量必须是确定的值,以便把这些值传递给形参。为了避免发生"类型不匹配"的错误,实参和形参的类型、数量、书写顺序都必须要保持一致。

C语言固定,实参变量对形参变量的数值传递是单向传递,即只能由实参传递给形参。

2.2 数组作为函数参数

上面介绍了,在传递函数参数时,将变量作为函数的参数,除此之外还有一种特殊的情况,即数组作为函数参数。因为将数组作为函数参数进行传递,不同于标准的赋值调用的参数传递方法。下面将介绍数组作为函数参数时的参数传递方法。

当数组作为函数的参数时,只传递数组的地址,而不是将整个数组赋值到函数中去。当用数组作为实参调用函数时,指向该数组的第一个元素的指针就被传递到函数中。

例如:定义一个具有10个元素的整型数组:int array[10] ;

注意:在C语言中,没有任何下标的数组名就是一个指向该数组第一个元素的指针。其中的代码没有下标的数组名array与指向第一个元素的指针*array是相同的。

由于实参可以是表达式形式,数组元素可以是表达式的组成部分,因此数组元素可以作为函数的实参,与用变量作为函数实参一样,是单向传递。

【示例2.2.1 数组元素作为函数参数】

cpp 复制代码
#include <stdio.h>
void showMembers(int i);
int main(){
    int array[10];
    int i ;
    for(i = 0;i<10;i++){
        array[i] = i;
    }
    for(i = 0;i < 10;i++){
        showMembers(array[i]);
    }
    return 0;
}
void showMembers(int i){
    printf("显示的元素是:%d\n" ,i);
}

3 函数调用

函数的调用方式有3种:函数语句调用、函数表达式和函数参数调用。

如果自定义函数在主函数的前面时,就不需要在引用头文件后再进行声明,如果自定义函数在主函数的后面时,就需要在引用头文件时进行提前声明。

3.1 函数语句调用

把函数的调用作为一个语句就叫函数语句调用。函数语句调用是最长使用的调用函数的方式。

【示例3.1】函数语句调用:

cpp 复制代码
#include <stdio.h>
void disPlay(){
    printf("hello,world!\n");
}
int main(){
    disPlay();//函数语句调用
    return 0;
}

3.2 函数表达式调用

函数出现在一个表达式中,这时要求函数的带回一个确定的值,这个值参加表达式的运算。

【示例3.2】函数表达式调用

cpp 复制代码
#include <stdio.h>
int addNum(int num1,int num2);
int main(){
    int result;
    int num3 = 10;
    result = num3 * addNum(3,5);
    printf("计算的结果是: %d  \n",result);
    return 0;
}
int addNum(int num1,int num2){
    int result;
    result = num1 + num2;
    return result;
}

3.3 函数参数调用

函数调佣可以作为一个函数的实参,将函数返回值作为实参传递到函数中进行使用。函数出现在一个表达式中,这时要求函数带回一个确定的值,这个值参加表达式的运算。

【示例3.3】函数参数调用:

cpp 复制代码
#include <stdio.h>
int addNum(int num1,int num2);
int main(){
    int result;
    result = addNum(20, addNum(3,2));
    printf("result: %d  \n",result);
    return 0;
}
int addNum(int num1,int num2){
    int result;
    result = num1 + num2;
    return result;
}

4 函数嵌套

在C语言中,函数的定义都是互相平行、独立的。也就是说在定义函数时,一个函数体内不能包含定义另一个函数。但是可以嵌套调用函数,也就是说,在一个函数体内可以调用另一个函数。

【示例4】函数嵌套调用

cpp 复制代码
#include <stdio.h>
void a();
void b();
void c();
int main(){
    a();
    return 0;
}
void a(){
    printf("a方法可以调用b方法\n");
    b();
}
void b(){
    printf("b方法可以调用c方法 \n");
    c();
}
void c(){
    printf("c方法被b方法调用 \n");
}
相关推荐
源码哥_博纳软云4 分钟前
JAVA同城服务场馆门店预约系统支持H5小程序APP源码
java·开发语言·微信小程序·小程序·微信公众平台
学会沉淀。11 分钟前
Docker学习
java·开发语言·学习
西猫雷婶42 分钟前
python学opencv|读取图像(二十一)使用cv2.circle()绘制圆形进阶
开发语言·python·opencv
kiiila42 分钟前
【Qt】对象树(生命周期管理)和字符集(cout打印乱码问题)
开发语言·qt
罗伯特祥1 小时前
C调用gnuplot绘图的方法
c语言·plot
小_太_阳1 小时前
Scala_【2】变量和数据类型
开发语言·后端·scala·intellij-idea
直裾1 小时前
scala借阅图书保存记录(三)
开发语言·后端·scala
唐 城2 小时前
curl 放弃对 Hyper Rust HTTP 后端的支持
开发语言·http·rust
嵌入式科普2 小时前
嵌入式科普(24)从SPI和CAN通信重新理解“全双工”
c语言·stm32·can·spi·全双工·ra6m5
码银3 小时前
【python】银行客户流失预测预处理部分,独热编码·标签编码·数据离散化处理·数据筛选·数据分割
开发语言·python