c语言3月14日学习总结

1.数组元素作为函数参数的使用

/*
    数组元素,单独拿出来就与普通变量一样

    int nums[] = {1, 2, 3};

    nums[0] = 1;

    1)赋值:   nums[0] = 123;
    2)取值:   int res = nums[0];
    3)运算:   nums[0]++;   ===   nums[0] = nums[0] + 1;

    函数参数传递的方式
        如果函数的参数是如例一样有基本类型定义(int,long,float,char...)
        那么函数的调用就为值传递,实际调用时使用的参数是实参.
        在调用中,将实参的数值(内存中存储的值)复制一份,传递给函数的形参

 */

练习:2、写一个程序,初始化一个数组。要求数组长度为10,里面的值为0-9的随机数,并且每一个数字出现一次。

# define LEN 128
    // 1,创建数组与必要的变量
    int nums[LEN], i = 0, temp, index;
    // 2,开始循环创建随机数
    while(i < 10) {
    // 3,生成随机数
    temp = arc4random_uniform(10); // 0-9的随机数

    // 0    i=0  index==i 成立 i++,随机数存到nums[0]中
    // 1    i=1  如过创建的随机数与上一次一样,就等于本次什么也不做
    // 2    i=1  随机数不同,index == i 成立,i++,随机数放到 nums[1] 中


    // 4,判断temp是否在数组中
    for (index = 0; index < i; index++) {
         if(temp == nums[index]) {
         // 表示找到相同的了,即数组中存在
             break;
         }
     }
    // 5,怎么判断是存在呢?
      if(index == i) {
        // for循环正常结束,即不存在
          nums[i++] = temp;
      }
    }


    // 将随机数打印出来即可
    for(int j = 0; j < 10; j++) {
        printf("%d.\t%d\n", j + 1, nums[j]);
    }

2.将数组名作为函数参数的使用

/*
    将数组名作为函数参数
    调用语法:
        int nums[] = {...};
        func(nums);
    需要注意,函数的声明语法为
        返回类型 函数名(数组类型 形参变量名[]);

        void func(int arr[])

    补充说明:
    1)数组名作为函数参数,此时是传递的数组的首地址
    2)传递的时地址,那么成为引用传递
    3)如果传入的时地址,那么在函数中的数组与在函数外的数组是同一个数组
    4)函数传参的过程中,只是将数组的地址传递过去了,数组的长度会丢失
    5)一般数组名作为函数参数的时候,函数会带有第二个参数,用于表示数组的长度
        void func(int arr[], int length);

    有的代码会将数组作为函数参数的函数定义为
        void func(int arr[3], int length); // 针对初学者好理解
        // int *    int []
        void func(int *arr, int length); // 指针的写法

    如果是传递的地址,就称为引用传递.引用传递函数内对数据的修改会在函数结束后保持下来
        void func(int num) {
            num = 10;
        }
        void func(int num[]) {
            num[0] = 10;
        }
 */

练习:初始化一个数组,并用函数求该数组的和,最大值,最小值,平均值


// 写一个可以对数组初始化的函数
void initArray(int nums[], int length) {
    printf("请输入数字\n");
    for (int i = 0; i < length; i++) {
        scanf("%d", &nums[i]);
    }
}
// 写函数去求数组的最大最小\和与平均
int max(int nums[], int length) {
    int maximun = nums[0];
    for (int i = 1; i < length; i++) {
        if(nums[i] > maximun) maximun = nums[i];
    }
    return maximun;
}
int min(int nums[], int length) {
    int minimun = nums[0];
    for (int i = 1; i < length; i++) {
        if(nums[i] < minimun) minimun = nums[i];
    }
    return minimun;
}
int sum(int nums[], int length) {
    int sum = 0;
    for (int i = 0; i < length; i++) {
        sum+=nums[i];
    }
    return sum;
}
double avg(int nums[], int length) {
    return sum(nums, length) * 1.0 / length;
}


