C的实用笔记20——数组作为函数的参数

1.形参中不存在数组的概念,即便中括号约定数组的大小,也无效

  1. 案例:
    #include <stdio.h>
    void printArr(int arr[10])					//传递进来一个数组,形参用数组的形式来写
    {
        int i;
        for(i=0; i<10; i++){					
            printf("%d ", arr[i]);
        }
        putchar('\n');
        printf("printArr: arr的大小是:%d\n", sizeof(arr));
    }
    int main(int argc, char const *argv[])
    {
        int arr[10] = {1,2,3,4,5,6,7,8,9,10};
        printf("main: arr的大小是:%d\n", sizeof(arr));
        printArr(arr);							//数组名作为函数的实际参数
        return 0;
    }

  2. 运行结果:
  3. 问:我们可以在函数中对数组元素进行调用,但为什么在函数中,数组的长度不是40反而是8呢?
  4. 原因:数组名字作为实参传递给函数时,传递的只是一个地址,是数组的首地址。地址就是指针的概念,不同的编译器,地址所占用的内存大小不同,在GCC编译器中,地址占8个字节(用%p输出能看见16位16进制数);在VS编译器中,地址占4个字节(用%p输出能看见8位16进制数)。     

 

2.做数组相关操作时,除了传递数组首地址之外,还应该传递数组的长度

  1. 原因:主调函数中数组的长度如果发生改变,那么还得去修改函数里面的逻辑,不方便
  2. 改进思路:用sizeof关键字计算数组的长度,然后作为实参传递给函数。
    #include <stdio.h>
    void printArr(int arr[], int len)
    {
        int i;
        for(i=0; i<len; i++){
            printf("%d ", arr[i]);
        }
        putchar('\n');
        printf("printArr: arr的大小是:%d\n", sizeof(arr));
    }
    int main(int argc, char const *argv[])
    {
        int arr[10] = {1,2,3,4,5,6,7,8,9,10};
        int len;
        len = sizeof(arr) / sizeof(arr[0]);
        printf("main: arr的大小是:%d\n", sizeof(arr));
        printArr(arr, len);
        return 0;
    }

3.数组作为函数参数的两种写法

  1. 基本原理:数组的内存中是一块连续的存储区域,数组名代表了数组的首地址。
  2. 写法一:数组的名字作为实参
    printArr(arr, len);

  3. 写法二:数组的首地址作为实参
    printArr(&arr[0], len);

​​​​​​​

4.数组名作为函数参数与普通变量名作为函数参数的区别

不同点:

  1. 数组名作为实参:传递的是一个地址,数组名是数组的首地址。函数中数组元素的改变会直接影响主调函数中数组元素的值。
  2. 普通变量名作为实参:传递的是一个数据。函数中变量的改变不会影响主调函数中变量的值。

相同点:二者都满足:

  1. 满足:函数调用的四个过程(无论是传递地址还是传递数值,都是值传递,只不过一个是地址的数值,一个是数据的数值)。
  2. 满足:形参和实参不是同一个变量,它们只是数值相等,但他们的内存地址不同。虽然说我们传递数组名时,传递的是它的首地址,形参也接收的是首地址,但是注意首地址也是一个数据,那么这两个地址数据又保存在哪里呢?答案是两个不同的内存地址中。
  3. 满足:形参和实参的作用范围不同

 

5.习题

代码心得:

  1. 我们以后会经常听到API:英文是,application Interface,意思是应用程序接口,是函数封装的意思。
  2. 可以将数组的初始化写进一个api,可以将遍历打印数组也写进一个api,等等。

