c语言3月14日学习总结

本文详细介绍了C语言中数组元素的使用方法,包括赋值、取值、运算及函数参数传递。通过实例展示了如何初始化数组并用函数求数组的和、最大值、最小值和平均值,同时介绍了冒泡排序、选择排序和二分法查找算法。还讨论了二维数组的概念、初始化方法及其在函数参数中的应用,最后以迷宫游戏为例,展示了二维数组的实际应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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");
<think>嗯,用户让我介绍一下C语言万年历系统的总结,大概八百字。首先,我得确定用户的需求是什么。可能是一个学生,正在学习C语言,需要完成一个项目或者作业,写一个万年历系统。用户需要的是对这个系统的总结,可能包括设计思路、实现方法、关键技术和遇到的问题等。 首先,我需要回忆一下C语言万年历系统的基本结构。通常,这样的系统需要处理期计算,比如判断某一天是星期几,某个月有多少天,闰年的判断等等。然后,用户可能需要一个界面来显示月历,可能还有查询功能,比如输入年份和月份来显示对应的历。 接下来,我应该考虑如何组织这八百字的总结。通常,这样的总结会包括以下几个部分:引言、设计目标、实现步骤、关键技术、遇到的问题及解决方法、总结与展望。用户可能希望结构清晰,逐步说明如何构建这个系统。 在引言部分,可能需要介绍万年历系统的作用,比如帮助用户查询期、星期,或者作为学习C语言的实践项目。设计目标部分,可以说明系统需要实现哪些功能,比如显示任意年月的历,支持用户输入,正确计算闰年等。 实现步骤方面,应该分模块来写。比如,首先处理期计算模块,包括闰年判断,某个月的天数计算,确定某一天是星期几的算法(比如蔡勒公式或者基姆拉尔森计算公式)。然后是用户输入模块,确保输入的年份和月份有效。接着是显示模块,将计算出的期按格式排列成月历的形式。 关键技术部分,需要详细说明期计算的方法。例如,闰年的判断是能被4整除但不能被100整除,或者能被400整除。每个月的天数,尤其是二月的天数在闰年和非闰年不同。确定某个月的第一天是星期几,可以使用基姆拉尔森公式,或者计算从某个基准期开始的总天数,再取模7。 遇到的问题可能包括输入验证,比如用户输入了非法的月份(比如13月),或者错误的年份。还有期计算中的边界情况,比如跨年跨月的处理。此外,显示格式的对齐问题,如何让历整齐排列成每周七天的形式。 解决方法方面,可以提到使用循环和条件语句进行输入验证,直到用户输入正确的数据。在期计算中,确保算法正确处理所有情况,特别是闰年。显示格式上,可以使用制表符或者空格来对齐,或者计算每个星期几的位置,逐行打印。 总结与展望部分,可以评价这个项目的学习价值,比如巩固了C语言的基础语法、函数模块化设计、调试能力等。展望的话,可能提到可以增加更多功能,比如节假标记、提醒功能,或者图形化界面。 现在需要确保内容符合系统级指令,比如数学公式用$...$,比如闰年的判断条件写成$year\%4==0 \&\& year\%100!=0$ || $year\%400==0$。独立公式可能需要用$$...$$,但这里可能用不到太多数学公式,主要是代码逻辑。 另外,用户要求用中文回答,结构清晰,分步骤解决问题。需要避免使用Markdown格式,所以用自然分段和序号。还要注意LaTeX语法的正确性,比如运算符周围的空格,括号匹配等。 可能需要检查是否有遗漏的部分,比如代码结构、函数分解的例子,或者具体算法的解释。例如,基姆拉尔森公式的具体实现,或者如何计算某个月第一天是星期几。 最后,确保总字数控制在八百字左右,不要太长或太短。可能需要调整各部分的比例,突出重点,如关键技术部分详细说明,而其他部分适当简洁。 总结下来,整个思考过程需要覆盖用户可能的背景和需求,确保内容全面且结构合理,符合格式要求,同时用清晰的中文逐步解释万年历系统的实现和总结。</think>以下为C语言万年历系统的技术总结(约800字): --- ### 一、系统设计目标 C语言万年历系统是通过控制台实现的期查询工具,核心功能包括: 1. 显示任意年份/月份的历 2. 自动计算星期分布 3. 支持闰年判断 4. 提供用户友好的交互界面 ### 二、关键技术实现 #### 1. 期计算模块 **(1) 闰年判断算法** 采用标准闰年计算公式: ```c if((year%4==0 && year%100!=0) || year%400==0) return 1; // 闰年 else return 0; ``` **(2) 月份天数计算** 建立数组存储各月天数: ```c int days[] = {31,28,31,30,31,30,31,31,30,31,30,31}; ``` 闰年时二月天数修正为29天 **(3) 星期计算** 使用**蔡勒公式**(Zeller's congruence)计算每月1的星期数: $$ h = \left(q + \left\lfloor\frac{13(m+1)}{5}\right\rfloor + K + \left\lfloor\frac{K}{4}\right\rfloor + \left\lfloor\frac{J}{4}\right\rfloor + 5J\right) \% 7 $$ 其中需处理1月、2月看作上年的13、14月 #### 2. 界面显示模块 **(1) 历排版** ```c printf(" 一 二 三 四 五 六\n"); // 星期标题 for(int i=0;i<weekday;i++) // 首行缩进 printf(" "); for
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值