int main(int argc, const char * argv[]) {

    int nums[10];

    initArray(nums, 10);


    printf("最大值为%d\n", max(nums, 10));
    printf("最小值为%d\n", min(nums, 10));
    printf("平均值为%lf\n", avg(nums, 10));
    printf("和为%d\n", sum(nums, 10));

3.冒泡排序

冒泡排序的思想:每趟从第一个开始依次比较,选出一个最大的或最小的值排在最后,直到排成有序数列为止.

//推倒思路
// 写一个可以对数组初始化的函数
void initArray(int nums[], int length) {
    printf("请输入数字\n");
    for (int i = 0; i < length; i++) {
        scanf("%d", &nums[i]);
    }
}
// 写函数去求数组的最大最小\和与平均
int max(int nums[], int length) {
    int maximun = nums[0];
    for (int i = 1; i < length; i++) {
        if(nums[i] > maximun) maximun = nums[i];
    }
    return maximun;
}
int min(int nums[], int length) {
    int minimun = nums[0];
    for (int i = 1; i < length; i++) {
        if(nums[i] < minimun) minimun = nums[i];
    }
    return minimun;
}
int sum(int nums[], int length) {
    int sum = 0;
    for (int i = 0; i < length; i++) {
        sum+=nums[i];
    }
    return sum;
}
double avg(int nums[], int length) {
    return sum(nums, length) * 1.0 / length;
}


int main(int argc, const char * argv[]) {

    int nums[10];

    initArray(nums, 10);


    printf("最大值为%d\n", max(nums, 10));
    printf("最小值为%d\n", min(nums, 10));
    printf("平均值为%lf\n", avg(nums, 10));
    printf("和为%d\n", sum(nums, 10));

排序算法代码:

void bubbleSort(int nums[], int length) {
    for (int i = 0; i < length - 1; i++) {
        for (int j = 0; j < length - 1 - i; j++) {
            if(nums[j] > nums[j+1]) {
                int temp = nums[j];
                nums[j] = nums[j+1];
                nums[j+1] = temp;
            }
        }
    }
}

4.选择排序

排序思想:将数列第一个位置的数设为最小或最大,每次与第一个比较,满足条件就放在第一个,再从第二个开始,以此类推.

//推导过程

    for (int i = 0; i < 4; i++) {
        if(nums[0] > nums[i]) {
            temp = nums[0];
            nums[0] = nums[i];
            nums[i] = temp;
        }
    } // 2, 9, 7, 3
    for (int i = 1; i < 4; i++) {
        if(nums[1] > nums[i]) {
            temp = nums[1];
            nums[1] = nums[i];
            nums[i] = temp;
        }
    }// 2, 3, 9, 7
    for (int i = 2; i < 4; i++) {
        if(nums[2] > nums[i]) {
            temp = nums[2];
            nums[2] = nums[i];
            nums[i] = temp;
        }
    }// 2, 3, 7, 9
    for (int i = 3; i < 4; i++) {
        if(nums[3] > nums[i]) {
            temp = nums[3];
            nums[3] = nums[i];
            nums[i] = temp;
        }
    }// 2, 3, 7, 9

选择排序算法代码:

for (int j = 0; j < n - 1; j++) {
        for (int i = j + 1; i < n; i++) {
            if(nums[j] > nums[i]) {
                temp = nums[j];
                nums[j] = nums[i];
                nums[i] = temp;
            }
        }
    }

选择排序算法代码优化:

int min = -1;
    for(int j = 0; j < 4 - 1; j++) {
        min = j; // 记录了最小取值的下标(索引)
        for (int i = j + 1; i < 4; i++) {
            if(nums[min] > nums[i]) {
                min = i;
            }
        }

        // 将最小的与第j项交换
        if(min != j) {
            temp = nums[min];
            nums[min] = nums[j];
            nums[j] = temp;
        }
    }

5.二分法查找(折半查找)

算法思想:将数列第一个元素设为high,最后一个设为low,取mid等于high+low除以2,判断要查找的值比mid所指的元素大还是小,如果大证明在mid右边的区域,将low设为mid+1,如果小则将high-1,以此类推,如果high

// 方法的返回值可以用于表示下标,如为-1表示没有找到
int indexOf(int nums[], int length, int key) {
    int low = 0, high = length - 1, mid;
    while (low <= high) {
        mid = (low + high) / 2;
        int obj = nums[mid];
        if(key == obj) {
            return mid;
        } else if(key > obj) {
            // 我的数据在 mid 到 high 之间
            low = mid + 1;  // 12
        } else {
            // 在 low 与 mid 之间
            high = mid - 1;
        }
    }
    // 说明没有找到
    return -1;
}

6.二维数组

  • 在C语言中,如果某一个数据需要用两个数据才能表示,可以使用二维数组

    语法:
    数组数据类型 数组名[常量表达式][常量表达式];

    元素类型 数组名[行数][列数];
    

    二维数组的初始化
    1)定义的同时初始化
    -> 分段初始化

 int a[2][3] = {
{ 1, 2, 3 }, 
{ 4, 5, 6 }
}; 

-> 连续初始化

int a[2][3] = {
1, 2, 3, 
4, 5, 6
}; 

-> 多维数组可以省略第一个下标

int a[][3] = {
1, 2, 3,
4, 5, 6
};
  • 二维数组的内存结构
  • 二维数组在概念上是二维的,即需要两个下标进行标识。虽说二维数组是一个二维结构,但是在实际硬件存储中依旧是一维的。也就是说,内存结构是线性结构,存储的数据也只能是线性的。那么二维数组是如何存储呢?

由于二维数组可以看做是,元素为一维数组的一维数组。因此内存中先存储数组的第一个元素,而第一个元素又是一个数组,也就是说首先存储这个数组。然后再存储第二个数组。例如:
int a[3][4];
逻辑结构为:
00 01 02 03
10 11 12 13
20 21 22 23

而此处第0个元素为
a[0] 00 01 02 03

因此内存首先存储这个数组,然后存储第1个数组
a[1] 10 11 12 13

最后存储第2个数组
a[2] 20 21 22 23

也就是说内存的物理结构为:
00
01
02
03
10
12
13
20
21
22
23

这里需要注意的是:
1)数组名表示数组的首地址
2)数组的首地址等于第一个数组的首地址
3)数组的首地址也等于第一个元素的首地址

