• C语言——函数


    C语言目录:

    1. 概述

    2. 数据类型

    3. 量

    4. 运算符

    5. 流程控制

    6. 函数

    7. C程序编译过程

    8. 文件

    9. 内存管理


    将一个常用的功能封装起来,方便以后调用

    6.1 分类及定义

    同一源文件函数名称不能相同

    返回值类型 函数名(参数类型 形式参数1,参数类型 形式参数2,…){
        函数体;
        返回值;
    }
    
    • 1
    • 2
    • 3
    • 4
    分类
    函数定义
    库函数
    用户定义函数
    函数执行结果
    有返回值函数
    无返回值函数
    数据传送
    无参函数
    有参函数

    6.1.1 库函数与用户定义函数

    a. 库函数

    由C语言系统提供,用户无需定义,也不必在程序中做类型说明,引入头文件后即可在程序中直接调用

    b. 用户定义的函数

    由用户按需编写的函数。对于用户自定义的函数,不仅要在程序中定义函数本身,而且在主调函数中必须对该被调函数进行声明,才能调用

    6.1.2 有返回值与无返回值函数

    a. 有返回值函数

    必须指定返回值类型和使用return关键字返回对应数据

    返回值类型 函数名(参数列表){
        函数体;
        返回值;
    }
    
    • 1
    • 2
    • 3
    • 4

    b. 无返回值函数

    void 函数名(参数列表) {
        函数体;
    }
    
    • 1
    • 2
    • 3

    6.1.3 有参函数和无参函数

    a. 无参函数

    返回值类型 函数名() {
        函数体;
        return;
    }
    
    • 1
    • 2
    • 3
    • 4

    b. 有参函数

    返回值类型 函数名(参数类型 形式参数1,参数类型 形式参数2,…) {
        函数体;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4

    6.2 参数与返回值

    6.2.1 形参与实参

    形参 :定义函数时,函数名后面的 () 称为形参

    形参变量只有在函数被调用时分配内存。在函数调用结束,释放内存单元

    实参 :函数调用时,传入的值称为实参

    实参可以是常量、变量、表达式、函数等

    在进行函数调用时,都必须具有确定的值,以便把这些值传递给形参

    a. 注意

    个数:调用函数时,传递的实参个数和函数的形参个数必须保持一致

    类型:形参与实参类型不一致,会自动转换为形参类型

    void change(double number1, double number2) {//  形参
    }
    
    int main() {
        change(10, 20);
        // 传入实参  10.000000, 20.000000
       // 自动将实参转换为double类型后保存
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    值传递:当使用基本数据类型(char、int、float)作为实参时,实参和形参之间只是值传递,修改形参的值并不影响实参

    void change(int number1, int number2) { //  形式参数
        number1 = 250; // 不会影响实参
        number2 = 222;
    }
    
    int main() {
        int a = 88;
        int b = 99;
        change(a, b);
        printf("a  = %d, b = %d", a, b); // 输出结果: 88, 99
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    6.2.2 返回值

    如果没有写返回值类型,默认是 int

    return 实际返回的值类型应与函数返回值类型一致,否则以返回值类型为准,自动进行类型转换

    int height() {
        return 3.14; 
    }
    
    int main() {
      double temp = height();
      printf("%lf", temp);// 输出结果: 3.000000
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    一个函数内部可以多次使用 return ,但 return 之后的代码不再执行

    6.3 函数的声明

    默认情况下,只有后面定义的函数才可以调用前面定义过的函数

    函数声明:在函数调用之前告诉系统,函数名称、参数列表、返回值类型

    函数实现:定义具体的业务逻辑是怎么运作的

    函数声明格式:返回值类型 函数名(参数列表);

    // 函数声明
    void getMax(int v1, int v2);
    int main(int argc, const char * argv[]) {
        getMax(10, 20); // 调用函数
        return 0;
    }
    // 函数实现
    void getMax(int v1, int v2) {
        int max = v1 > v2 ? v1 : v2;
        printf("max = %i\n", max);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 函数的实现不能重复, 而函数的声明可以重复

    • 函数声明可以写在函数外面,也可以写在函数里面,,只要在调用之前被声明即可

    int main(int argc, const char * argv[]) {
        void getMax(int v1, int v2); // 函数声明, 不会报错
        getMax(10, 20); // 调用函数
        return 0;
    }
    // 函数实现
    void getMax(int v1, int v2) {
        int max = v1 > v2 ? v1 : v2;
        printf("max = %i\n", max);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    如果被调函数的返回值是整型,可以不对被调函数做声明,可以直接调用

    int main(int argc, const char * argv[]) {
        int res = getMin(5, 3); // 不会报错
        printf("result = %d\n", res );
        return 0;
    }
    
    int getMin(int num1, int num2) {// 返回int, 不用声明
        return num1 < num2 ? num1 : num2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    6.4 输入输出

    6.4.1 putchar()和getchar()

    putchar():向屏幕输出一个字符

    #include 
    int main(){
        char ch = 'a';
        putchar(ch); // 输出a
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    getchar():从键盘获取一个字符

    #include 
    int main(){
        char ch;
        ch = getchar();// 获取一个字符
        printf("ch = %c\n", ch);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    6.4.2 scanf函数

    系统会先将用户输入放入输入缓冲区,从缓冲区中逐个取数据赋值给变量,如果输入缓冲区不为空,scanf 会一直从缓冲区中获取

    #include 
    
    int main(){
        int num1;
        int num2;
        char ch1;
        scanf("%d%c%d", &num1, &ch1, &num2);
        printf("num1 = %d, ch1 = %c, num2 = %d\n", num1, ch1, num2);
        
        char ch2;
        int num3;
        scanf("%c%d",&ch2, &num3);
    
        printf("ch2 = %c, num3 = %d\n", ch2, num3);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

    a. fflush

    利用 fflush(stdin); 清空缓冲区

    C和C++标准从未定义过,是C标准的扩充函数,不是所有平台都支持

    b. setbuf

    setbuf(stdin,NULL) 设置缓冲区为空

    所有平台有效

    6.4.3 printf()函数格式

    a. 数据类型符

    类型含义
    %d / %i有符号十进制整型
    %u无符号十进制整型
    %o无符号八进制整型
    %x / %X无符号十六进制整型
    %f单、双精度浮点数
    %e / %E以指数形式输出单、双精度浮点数
    %c字符
    %s字符串
    %p地址
    %%表示%本身
    #include 
    
    int main(){
        int a = 10;    
        int b = -10;
        
        // 有符号整数(可以输出负数)
        printf("a = %d\n", a); // 10
        printf("a = %i\n", a); // 10
    
        // 无符号整数(不可以输出负数)
        // 输出存储单元内二进制数对应的十进制整数
        printf("a = %u\n", a); // 10
        printf("b = %u\n", b); // 429496786
    
        // 无符号八进制整数(不可以输出负数)
        //输出存储单元内二进制数对应的十进制整数对应的八进制数
        printf("a = %o\n", a); // 12
        printf("b = %o\n", b); // 37777777766
    
        // 无符号十六进制整数(不可以输出负数)
        printf("a = %x\n", a); // a
        printf("b = %x\n", b); // fffffff6
    
        // 无符号十六进制整数(不可以输出负数)
        printf("a = %X\n", a); // A
        printf("b = %X\n", b); // FFFFFFF6
    
        float c = 6.6f;
        double d = 3.1415926;
        
        // 单、双精度浮点数(默认保留6位小数)
        printf("c = %f\n", c); // 6.600000
        printf("d = %lf\n", d); // 3.141593
    
        double e = 10.10;
        // 以指数形式输出单、双精度浮点数
        printf("e = %e\n", e); // 1.010000e+001
        printf("e = %E\n", e); // 1.010000E+001
        
        // 以最短输出宽度,输出单、双精度浮点数
        printf("e = %g\n", e); // 10.1
        printf("e = %G\n", e); // 10.1
        
        char f = 'a';
        // 输出字符
        printf("f = %c\n", f); // a
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    实型有效位问题
    • 单精度 %f 输出时,仅前6-7位是有效数字;双精度 %lf 输出时,仅前15-16位是有效数字
    • 有效位数包含小数点前的非零数位

    精度与有效位

    有效位:指从第一个非零数字开始,误差不超过本数位半个单位的、正确的数位

    原因:计算机存储浮点数时,采用IEEE754,存的是IEEE754可表示的最相近浮点数

    #include 
    int main(){
        //        1234.567871093750000
        float a = 1234.567890123456789;
        //         1234.567890123456900
        double b = 1234.567890123456789;
        printf("a = %.15f\n", a); // 前8位数字是准确的, 后面的都不准确
        printf("b = %.15f\n", b); // 前16位数字是准确的, 后面的都不准确
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    b. 精度格式符

    精度:小数点后位数

    %.n数据类型符 ,n为十进制整数

    • 如果输出数字,则表示小数的位数;
    • 如果输出的是字符,则表示输出字符的个数;
    • 若实际位数大于所定义的精度数,则截去超过的部分
    #include 
    int main(){
        double a = 3.1415926;
        printf("a = %.2f\n", a); // 3.14
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    动态指定保留小数位数

    格式:printf("%.*f",[],a);

    #include 
    int main(){
        double a = 3.1415926;
        printf("a = %.*f", 2, a); // 3.14
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    c. 格式控制符

    符号含义
    %m…m指定输出字段的宽度,如果位数小于m,则左端以空格补全;若位数大于,则按实际位数输出
    -结果左对齐,右边补空格
    #对于c,s,d,u类影响
    八进制,加前缀o
    十六进制,加前缀0x
    对于浮点数,只有当结果有小数才给出小数点
    空格输出值为整数,在输出值前面加上空格,为负数加上负号
    +当输出值为正数时,在输出值前面加上一个+号, 默认不显示
    0右对齐时,用0填充
    #include 
    int main(){
        int a = 1;
        int b = -1;
        // -号标志
        printf("a =|%d|\n", a); // |1|
        printf("a =|%5d|\n", a); // |    1|
        printf("a =|%-5d|\n", a);// |1    |
        // +号标志
        printf("a =|%d|\n", a); // |1|
        printf("a =|%+d|\n", a);// |+1|
        printf("b =|%d|\n", b); // |-1|
        printf("b =|%+d|\n", b);// |-1|
        // 0标志
        printf("a =|%5d|\n", a); // |    1|
        printf("a =|%05d|\n", a); // |00001|
        // 空格标志
        printf("a =|% d|\n", a); // | 1|
        printf("b =|% d|\n", b); // |-1|
        // #号
        int c = 10;
        printf("c = %o\n", c); // 12
        printf("c = %#o\n", c); // 012
        printf("c = %x\n", c); // a
        printf("c = %#x\n", c); // 0xa
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    6.7 递归函数

    一个函数在它的函数体内调用它自身称为递归调用

    • 递归常用于"回溯", “树的遍历”,"图的搜索"等问题
    void function(int x){
        function(x);
    }
    
    • 1
    • 2
    • 3
    • 存在一个条件能够让递归结束

    • 问题的规模能够缩小

    • 能用循环实现的功能,用递归都可以实现

    代码理解难度大内存消耗大(易导致栈溢出), 所以考虑到代码理解难度和内存消耗问题, 在企业开发中一般能用循环都不会使用递归

  • 相关阅读:
    Vue项目实战——【基于 Vue3.x + Vant UI】实现一个多功能记账本(开发导航栏及公共部分)
    了解 Xcode 工作区、项目、方案和目标如何协同工作
    【mcuclub】四相五线步进电机
    Task07|缺失数据|DataWhale组队学习
    HTTP原理入门
    设计模式之原型模式
    (1)(1.16) Maxbotix I2C声纳
    flask学生信息管理
    Go-Zero定义API实战:探索API语法规范与最佳实践(五)
    Harbor企业级私服Docker镜像仓库搭建及应用
  • 原文地址:https://blog.csdn.net/qq_40479037/article/details/126175170