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

C语言06 |数组笔记

目录

  • 一、数组基础
    • 1.1 三种定义与初始化方式
      • 方式1:只指定长度,不赋值
      • 方式2:省略长度,完全初始化
      • 方式3:指定长度,部分初始化
    • 1.2.数组遍历与下标规则
  • 二、数组的内存底层原理
  • 三、数组传参
  • 四、练习
    • 4.1 基础
      • 求数组最大值
      • 求和、平均数与统计
    • 4.2 查找算法
      • 顺序查找
      • 二分查找
    • 4.3 排序算法
      • 冒泡排序
      • 选择排序
    • 4.4 进阶
      • 数组反转
      • 随机打乱(洗牌算法)
  • 五、易错

一、数组基础

1.1 三种定义与初始化方式

数组基本语法:数据类型 数组名[长度] = {初始值};

方式1:只指定长度,不赋值

intarr1[80];
  • 定义了可存放80个int的数组
  • 注意:局部数组不手动初始化,里面是随机垃圾值,不是0!

方式2:省略长度,完全初始化

intarr2[]={1,2,3};
  • 编译器会自动根据初始值数量,把数组长度定为3
  • 最常用的写法,不容易写错长度

方式3:指定长度,部分初始化

intarr3[5]={1,2,3};
  • 只给前3个元素赋值,剩下的元素系统自动补0
  • 实用技巧:int arr[100] = {0};可以一键把整个数组清0

1.2.数组遍历与下标规则

数组通过索引访问单个元素,从0开始
比如长度为5的数组,合法下标是0~4,第1个元素是arr[0],最后一个是arr[4]

想把数组所有元素都打印出来,就要用循环遍历:

#include<stdio.h>intmain(){intarr[]={1,2,3,4,5};intlen=sizeof(arr)/sizeof(arr[0]);// 计算数组长度for(inti=0;i<len;i++){printf("%d ",arr[i]);}return0;}

运行结果:

1 2 3 4 5
  • sizeof(arr)得到数组总字节数,除以单个元素字节数就是元素个数

二、数组的内存底层原理

很多人学数组只停留在“会用”,理解了内存逻辑,后续学指针才不会懵。
我们通过代码打印每个元素的地址,看看规律:

#include<stdio.h>intmain(){intarr[]={1,2,3};printf("数组名地址:%p\n",arr);printf("arr[0]地址:%p\n",&arr[0]);printf("arr[1]地址:%p\n",&arr[1]);printf("arr[2]地址:%p\n",&arr[2]);return0;}

运行结果示例(地址每次运行不同,但规律一致):

数组名地址:000000000061FE0C arr[0]地址:000000000061FE0C arr[1]地址:000000000061FE10 arr[2]地址:000000000061FE14

结论

  1. 数组名本质就是首地址,和&arr[0]的值完全一样,指向第0个元素
  2. int占4个字节,每个元素地址依次相差4
  3. arr[i]的底层逻辑:首地址 + i × 单个元素大小,下标就是偏移量

三、数组传参

把数组传给函数是高频操作,但这里有个经典大坑,一定要记牢。

先看一段代码:

#include<stdio.h>voidprintArr(intarr[],intlen);intmain(){intarr[]={1,2,3,4,5};intlen=sizeof(arr)/sizeof(arr[0]);printf("main中数组大小:%zu字节\n",sizeof(arr));printArr(arr,len);return0;}voidprintArr(intarr[],intlen){printf("函数中数组大小:%zu字节\n",sizeof(arr));for(inti=0;i<len;i++)printf("%d ",arr[i]);printf("\n");}

64位环境运行结果:

main中数组大小:20字节 函数中数组大小:8字节 1 2 3 4 5

为什么会这样?

数组作为函数参数时,会退化为指针
函数里的arr只是一个存地址的指针变量,sizeof得到的是指针大小(32位4字节,64位8字节),不是整个数组的大小。

重点

把数组传给函数时,必须同时把数组长度一起传过去,函数内部无法自己算出数组长度。


四、练习

4.1 基础

求数组最大值

题目:给定数组{33, 5, 22, 44, 55},找出最大值并打印。
思路:先假设第0个元素是最大值,遍历数组挨个比较,遇到更大的就更新。

完整代码:

#include<stdio.h>intmain(){intarr[]={33,5,22,44,55};intlen=sizeof(arr)/sizeof(arr[0]);intmax=arr[0];for(inti=1;i<len;i++){if(arr[i]>max)max=arr[i];}printf("最大值:%d\n",max);return0;}

运行结果:

最大值:55

求和、平均数与统计

题目:生成10个1~100的不重复随机数,计算总和、平均数,并统计有多少个数小于平均数。

完整代码:

