Linux和C语言(Day10)

一、学习内容

  1. 指针数组

    1. 本质是一个数组,数组的类型是指针,也就是存储的是地址

    2. 整型数组:int a[5]={1,2,3,4,5}//类型是整数,存的都是整数

    3. 指针数组:int *a[5]={&,&,&,&,&}

  2. 指针和字符串

    • 指针指向字符数组

    • 指针指向字符串常量

  3. 函数

    1. 函数的定义

      1. 实现特定功能的代码块

    2. 函数的作用

      1. 分工合作、提高效率

      2. 提高代码的重用率

      3. 功能独立。便于维护与修改

    3. 函数的分类

      1. 用户角度
        1. 库函数——前辈写好的,放在include目录中,以.h做后缀的头文件

          1. eg:strlen\strcmp\strcpy\strcat\getchar\putchar\gets\puts\printf\memset\bzero

        2. 自定义函数——用户自己写的函数

          1. eg:int my_strlen(const char *s){ int count=0; while(*s !='\0'){ count++; s++; } }

      2. 参数角度
        1. 有参函数

        2. 无参函数

      3. 返回值角度
        1. 无返回值函数

        2. 有返回值函数

    4. 函数的定义语法格式

      1. 定义函数: 存储类型 数据类型 函数名(参数列表){ 实现特定功能的代码块 }

      2. 分析: 存储类型——自动存储(auto)、寄存器存储(register)、静态存储(static)、外部存储(extern)和常量存储(const)等【函数若省略存储类型,默认是extern】 数据类型——基本、构造、指针、空,控制的是函数的返回值,一个函数可以返回一个值,若没有返回值设为void 函数名——符合命名规范 ①驼峰命名法SumFunction()②连字符法 sum_fun() ()——函数的标志,不可以省略 (参数列表)——参数列表可以为空void,也可以不为空,可以写多个参数,中间以逗号隔开。定义函数时的参数——形参,只起到一个占位符的作用,没有实际意义。当你去使用该函数的时候,往里面按传你想传的参数——实参,有实际意义。 {}——中间写代码块

      3. 函数三要素:功能,返回值,参数

    5. 使用/调用函数

      1. 第一种: int fun(int a,int b){ return a+b; } //定义有参有返回值函数 并 实现功能 printf("%d\n",fun(1,2));//使用函数fun

      2. 第二种: void show(char *name){ printf("Welcome %s",name) } //定义有参无返回值函数 并 实现功能 show("张xx"); //使用函数show

  4. 函数声明

    • 一个程序中有且只有一个主函数main,作为程序的入口部分。C语言的代码执行是从上往下依次执行的,若顺序颠倒的话,读到9 10 11 12行出现不明函数。 这个时候我们可以使用函数声明。

      • 定义变量初始化
        • int a=10; int a; a=10;

      • 定义函数并实现
        • 第一种:int my_sum(int a,int b){return a+b;}

        • 第二种:①int my_sum(int a,int b); //int my_sum(int,int); ②int my_sum(int a,int b){return a+b;}

      • 函数声明的意义是什么呢
        • 提高效率【main可以放在前面,也可以放在后面,但是建议放在最前面,作为入口】

        • 便于分工合作

  5. 讲解有参函数

    • 形参 和 实参

      • 形参——定义时的参数,形式上的参数,没有实际意义,语法上必须带有数据类型 void fun(int a,int b); void fun(int a[],int n); void fun(char *s); 可以是:变量、数组、指针

      • 实参——调用时的参数,实际上的参数,有实际意义,实参语法上不加数据类型,直接传参名字 fun(a,b) fun(1,2) fun(a+2,3) fun(a,strlen(a)) fun(3,fun(4,5)) 可以:常量、变量名、数组名、指针名、表达式

      • 注意:实参必须和形参保持数据类型、顺序、数量一一对应。【名字无所谓】

        • eg: void fun(int a,float b,char c); fun(3 , 4 , 'A'); //正确 fun(3,4); //错误 int x=3; float y=3.5; char z='a'; fun(x,y,z); //正确

    • 值传递 和 地址传递

      • 值传递

        • 形参和实参分处不同的存储单元形参变实参不变

          • 实参【原件】拷贝出一份值给形参【复印件】,复印件修改原件不变

      • 地址传递

        • 形参和实参除处在相同的存储单元里面形参变、实参也变

          • 实参【原件】直接给了形参

    • 数组传参方式

      • 整型一维数组传参

        • 一维数组传参需要两个参数——数组、数组的长度

          • void FA(int a[10],int n);

          • void FA(int a[],int n);

          • void FA(int *a,int n);

      • 整型二维数组传参

        • 二维数组传参需要三个参数——数组、行数、列数

          • void FB(int b[2][3], int hang, int lie);

          • void FB(int b[][3], int hang, int lie);

          • void FB(int (*b)[3], int hang, int lie);

  6. 脑图

