尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

C语言06 |数组笔记

C语言06 |数组笔记
📅 发布时间:2026/8/2 4:40:32

目录

  • 一、数组基础
    • 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语言入门干货~

相关新闻

  • Nginx 1.18.0 生产环境部署与核心配置深度解析
  • Power BI数据建模核心:表间关系创建、管理与优化实战指南
  • LeetCode 0486.预测赢家:深度优先搜索(DFS)

最新新闻

  • OB复盘分析:7/1/7辛德拉为何输掉比赛?从个人操作到团队决策的破局思考
  • 家用艺术涂料选购与施工全攻略:新手也能避开90%的坑
  • AI插件重构软件价值链:从VSCode插件到SaaS安全的新范式
  • MiniMax H3 效果展示与能力评测大纲
  • Altium Designer PCB层叠设计全解析:从核心概念到Gerber输出避坑指南
  • AI生成汇报级PPT难点与落地实践

日新闻

  • 怀化母婴除甲醛公司测甲醛中心怎么选:康之居母婴除甲醛标准、流程、避坑指南 - 信誉隆金银铂奢回收
  • 三步打造你的终极音乐中心:foobox-cn网络电台功能完整指南
  • Lance湖仓格式:为多模态AI工作流设计的终极数据存储方案

周新闻

  • 怀化母婴除甲醛公司测甲醛中心怎么选:康之居母婴除甲醛标准、流程、避坑指南 - 信誉隆金银铂奢回收
  • 三步打造你的终极音乐中心:foobox-cn网络电台功能完整指南
  • Lance湖仓格式:为多模态AI工作流设计的终极数据存储方案

月新闻

  • ClickHouse版本管理深度实战:4步构建零风险升级与回滚体系
  • Java 23 种设计模式:从踩坑到精通 | 番外:责任链模式 —— 物流审批流程实战
  • 华硕笔记本性能解放指南:G-Helper轻量级控制工具全面解析

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号