#include<stdio.h>#include<stdlib.h>#include<time.h>// 判断数字是否已在数组中,存在返回1,不存在返回0intcontains(intarr[],intlen,intnum);intmain(){intarr[10]={0};intlen=sizeof(arr)/sizeof(arr[0]);srand(time(NULL));// 生成不重复随机数for(inti=0;i<len;){intnum=rand()%100+1;intflag=contains(arr,len,num)if(!flag){arr[i]=num;i++;}}// 打印数组printf("生成的数组:");for(inti=0;i<len;i++)printf("%d ",arr[i]);printf("\n");// 求和intsum=0;for(inti=0;i<len;i++)sum+=arr[i];// 求平均数doubleavg=(double)sum/len;printf("总和:%d,平均数:%.2f\n",sum,avg);// 统计小于平均数的个数intcount=0;for(inti=0;i<len;i++){if(arr[i]<avg)count++;}printf("小于平均数的数有:%d个\n",count);return0;}intcontains(intarr[],intlen,intnum){for(inti=0;i<len;i++){if(arr[i]==num)return1;}return0;}

运行结果:

生成的数组:42 68 35 1 70 25 79 59 63 65 总和:507,平均数:50.70 小于平均数的数有:4个

4.2 查找算法

顺序查找

适用场景:乱序、有序数组都能用,适合数据量小的情况
思路:从第0个元素开始挨个比对,找到就返回下标,遍历完没找到返回-1。

题目:在数组{1,2,3,4,5}中查找数字4的下标。

完整代码:

#include<stdio.h>intorderSearch(intarr[],intlen,intnum);intmain(){intarr[]={1,2,3,4,5};intlen=sizeof(arr)/sizeof(arr[0]);intnum=4;intindex=orderSearch(arr,len,num);printf("目标数字%d的下标:%d\n",num,index);return0;}intorderSearch(intarr[],intlen,intnum){for(inti=0;i<len;i++){if(arr[i]==num)returni;// 找到,返回下标}return-1;// 没找到,返回-1}

运行结果:

目标数字4的下标:3

二分查找

适用场景:必须是有序数组,数据量越大效率越高
核心思路:每次取中间元素和目标比较,每次排除一半的查找范围,效率远高于顺序查找。

题目:在升序数组{7,23,79,81,103,127,131,147}中,查找数字131的下标。

#include<stdio.h>intbinarySearch(intarr[],intlen,intnum);intmain(){intarr[]={7,23,79,81,103,127,131,147};intlen=sizeof(arr)/sizeof(arr[0]);intnum=131;intindex=binarySearch(arr,len,num);printf("目标数字%d的下标:%d\n",num,index);return0;}intbinarySearch(intarr[],intlen,intnum){intmin=0;// 左边界intmax=len-1;// 右边界while(min<=max){intmid=(min+max)/2;// 计算中间下标if(num>arr[mid])min=mid+1;// 目标比中间大,去右半边找elseif(num<arr[mid])max=mid-1;// 目标比中间小,去左半边找elsereturnmid;// 找到,返回下标}return-1;// 没找到}

运行结果:

目标数字131的下标:6

补充:也可以用for循环实现相同逻辑,本质都是控制左右边界收缩,while写法更符合二分查找的语义,更常用。
注意:二分查找的前提是数组有序,乱序数组不能直接使用。


4.3 排序算法

排序是数组的经典应用,面试和日常开发都很常见。

冒泡排序

核心思想:相邻元素两两比较,大的往后交换;每一轮结束,当前最大的数会“冒”到末尾。
n个元素只需要排n-1轮,每轮比较次数逐轮减少。

题目:把数组{3,5,2,1,4}按从小到大升序排列。

完整代码:

#include<stdio.h>intmain(){intarr[]={3,5,2,1,4};intlen=sizeof(arr)/sizeof(arr[0]);// 外层循环:控制轮数,n个数排n-1轮for(intj=0;j<len-1;j++){// 内层循环:每轮两两比较,末尾已排好的不用再比for(inti=0;i<len-1-j;i++){if(arr[i]>arr[i+1]){inttemp=arr[i];arr[i]=arr[i+1];arr[i+1]=temp;}}}// 打印排序结果for(inti=0;i<len;i++)printf("%d ",arr[i]);return0;}

运行结果:

1 2 3 4 5

选择排序

核心思想:从第0个位置开始,和后面所有元素比较,找到最小的换到当前位置;
下一轮从第1个位置开始重复,直到所有元素排好。相比冒泡排序,交换次数更少。

题目:把数组{3,5,2,1,4}按升序排列。

完整代码:

#include<stdio.h>intmain(){intarr[]={3,5,2,1,4};intlen=sizeof(arr)/sizeof(arr[0]);// 外层循环:控制当前要确定的位置for(inti=0;i<len-1;i++){// 内层循环:和后面所有元素比,找最小的for(intj=i+1;j<len;j++){if(arr[i]>arr[j]){inttemp=arr[i];arr[i]=arr[j];arr[j]=temp;}}}for(inti=0;i<len;i++)printf("%d ",arr[i]);return0;}

运行结果:

1 2 3 4 5

4.4 进阶

数组反转

思路:双指针法,一个指头一个指尾,交换元素后头后移、尾前移,直到相遇。
题目:把数组{1,2,3,4,5}反转成{5,4,3,2,1}