二、作业

1.函数之间参数传递的方式有________和________。(富士安全)

解答:

值传递和地址传递
值传递:将实际参数的值复制给形参,函数内部修改形参不会影响实际参数。

地址传递:传递的是参数的引用(或指针),函数内部修改形参会直接影响实际参数。

2.简述:函数之间两种参数传递方式的区别。

解答:

值传递:

概念:将实际参数的值复制给函数的形参,函数内部操作的都是形参的副本。

特点:函数对形参的修改不会影响实际参数。适用于不希望函数修改原始数据的情况。

地址传递:

概念:传递的是实际参数的地址或引用,函数对形参的操作会直接影响实际参数。

特点:函数可以直接修改实际参数的值。适用于需要在函数内部修改外部变量的场景。

3.函数main 有那些参数?各代表什么含义? 假如程序a调用如下所示:a 123写出程序a中main 函数的参数的具体值。 (拓仓科技)

解析:

int argc, const char *argv[]一共是两个参数,argc代表的是调用命令的个数,而agrv[]是调用命令时所存的数组

解答:

当程序调用a 123时,参数的值会发生改变,变为agrc=2 argv[0]=a、argv[1]=123

4.用指针作函数参数,编程序求一维数组中的最大和最小的元素值

思路:①主函数中定义一维数组int a[]={11,8,89,7,5,4,32,15,21} , max , min;

  ②定义函数 void arr_max(int *a, int n,int *max);      //a接收数组 n表示长度 max接收最大值

  ③定义函数 void arr_min(int *a, int n,int *min);        //a接收数组 n表示长度 min接收最小值

  ④在主函数中输出最大值和最小值

解答:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// 函数声明:用于找到数组中的最大值
void arr_max(int *a, int n, int *max);
// 函数声明:用于找到数组中的最小值
void arr_min(int *a, int n, int *min);

int main(int argc, const char *argv[]) {
    // 初始化一个整型数组 a,并赋值
    int a[] = {11, 8, 89, 7, 5, 32, 15, 21};
    
    // 定义变量 max 和 min,分别存储数组中的最大值和最小值
    int max, min;

    // 计算数组的长度
    int len = sizeof(a) / sizeof(int);

    // 调用 arr_max 函数找到最大值
    arr_max(a, len, &max);

    // 调用 arr_min 函数找到最小值
    arr_min(a, len, &min);

    // 输出最大值和最小值
    printf("最大值为%d   最小值为%d\n", max, min);

    return 0;
}

// 函数定义:找到数组中的最大值并存储到 max 中
void arr_max(int *a, int n, int *max) {
    // 假设数组的第一个元素为最大值
    *max = a[0];
    
    // 遍历数组的每一个元素
    for (int i = 1; i < n; i++) {
        // 如果当前元素比已知最大值大,更新最大值
        if (*max < *(a + i)) {
            *max = *(a + i);
        }
    }
}

// 函数定义:找到数组中的最小值并存储到 min 中
void arr_min(int *a, int n, int *min) {
    // 假设数组的第一个元素为最小值
    *min = a[0];
    
    // 遍历数组的每一个元素
    for (int i = 1; i < n; i++) {
        // 如果当前元素比已知最小值小,更新最小值
        if (*min > a[i]) {
            *min = *(a + i);
        }
    }
}

结果展示:

5.用指针接收函数参数,编程序求二维数组的输入、输出、求最大值

思路:1》主函数中定义二维数组 int a[3][4];

  2》自定义函数void arr_input(int (*a)[4] , int H , int L);

  3》自定义函数void arr_output(int (*a)[4] , int H , int L);

  4》自定义函数void arr_max(int (*a)[4] , int H , int L);

  5》主函数调用函数实现

解答:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// 函数声明:用于输入二维数组元素
void arr_input(int (*a)[4], int H, int L);
// 函数声明:用于输出二维数组元素
void arr_output(int (*a)[4], int H, int L);
// 函数声明:用于找到二维数组中的最大值
void arr_max(int (*a)[4], int H, int L);

int main(int argc, const char *argv[]) {
    int a[3][4];  // 定义一个 3x4 的二维数组
    
    // 调用函数,输入、输出和查找最大值
    arr_input(a, 3, 4);  // 输入数组元素
    arr_output(a, 3, 4); // 输出数组元素
    arr_max(a, 3, 4);    // 查找并输出数组中的最大值
    
    return 0;
}