// 二维数组的第一个元素与子数组与二维数组的首地址一样
    // nums[0][0]
    // array[0]

    printf("\n\n\n");

    printf("nums\t\t=\t%p\n", nums);
    printf("nums[0]\t=\t%p\n", nums[0]);
    printf("&nums[0][0]\t=\t%p\n", &nums[0][0]);
    //nums 与 nums[0] 和 nums[0][0]的地址相同

    printf("\n\n\n");

    printf("nums[1]\t=\t%p\n", nums[1]);
    printf("&nums[1][0]\t=\t%p\n", &nums[1][0]);
    //nums[1]与nums[1][0]的地址相同


    printf("\n\n\n");
    int nums[2][3];
    printf("%lu\n", sizeof(nums)); // 24
    printf("%lu\n", sizeof(nums[0])); //12
    printf("%lu\n", sizeof(nums[1])); //12
  • 二维数组名做函数参数
    二维数组名作为函数参数
    数组名表示数组的首地址,因此将数组名作为函数参数是引用传递

需要注意的是:
1)在函数中,数组会丢失长度信息
2)函数定义中,可以省略数组的第一个长度

二维数组名作为函数参数只需要搞清楚函数如何定义
void func(int nums[][列数], int rows, int cloumns);

练习:输入数字初始化二维数组

int  rows, cols;
    printf("请输入两个数字\n");
    scanf("%d", &rows);
    scanf("%d", &cols);

    int num[rows][cols];

    // 利用循环初始化
    for(int i= 0; i< rows; i++) {
        for(int j = 0; j < cols; j++) {
            scanf("%d", &num[i][j]);
        }
    }

    printf("输入完毕,打印结果为\n");

    for(int i= 0; i< rows; i++) {
        for(int j = 0; j < cols; j++) {
            printf("%d\t", num[i][j]);
        }
        printf("\n");
    }

7.迷宫游戏

1、游戏界面简介
“`
{#,#,#,#,#,#},
{#,O,#,#, , },
{#, ,#,#, ,#},
{#, , ,#, ,#},
{#,#, , , ,#},
{#,#,#,#,#,#},


其中 # 代表墙,O 代表人,空白代表路
利用 w,s,a,d 控制小人走出迷宫

这里利用一个二维数组记录迷宫的结构,为例方便编写,假定向下为 x 轴,向右为 y 轴。如此一来,数组就可以定义为 a[x][y]

2、控制说明
W 或 w 代表向上,实际只需要将 x - 1 即可
S 或 s 代表向下,只需要 x + 1
A 或 a 代表向左,只需要 y - 1
D 或 d 代表向右,只用 y + 1 即可

实现代码:

int main(int argc, const char * argv[]) {

    // 1,设计字符数组,用于显示地图与玩家的位置
    char map[ROW][COL]={
        {'#','#','#','#','#','#'},
        {'#','O','#','#',' ',' '},
        {'#',' ','#','#',' ','#'},
        {'#',' ',' ','#',' ','#'},
        {'#','#',' ',' ',' ','#'},
        {'#','#','#','#','#','#'}
    };

    char c, cTemp, temp;
    int i = 1, j = 1;

    while(1) {

        // 2,打印地图
        printMap(map);
        // 判断用户是否赢了
        if(j == COL - 1) break;

        // 3,提示用户输入
        printf("请玩家操作:w(上),s(下),a(左),d(右)\n");
        // 4,获取用户数组
        scanf("%c", &c);
        scanf("%c", &cTemp);
        // 5,判断wsad进行处理
        switch (c) {
            case 'w': // 向上  i - 1
                // 6,判断下一个位置是否可以走
                //      如果可以就走过去(交换空格与0的位置)
                // 7,判断是否已经走出来了
                if(map[i - 1][j] == ' ') {
                    // 可以走
                    // 先将 i,j 与 i-1,j 进行交换
                    temp = map[i][j];
                    map[i][j] = map[i - 1][j];
                    map[i - 1][j] = temp;

                    i--;
                }

                break;
            case 's': // 向下  i + 1
                if(map[i + 1][j] == ' ') {
                    temp = map[i][j];
                    map[i][j] = map[i + 1][j];
                    map[i + 1][j] = temp;

                    i++;
                }

                break;
            case 'a': // 向左  j - 1
                if(map[i][j - 1] == ' ') {
                    temp = map[i][j];
                    map[i][j] = map[i][j - 1];
                    map[i][j - 1] = temp;

                    j--;
                }

                break;
            case 'd': // 向右  j + 1
                if(map[i][j + 1] == ' ') {
                    temp = map[i][j];
                    map[i][j] = map[i][j + 1];
                    map[i][j + 1] = temp;

                    j++;
                }


                break;
        }

    }

    printf("恭喜你通关\n");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值