完整代码:

#include<stdio.h>intmain(){intarr[]={1,2,3,4,5};intlen=sizeof(arr)/sizeof(arr[0]);inti=0;intj=len-1;while(i<j){inttemp=arr[i];arr[i]=arr[j];arr[j]=temp;i++;j--;}for(inti=0;i<len;i++)printf("%d ",arr[i]);return0;}

运行结果:

5 4 3 2 1

随机打乱(洗牌算法)

思路:遍历每个位置,每次生成一个随机下标,和当前位置交换元素。

完整代码:

#include<stdio.h>#include<stdlib.h>#include<time.h>intmain(){intarr[]={1,2,3,4,5};intlen=sizeof(arr)/sizeof(arr[0]);srand((unsignedint)time(NULL));for(inti=0;i<len;i++){intrnd=rand()%len;// 生成随机下标inttemp=arr[i];arr[i]=arr[rnd];arr[rnd]=temp;}for(inti=0;i<len;i++)printf("%d ",arr[i]);return0;}

运行结果示例:

3 1 5 2 4

五、易错

  1. 下标越界
    长度为n的数组,下标范围是0~n-1。越界不会直接报错,但会破坏内存数据,导致程序异常。

  2. 数组不能整体赋值
    只能在定义时初始化,定义完成后不能用arr = {1,2,3}这种写法赋值。

  3. 函数里用sizeof算数组长度
    数组传参会退化为指针,sizeof得到的是指针大小,不是数组总大小。传数组必须同时传长度。

  4. 局部数组不初始化是垃圾值
    只有部分初始化时,剩余元素才会自动补0;完全不初始化的局部数组,里面是随机值。

  5. 二分查找必须用在有序数组
    乱序数组直接用二分查找会得到错误结果,必须先排序再查找。

如果这篇文章对你有帮助,欢迎点赞收藏关注,后续会更新更多C语言入门干货~

http://www.jsqmd.com/news/1311211/

相关文章:

  • 2026 年 7 月新发布:霍城专业的中央空调新风系统安装施工公司电话,你家新房装这套能让空气变甜的设备,到底要花多少冤枉钱?-博力久能暖通 - 企业推荐管【认证】
  • SSDTTime:黑苹果ACPI补丁的一站式解决方案
  • Godot引擎PluginScript原理:深度集成Lua脚本的架构设计与实现
  • 2026 年平潭到兴安盟汽车托运公司选哪家,你还不知道的本地车辆长途转运门道,兴安盟汽车托运竟藏着这么多学问!-兴运通达轿车托运 - 鉴选官
  • reComputer R1100刷机指南:从强制恢复到系统定制,掌握Jetson Orin NX边缘AI设备部署
  • HarmonyOS NEXT 企业级记账APP:Canvas 绘制折线图
  • 从混沌到秩序:构建海量非结构化数据智能处理平台
  • PyTorch模型在NPU上训练:从环境搭建到性能调优实战指南
  • 好书推荐 ▏儿童诗集《醉享爱的光阴》 金融作家虹笙 著
  • 数字孪生软件选型实战指南:12款工具深度解析与避坑路线图
  • 贾子新体系战略落地问题与免疫机制总论 |Strategic Implementation Problems and Immune Mechanisms of the Kucius New System
  • 实操手册-OpenClaw备用模型机制
  • LeetCode 0486.预测赢家:深度优先搜索(DFS)
  • 非标LCD屏驱动实战:从HDMI/Type-C接口到RK3588系统集成
  • 智选波段主 同花顺期货通指标
  • 2026年万能断路器回收厂家怎么选?重庆本地正规回收企业推荐指南 - 优质品牌商家
  • Hive数组高阶应用:从建模到性能优化的实战指南
  • 数学奇点全解析:从函数失效到系统平衡,理解技术中的临界点
  • 去AI痕迹怎么操作?2026年论文AI率从70%降到8%的实测记录
  • classpath到底是干嘛的
  • 期货分割趋势 同花顺期货通指标
  • 工业树莓派reComputer R20xx eMMC系统刷写全攻略:从原理到实践
  • 贾子理论新学术体系:可持续运营、反垄断与民间求真者组织的三大免疫机制
  • 数组传参、指针函数、函数指针
  • 大数据转大模型:算法是入场券,权限日志才是护城河
  • Node.js Excel读写全攻略:从SheetJS/xlsx入门到实战应用
  • 2026 年怀化可靠的市政管道公司有哪些,楼下那根看不见的管子,竟藏着关乎你家钱包的大秘密?-禹顺管道 - 实业推荐官【官方】
  • 华为MetaERP 在 Fusion 里“用 AutoAccounting 派生项目利润中心“这个说法需要稍微修正一下:Fusion PPM(项目组合管理)的会计分录不再走传统的 AutoAccoun
  • LSTM时间序列预测中滑动窗口的陷阱与最佳实践
  • 桓台宾馆(中心大街县政府店)的6个产品特色体验分享