// 函数定义:输入二维数组的元素
// 参数:二维数组指针 int (*a)[4],数组的行数 H 和列数 L
void arr_input(int (*a)[4], int H, int L) {
    // 遍历二维数组的每一行和每一列,依次输入元素
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < L; j++) {
            // 通过指针输入元素 *(a+i) 指向第 i 行,+j 指向第 j 列
            scanf("%d", *(a + i) + j);
        }
    }
}

// 函数定义:输出二维数组的元素
// 参数:二维数组指针 int (*a)[4],数组的行数 H 和列数 L
void arr_output(int (*a)[4], int H, int L) {
    // 遍历二维数组的每一行和每一列,依次输出元素
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < L; j++) {
            // 通过指针输出元素,*(a+i)+j 指向二维数组的具体元素
            printf("%5d", *(*(a + i) + j));
        }
        printf("\n");  // 输出换行符,分隔每一行
    }
}

// 函数定义:找到二维数组中的最大值并输出
// 参数:二维数组指针 int (*a)[4],数组的行数 H 和列数 L
void arr_max(int (*a)[4], int H, int L) {
    // 初始化 max 为数组的第一个元素
    int max = *(*(a)); 
    
    // 遍历二维数组的每一行和每一列,查找最大值
    for (int i = 0; i < H; i++) {
        for (int j = 0; j < L; j++) {
            // 如果找到比当前 max 更大的元素,更新 max
            if (max < *(*(a + i) + j)) {
                max = *(*(a + i) + j);
            }
        }
    }
    // 输出最大值
    printf("最大值为 %d\n", max);
}

 结果展示:

三、总结

1. 学习内容概述

指针数组

理解了如何定义和使用指针数组,指针数组是数组的元素为指针的数组,常用于存储字符串数组.

函数指针

学习了如何定义函数指针及其用途,函数指针可以指向一个函数,并通过指针调用该函数,这对于实现回调机制或动态函数调用非常有用。

宏定义

掌握了如何通过`#define`指令进行宏定义,宏定义可以用于定义常量、简单的函数和代码块,提高代码的可读性和可维护性。

自定义命令

学习了如何在终端中创建并使用自定义命令,便于简化重复性操作,提升开发效率。

2. 学习难点

函数指针的使用

函数指针本身的定义和调用机制较为复杂,尤其是将其作为参数传递给其他函数时,理解函数指针与普通指针的区别和使用场景是一个难点。

指针数组与数组指针的区别

在实际使用中,指针数组和数组指针容易混淆。指针数组是数组的元素为指针,而数组指针则是指向数组的指针,需要通过不同的方式访问元素。

条件编译的灵活性

条件编译允许根据不同条件选择性编译代码块,虽然灵活,但也需要对项目的整体结构和预处理流程有清晰的理解,以避免逻辑混乱或错误。

3. 注意事项

函数指针的声明和使用

函数指针的声明语法较为复杂,尤其是在嵌套使用时,容易产生混淆。建议先清晰理解函数指针的基本定义和用法,然后逐步应用到更复杂的场景中。

指针数组与数组指针的区别

在使用过程中,要明确区分这两者的作用及其内存分布情况。例如,指针数组可以直接用下标访问其中的指针,而数组指针则需要先解引用才能访问数组中的元素。

宏定义的边界条件

在定义宏时,确保考虑到所有边界条件,使用括号包裹宏参数和表达式以防止求值优先级问题。另外,宏不要过度复杂化,以免影响代码的可读性和维护性。

自定义命令的命名规范

在创建自定义命令时,确保命名合理,不要与系统内置命令冲突,且命令的功能要与其命名相符,方便日后调用和维护。

 4. 未来学习的重点

深入学习函数指针与回调函数

函数指针可以用于更复杂的编程场景,特别是回调函数和动态链接库的实现。在后续学习中可以深入研究其在大型系统中的应用。

宏定义的高级用法

进一步学习宏的条件编译和递归展开的用法,尤其是复杂宏定义中的使用技巧,以及如何避免宏定义带来的副作用。

指针在数据结构中的应用

指针是C语言中构建动态数据结构(如链表、树等)的基础,在深入理解指针操作后,可以进一步学习如何通过指针实现这些数据结构的增删查改操作。

代码优化与重构

通过自定义命令、函数指针、宏定义等手段,可以实现代码的优化与重构,提升程序运行效率和可维护性,建议在今后的学习中将这些技巧应用到实际项目中,积累经验。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值