习题1:有两个班级的同学,分别是10个人和5个人,分别求这两个班的平均分。

  1. 思路:
    f1. 封装初始化数组的API:void initArry(int arry[], int len); 形参分别是数组首地址,数组长度
    	f1.1 for循环,表示数组下标的循环变量i从0开始,<len 时,将纳入循环
        	f1.1.1 输入成绩
    f2. 封装打印数组的API:void printArry(int arry[], int len); 形参分别是数组首地址,数组长度
    	f2.1 打印总人数
    	f2.2 for循环,表示数组下标的循环变量i从0开始,<len 时,将纳入循环
        	f2.2.1 打印数组元素值
        f2.3 换行
    f3. 封装获取数组平均数的API:float getAverage(int arry[], int len); 形参分别是数组首地址,数组长度
    	f3.1 for循环,表示数组下标的循环变量i从0开始,<len 时,将纳入循环
        	f3.1.1 修改用于求和的循环变量sum的值: sum += arry[i];
    	f3.2 计算平均值:aver = sum / len;
    	f3.3 返回平均值aver
    1. 定义两个数组,分别代表两个班级
    2. 用sizeof运算符获取数组的长度
    3. 用API1. 对两个数组初始化
    4. 用API2. 打印两个数组
    5. 用API3. 获取两个班级平均数
    6. 打印平均数

  2. 代码:
    #include <stdio.h> 
    void initArry(int arry[], int len);
    void printArry(int arry[], int len);
    float getAverage(int arry[], int len);
    int main(int argc, char const *argv[])
    {
        int classOne[5];
        int classTwo[10];
        float averageOfClassOne;
        float averageOfClassTwo;
        int lenOfClassOne = sizeof(classOne)/sizeof(classOne[0]);
        int lenOfClassTwo = sizeof(classTwo)/sizeof(classTwo[0]);
    
        /* 初始化数组 */
        initArry(classOne, lenOfClassOne);
        initArry(classTwo, lenOfClassTwo);
        /* 打印数组 */
        printArry(classOne, lenOfClassOne);
        printArry(classTwo, lenOfClassTwo);
        /* 计算平均分 */
        averageOfClassOne = getAverage(classOne, lenOfClassOne);
        averageOfClassTwo = getAverage(classTwo, lenOfClassTwo);
    
        printf("一般的平均分:%f\n", averageOfClassOne);
        printf("二班的平均分:%f\n", averageOfClassTwo); 
        return 0;
    }
    void initArry(int arry[], int len)
    {
        int i;
        for(i=0; i<len; i++){
            printf("请输入第%d个学生的成绩:\n", i+1);
            scanf("%d", &arry[i]);
        }
    }
    void printArry(int arry[], int len)
    {
        int i;
        printf("总人数%d个\n", len);
        for(i=0; i<len; i++){
            printf("%d ", arry[i]);
        }
        puts("\n done \n");
    }
    float getAverage(int arry[], int len)
    {
        float aver = 0.0;   //平均分
        float sum = 0;    //总分
        int i;
        for(i=0; i<len; i++){
            sum = sum + arry[i];
        }
        aver = sum / len;
        return aver;
    }

 

习题2:封装冒泡排序法的函数

  1. 思路:回顾冒泡排序法
  2. 代码:
    void bubbleSort_SmallToLarge(int arr[], int len)
    {
        int i, j;   //分别是外、内层循环变量
        int temp;   //用于交换的临时变量
        for(i=0; i<len-1; i++){
            for(j=0; j<len-1-i; j++){   //擂台总是从农村开始摆
                if(arr[j] > arr[j+1]){  //arr[j]是摆擂者,arr[j+1]是被挑战者,大的浮上去,所以用>判断
                    temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }

习题3:封装选择排序法的函数

  1. 思路:回顾选择排序法
  2. 代码:
    void selectionSort_SmallToLarge(int arr[], int len)
    {
        int i, j;   //分别是外、内层循环变量
        int temp;   //用于交换的临时变量
        int sword;  //尚方宝剑
        for (i=0; i<len-1; i++){
            sword = i;  //暂时把尚方宝剑交给第i个人
            for (j=i+1; j<len; j++){    //j每次都从i+1开始,因为一轮开始时尚方宝剑在第i个人手中
                if (arr[sword] < arr[j]){   //尚方宝剑在arr[sword]位置,让arr[j]轮流去挑战,大的夺走sword
                    sword = j;
                }
            }
            if (sword != i){    //判断尚方宝剑是否还在第i个人手中
                temp = arr[i];
                arr[i] = arr[sword];
                arr[sword] = temp;  
            }
        }
    }

 

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值