当前位置: 首页 > news >正文

C语言:20250717笔记

内容提要

  • 数组

    • 数组的概念

    • 一维数组

    • 排序算法:冒泡排序

    • 二维数组

    • 字符数组

数组

数组的引入

  • 如果要在程序中保存一个人的年龄?如何保存?

    答:创建一个基于int类型的变量即可,举例:int age = 21

  • 如果要在程序中保存一个人的三门课的成绩?如何保存?

    答:创建三个基于float类型的变量,举例:float score1, score2,score3;

    问:保存一个人15门课程的成绩?如何保存?需要用到一个新的知识点:数组

数组的概念

什么是数组

定义:数组是相同类型有序数据的结合。

数组的特征
  • 数组中的数据被称之为数组的元素(所谓的元素,其实就是数组的每一个匿名的变量空间),是同构。

  • 数组中的元素存放在内存空间(char player_name[6]:申请在内存中开辟6块连续的基于char型的变量空间)

char a[6]; short b[3]这两个在内存中申请空间相同

衍生概念:下标(索引)
  • 下标或者索引代表了数组中元素距离第1个元素(首地址所在的元素)的偏移量。举例:第1个元素距离第1个元素的偏移量是0,所以数组中的下标是从0开始的。

  • 数组的下标从零开始:

数组的最大下标 = 数组的元素个数(数组的大小或容量) -1

int a:在内存中开辟1块空间,该空间的大小是4个字节。

int a1,a2,a3,a4,a5:在内存中开辟连续的5块空间,每一块空间的大小是4个字节。但是不如数组方便。

int arr[5]:在内存中开辟连续的5块空间,每一块空间的大小是4个字节。

一维数组

数组的定义

语法:

数据类型 数组名[数据容量];

注意:数据类型又被称作类型说明符,数组容量又被称作数组元素个数或者数组的大小/长度。

说明:

  • 数组的数据类型由数组中的元素来决定。也就是说数据类型,由元素的类型来决定,元素是什么类型,数组就是什么类型。同一个数组中,所有元素的类型都是一致的。

  • 数组名也是标识符,我们所说的数组(名),大家可以理解为数据类型是数组的变量(名)。命名规则与变量的规则一样,唯一的区别是变量使用单数,数组使用复数。也就是以字母或者下划线开头,后面只能跟字母、数字、下划线。

  • 数组容量还可以叫做常量表达式。其值必须是整数。关于数组容量的类型:

    • c89标准:只支持常量和符号常量,不支持标量。

#define SIZE 5  //符号常量,使用宏定义​int lenght = 5;  // 变量​int arr1[5];     // 常量(字面量)正确int arr2[SIZE];  // 符号常量,正确int arr3[length];// 变量,C89错误
  • C99标准(大部分环境支持):引入变长数组(VLA)的概念,就是可以使用变量,数组在运行的时候决定大小。举例:

 int length = 5;  // length = 5; 创建一个变量length,赋值5int arr[length]; // 创建一个容量为5的数组,C99标准下是正确的(执行这句的代码的时候,已经在内存申请空间)length = 10;     // 此时虽然变量length的值变成了10,但是已经创建的数组的大小是不会改变的。数组大小依然是5

类型:

代表了数组中元素的类型,数组的空间大小 = 数组中所有元素空间之和。

容量:

数组中能存储多少个元素,数组容量一定是一个整型。

深入理解:

① 定义一个数组,相当于申请了一个可以容纳所指定元素个数的内存单元。所申请的内存单元是连续的。

② 定义一个数组,相当于定义了多个匿名的变量,这些变量可以通过数组名[下标]来访问。

范例:

 // 定义一个数组int arr[10]; // 定义一个存放10个int类型元素的数组

关于数组中元素默认值问题:

  • 全局作用域和static修饰的变量:元素的默认值是0

  • 局部作用域:元素的默认值是随机值,此时强烈建议用户初始化。

    举例:

 #include <stdio.h>​int g_age;  //全局作用域,定义在函数的外面,默认值是0int g_ages[5];//全局作用域,等同于全局变量,元素的默认值是0​int main(int argc,char *argv[]){int p_age;  //局部作用域,函数中定义的所有的变量都属于局部作用域。变量使用前需要初始化int p_ages[5]; //局部作用域,元素的值使用前需要初始化​return 0;}

注意:关于默认值 ,整型和浮点型的默认值是0,字符型的默认值是\0\0对应的ASCII码为0

数组元素的访问

原则:

数组中的元素不能一次性访问所有,只能一个一个的访问。

语法:

  • 取值操作

数组名[下标];
  • 赋值:

数组名[下标] = 值;

举例:

 // 定义一个存储10个元素的int数组int arr[10];​// 给数组的第一个元素进行赋值arr[0] = 88;​// 访问数组的第一个元素int a = arr[0];​// 修改数组中第一个元素的值arr[0] = 66; // 使用66覆盖88​int c = arr[9]; // 如果是一个局部作用域的数组,此时访问的元素的值是 随机值;如果是全局作用域,值是0int b = arr[10];// error,报一个错误:下标越界异常,因为访问了一个未知的存储空间
案例:
  • 需求:利用循环给数组元素a[0]~a[9]赋值0~9,并且要求逆序输出。

  • 代码:

 /*************************************************************************> File Name:    demo01.c> Author:       阮> Description:  > Created Time: 2025年07月17日 星期四 11时42分35秒************************************************************************/​#include <stdio.h>​int main(int argc,char *argv[]){ // 创建一个数组,用来存放0~9int arr[10];​// 计算数组的大小:数组大小 = 数组所有元素的总字节数 / 每一个元素的字节数 需要使用到sizeof运算符int len = sizeof(arr) / sizeof(arr[0]);​// 通过for循环给数组赋予0~9for (int i = 0; i <= 9; i++) arr[i] = i;// 逆序输出数组中的元素:数组最大下标 = 数组大小 - 1// 使用for循环获取数组每一个元素称之为数组的遍历for (int j = len -1; j >= 0; j--) printf("%4d", arr[j]);​printf("\n");​return 0;}
数组的初始化

说明:所谓的初始化,就是定义数组的时候,用指定的数据给对应的元素赋值。

语法:

数据类型 数组名[数组容量] = {...};

注意事项:

  • 数组可以部分初始化:(也就是一个数组中,一旦)

//数组的部分初始化
 int arr[10] = {11,12,13,14,15};int arr[10] = {11,12,13,14,15,0,0,0,0,0};​char arrl[5] = {'a','b','c'}; //推荐写法,等价于下面char arrl[5] = {'a','b','c','\0','\0'}; //等价于下面char arrl[5] = {'a','b','c',0,0}; ​int arr2[5] = {}; //等价于下面第三种写法int arr2[5] = {0}; //等价于下面第三种写法,推荐int arr2[5] = {0,0,0,0,0};
  • 数组根据初始化的元素自动分配大小:

 int arr[] = {11,12,13,14,15}; //推荐写法,等价于下面写法int arr[5] = {11,12,13,14,15};  这两个是等价的
一维数组案例
案例1
  • 需求:求斐波拉契数列,限制在20个。

  • 分析:1,1,2,3,5,8...

  • 代码:

 /*************************************************************************> File Name:    demo02.c> Author:       阮> Description:  > Created Time: 2025年07月17日 星期四 14时37分33秒************************************************************************/​#include <stdio.h>​int main(int argc,char *argv[]){//定义循环变量int i;//定义数组,用来存储20个数列int f[20] = {1,1};​//计算数组大小int len = sizeof(f) / sizeof(f[0]);​for(i = 2 ; i < len ; i++) f[i] = f[i-1] + f[i - 2]; //{1,1,2,3,5}​//遍历数组​for (i = 0;i < len ;i++){//一行显示五个if(i > 0 && i % 5 == 0)printf("\n");printf("%8d",f[i]);}​printf("\n");​return 0;}​

结果:

案例2

  • 需求:从键盘输入年、月、日,计算并输出该日是该年第几天。

  • 分析:

    • 首先创建一个数组,用来存放每一个月的天数,因为二月特殊,初始化的时候,默认为平年天数。

    • 从控制台输入年,月,日

    • 闰年校验:如果是闰年,就修改数组中二月份对应的天数(平年:28天,闰年:29天)。

    • 定义一个变量,用来记录天数,默认就是我们输入的天数。

    • 遍历数组,将输入月份之前的每一个月的天数取出来加到记录天数的变量中。

    • 将统计后的天数打印输出。

  • 代码:

  /*************************************************************************> File Name:    demo03.c> Author:       阮> Description:  > Created Time: 2025年07月17日 星期四 14时53分41秒************************************************************************/​#include <stdio.h>​int main(int argc,char *argv[]){int t[] = {31,28,31,30,31,30,31,31,30,31,30,31};​int year,month,day;​printf("请输入年,月,日(yyyy-mm-dd):");scanf("%d-%d-%d",&year,&month,&day);​if (year %4 ==0 && year % 100 != 0 || year % 400 == 0)t[1] = 29;​int sum = day;​for(int i = 0;i < month - 1; i++) sum += t[i];​printf("%d月%d日是%d年的第%d天\n",month,day,year,sum);​​return 0;}
结果:

冒泡排序
  • 排序思想(向前冒泡):

    • 一次只排好一个数,针对n个数,最差情况需要n-1次就可以排好,最好情况需要0次(交换位置)

    • 每次排序假定第一个元素是最大或者最小的,然后相邻的两个元素依次进行比较,遇到较大或者较小的元素进行交换,访问完数组的最后一个元素,就排好了一个数。

    • 在余下的元素中,再次应用第二步操作,直到只剩下1个数

  • 推理:

  • 例如:将5,4,3,2,1冒泡排序为1,2,3,4,5

    排序演示:


    第0轮:5,4,3,2,1 → 4,3,2,1,5 比较4次 = 数组长度5 - 轮数0 - 1

    第1轮:4,3,2,1,5 → 3,2,1,4,5 比较3次 = 数组长度5 - 轮数1 - 1

    第2轮:3,2,1,4,5 → 2,1,3,4,5 比较2次 = 数组长度5 - 轮数2 - 1

    第3轮:2,1,3,4,5 → 1,2,3,4,5 比较1次 = 数组长度5 - 轮数3 - 1

  • 总结:

    • 案例涉及到5个数的排序,排序了4轮,得到:轮数 = 元素个数(数组大小)- 1,我们可以通过一个外层for循环实现轮数的遍历。

    • 案例涉及的每一轮中数列的排序次数,得到:次数 = 元素个数 - 轮数 [- 1],我们可以通过一个内层for循环实现每一轮次数的遍历。

    • 每一次比较过程中,两个数涉及到位置交换,比如 a = 3, b = 4,交换ab的数据变为 a = 4,b = 3,应该如何实现:

      • 引入一个临时变量temp,将a的值赋值给temp,int temp = a;

      • 将b的值赋值给a, a = b;

      • 将temp的值赋值给b, b = temp;

  • 代码:

 /*************************************************************************> File Name:    demo04.c> Author:       阮> Description:  > Created Time: 2025年07月17日 星期四 16时11分21秒************************************************************************/​#include <stdio.h>​int main(int argc,char *argv[]){// 创建一个数组,用来存放冒泡排序的数列int arr[10];​//循环变量和临时变量int i,j,temp,desc = 1;​printf("请输入10个整数:\n");​//计算数组的大小​int len = sizeof(arr) / sizeof(arr[0]);​//控制台输入10个数字for (i= 0;i < len; i++)scanf("%d",&arr[i]);//&arr[i]: []的优先级高于&​printf("\n排序前:");for (i = 0;i < len ;i++)printf("%-4d",arr[i]);printf("\n");​//冒泡排序//外层循环:实现排序轮数的遍历:轮数=数组大小 - 1for ( i = 0;i<len - 1; i++){//设置一个flag,用int flag = 0;//内层循环:实现每一轮比较次数:比较次数 = 数组大小 - 轮数 - 1for (j= 0; j <len -i -1; j++){//相邻的两个数比较,满足交换条件,就要交换位置//降序排序:if(arr[j] < arr[j+1])//升序排序:if(arr[j] > arr[j+1])if (desc){if(arr[j] < arr[j+1]){temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;flag = 1;}}else{//升序if(arr[j] > arr[j+1]){temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;flag = 1;}​}}​if (!flag) break; //1,2,3}printf("\n排序后:");for(i = 0; i < len; i++) printf("%-4d",arr[i]);printf("\n");return 0;}
结果:

  • 衍生:

冒泡排序 → 鸡尾酒排序、摇坠排序、摇床排序、搅拌排序...

http://www.dtcms.com/a/283679.html

相关文章:

  • Redis深度解析:从缓存原理到高并发实战
  • AI算法机器学习主要类型
  • 专业云端视觉计算解决方案:云渲染云电脑
  • 【AI论文】基于反射生成模型的测试时动态缩放方法
  • 【软件测试】软件测试分类与方法解析:目标到工具
  • HANA SQLScript中的变量类型汇总
  • 云原生环境下的安全控制框架设计
  • USB导出功能(QT)
  • Windows10笔记本电脑开启BIOS
  • 云手机网络加速全攻略:解决游戏卡顿与APP连接失败困扰
  • 玖[9],相机/镜头/光源
  • yolo位置损失中的权重项的作用是什么
  • YOLO融合[CVPR2025]EVSSM中的EDFFN模块
  • LeetCode20
  • 2D视觉系统标定流程与关键要求
  • 不同相机CMOS噪点对荧光计算的影响
  • 前端设计模式应用精析
  • Java零基础快速入门
  • Python应用指南:使用PyKrige包实现ArcGIS的克里金插值法
  • Ceph OSD.419 故障分析
  • git的cherry-pick
  • AI安全威胁之MCP Server投毒攻击实践
  • Git 多人协作实战:从基础操作到分支管理全流程记录
  • LiteSQL:让C++与数据库无缝对接的ORM利器
  • 物联网主机在化工园区安全风险智能化管控平台中的应用
  • 2025TGRS多尺度稀疏交叉注意力网络
  • 如何在PyCharm中删除虚拟环境
  • 建立框架思维
  • 锂电池制造行业MES特色解决方案:差异化生产管控与智能工厂实践
  • 深入理解Map.Entry.comparingByValue()和Map.Entry.comparingByKey()