【C语言 | 数组】C语言数组详解(经典,超详细)
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍C语言的数组🍭
😎金句分享😎:🍭🍭
本文未经允许,不得转发!!!
目录
- 🎄一、了解数组,清楚这五个方面
- ✨1.1 数组所在的内存地址
- ✨1.2 数组的内容
- ✨1.3 数组的类型
- ✨1.4 数组元素的类型
- ✨1.5 数组元素的个数
- 🎄二、数组的几个地址—— a、&a、&a[0]
- 🎄三、不指定数组长度——int a[]={1,2};
- 🎄四、数组初始化
- 🎄五、字符串
- 🎄六、总结
![]()
🎄一、了解数组,清楚这五个方面
如果定义一个基本数据类型变量,我们可以了解到这三个方面的内容:1、变量所在的内存地址; 2、变量的值; 3、变量的类型;
例如:从语句
int i = 1;,我们可以知道:
- 1、编译器分配一块4个字节(sizeof(int))的内存,地址是
&i;- 2、这块内存里面存放了值为4的内容;
- 3、这个变量是
int类型的。
如果定义的是数组,则我们需要清楚四个方面的内容:
- 1、数组所在的内存地址;
- 2、数组的内容;
- 3、数组的类型;
- 4、数组的元素类型;
- 5、数组的元素个数;
✨1.1 数组所在的内存地址
定义了一个任何类型变量,编译器都会为其分配一块内存来存放该变量,起始地址就是 &变量名 ,大小就是该变量的类型的大小。
所以数组也是如此,定义一个数组后,编译器会为该数组分配一块内存。内存大小,就是数组类型的大小。例如:语句int a[5];,编译器会分配一块内存,起始地址可以通过&a来获取,内存大小是20个字节(sizeof(int [5]))。
数组所在的内存地址(数组的地址),就是 &数组名 的值。
✨1.2 数组的内容
数组的内容是指定义数组时,分配的那块内存里存放的东西,与数组元素类型、数组元素个数 有关。
数组的内容就是由若干个 固定大小 的内存块,线性排列组成的一个内存块。这里的若干个就是数组元素个数,固定大小就是sizeof(数组元素类型)。
✨1.3 数组的类型
针对基本数据类型变量 或 指针变量,大部分人都可以轻易指出该变量的类型是什么。
看例子1.3.1:
// array_type.c
char c; // char 类型
int i; // int 类型
char *pc; // char* 类型
int *pi; // int* 类型
那么,数组的类型是什么?好像以前都没听过这个词汇!!!
仔细观察上面例子,变量的类型都是在定义语句中,把变量名去掉,就得到该变量的类型。同样地,在数组定义语句中把数组名去掉就是数组的类型。
看例子1.3.2:
#include <stdio.h>int main()
{char ca[10]; // 数组类型是 char [10]int ia[5]; // 数组类型是 int [5]char *pca[8]; // 数组类型是 char *[8]int *aapi[4][5];//数组类型是 int *[4][5]int (*apai[4])[5];//数组类型是 int (*[4])[5])printf(" sizeof(aapi)=%lu, %lu\n", sizeof(aapi), sizeof(int *[4][5]));printf(" sizeof(apai)=%lu, %lu\n", sizeof(apai), sizeof(int (*[4])[5]));return 0;
}
从这个例子,可以轻易指出数组的类型。在数组定义语句中,把数组名去掉,剩下的就是数组的类型。
但是,在例子中,aapi 和 apai 变量的类型可能又把一部分人的CPU干烧了。
这里需要使用一个右左法则来阅读复杂类型:
右左法则:
- 1、从变量名(没变量名的,从最里层的圆括号)开始,先看右边,再看左边;
- 2、如果右边是
()则是函数,如果是[]则是数组。- 3、如果遇到
[],后面还是[],就先看完右边的[],再看左边。
例如:int *pi[4][5];,p先跟[4][5]结合,再跟*结合。
变量aapi,先跟右边[4]结合,说明是一个有4个元素数组;再跟[5]结合,说明数组的每个元素都是带有5个元素数组;再跟左边*结合,表示第二维数组的5个元素都是指针;再跟左边int结合,表示指针指向int类型数据。
变量apai,先跟右边[4]结合,说明是一个有4个元素数组;因为()改变优先级,再跟*结合,说明数组的每个元素都是指针;再跟右边[5]结合,表示每个指针指向带有5个元素的数组;再跟左边int结合,表示这些数组都是int类型的。
✨1.4 数组元素的类型
在数组定义语句中,把数组名和后面的[]去掉,剩下的就是数组元素的类型。
看例子1.4.1:
// array_unit_type.c
#include <stdio.h>int main()
{char ca[10]; // 数组元素类型是 char int ia[5]; // 数组元素类型是 int char *pca[8]; // 数组元素类型是 char *int *aapi[4][5];//数组元素类型是 int *[5]int (*apai[4])[5];//数组元素类型是 int (*)[5])printf(" sizeof(aapi[0])=%lu, %lu\n", sizeof(aapi[0]), sizeof(int *[5]));printf(" sizeof(apai[0])=%lu, %lu\n", sizeof(apai[0]), sizeof(int (*)[5]));return 0;
}
例子中,前三个类型都比较容易看明白,int *[5] 和 int (*)[5] 分别是什么类型?
int *[5] 类型表示一个数组,每个数组元素都是int *类型。
int (*)[5]类型表示一个指向包含5个int型元素的数组的指针 。
✨1.5 数组元素的个数
C语言中,在定义数组时,都需要明确的给出数组元素个数。
在数组定义语句中,数组名后面的[]中的数字,就是数组元素的个数。
已int a[5];为例子,数组个数可以用表达式:sizeof(a) / sizeof(a[0]) 来获得。

![]()
🎄二、数组的几个地址—— a、&a、&a[0]
当我们定义一个数组 a 时,编译器根据指定的元素个数和元素的类型分配确定大小(元素类型大小*元素个数)的一块内存,并把这块内存的名字命名为 a。名字 a 一旦与这块内存匹配就不能被改变。
a[0]、a[1]等为 a 的元素,但并非元素的名字。数组的每一个元素都是没有名字的。
- 数组名
a:数组名a作为地址使用时,表示数组首个元素的地址(指针),那它所指向的类型就是数组元素类型,加减一个整数就相当于加减(整数*sizeof(元素类型))。
数组名a可以看成一个指针常量,它的值不能被修改,不能单独作为左值使用。 &a:&a表示对编译器分配好内存的变量a取地址,得到的是整个数组的地址(指针),其所指向的类型是数组的类型,加减一个整数就相当于加减(整数*sizeof(数组的类型))。&a[0]:a[0]是数组的首个元素,&a[0]是对数组首个元素取地址,得到的是数组首个元素的地址(指针),那它所指向的类型就是数组元素类型,加减一个整数就相当于加减(整数*sizeof(元素类型))。
看例子2.1:
// array_addr.c
#include <stdio.h>int main()
{int a[5];// 数组类型:int [5] ; 数组元素类型:intprintf("a=%p a+1=%p %lx\n",a, a+1, (unsigned long)a+sizeof(int));printf("&a=%p &a+1=%p %lx\n",&a, &a+1, (unsigned long)&a+sizeof(int [5]));printf("&a[0]=%p &a[0]+1=%p %lx\n",&a[0], &a[0]+1, (unsigned long)&a[0]+sizeof(int));printf("a=%lu &a=%lu &a[0]=%lu\n",sizeof(a), sizeof(&a), sizeof(&a[0]));return 0;
}
打印结果如下:

从结果看,可以得出结论:
a、&a、&a[0]作为地址(指针)使用时,三个值都是相等的;a、&a、&a[0]的指针类型不一样,&a的指针类型是数组的类型,a、&a[0]的指针类型是数组元素类型,最后进行指针运算时,a、&a[0]的结果是一样的,与&a存在差别;a、&a、&a[0]进行sizeof计算时,sizeof(a)是这个数组大小,其余两个是指针的大小(32位系统为4,64位系统为8)。
![]()
🎄三、不指定数组长度——int a[]={1,2};
在C语言中,可以使用不指定数组长度的方式来定义和初始化数组。这种情况下,编译器会根据提供的初始化值自动推断数组的长度。
例如,代码int a[]={1,2};定义了一个整型数组a,并用初始值1和2进行了初始化。由于未指定数组长度,编译器会根据提供的初始化值计算数组的大小。
在这个例子中,由于提供了两个初始化值,编译器会推断数组长度为2,因此数组a将具有两个元素:a[0]和a[1]。其值分别为:
a[0] = 1
a[1] = 2
通过这种方式,可以方便地定义和初始化具有不同长度的数组,而无需显式指定数组的长度。但是请注意,这种隐式推断数组长度的方式只适用于在声明时进行初始化的静态和自动(非堆)数组。对于动态分配的数组,仍然需要显式指定数组的长度。
总结起来,使用不指定数组长度的方式定义和初始化数组是C语言中的一种常见用法,编译器会根据提供的初始化值来推断数组的长度。
![]()
🎄四、数组初始化
在C语言中,主要有3种常见的方式可以初始化数组。下面列举了其中的几种方式,并提供了相应的示例:
- 1、在定义数组时,给各个元素初始化。
int a[5] = {1, 2, 3, 4, 5}; - 2、部分初始化:只为数组的一部分元素提供初始值,剩余元素会被设置为默认值(0)。
int a[5] = {1, 2}; // a[0]和a[1]被初始化为1和2,a[2]、a[3]和a[4]被初始化为0 - 3、不指定数组长度的方式定义和初始化数组。这是C语言中的一种常见用法,编译器会根据提供的初始化值来推断数组的长度。
int a[]={1,2}; // 初始化结束后,数组a的长度为2 char str[] = "Hello"; // 字符数组str会被初始化为包含"Hello"字符串的字符序列
这些是C语言中常见的数组初始化方式,你可以根据自己的需求选择适合的方式来初始化数组。
看例子4.1:
// array_init.c
#include <stdio.h>int main()
{int i=0;printf("no init:\n");int a[5];for(i=0; i<(sizeof(a)/sizeof(a[0])); i++){printf("%d, ",a[i]);// 没初始化,打印随机值}printf("\n\n");printf("init1: init all unit\n");int a1[5] = {1,2,3,4,5};for(i=0; i<(sizeof(a1)/sizeof(a1[0])); i++){printf("%d, ",a1[i]);}printf("\n\n");printf("init2: init first unit\n");int a2[5] = {5};for(i=0; i<(sizeof(a2)/sizeof(a2[0])); i++){printf("%d, ",a2[i]);}printf("\n\n");printf("init3: Do not specify length\n");int a3[] = {1,2,3,4,5};for(i=0; i<(sizeof(a3)/sizeof(a3[0])); i++){printf("%d, ",a3[i]);}printf("\n\n");printf("init4: Specify some unit\n");int a4[5] = {[1]=2, [3]=4};for(i=0; i<(sizeof(a4)/sizeof(a4[0])); i++){printf("%d, ",a4[i]);}printf("\n\n");printf("init5: Do not specify length, and specify the unit\n");int a5[] = {[1]=2, [3]=4};for(i=0; i<(sizeof(a5)/sizeof(a5[0])); i++){printf("%d, ",a5[i]);}printf("\n");return 0;
}
运行结果:

![]()
🎄五、字符串
C语言中的字符串,本质为字符数组,编译器自动在结尾加上 ‘\0’ 字符。
字符串字面值可以用来初始化字符数组:char str[]="abc";
字符串字面值存储于程序的全局只读存诸区,内容不可以修改,地址可以看出常量指针,指针类型是const char * const。
字符串字面值的长度可以用strlen函数来获取。
// array_str.c
#include <stdio.h>
#include <string.h>int main()
{// 1、字符串字面值的地址、空间大小、字符串长度printf("str_addr=%p str_size=%lu str_len%lu\n", (char*)"str", sizeof("str"), strlen("str"));// 2、字符串字面值给字符数组初始化unsigned char str[100] = "12345";// 3、字符串字面值是 `const char* const` 指针printf("str_1=[%c] str_end=[%c]\n", *("str"+1), *("str"+strlen("str")));return 0;
}
运行结果:

![]()
🎄六、总结
本文详细地介绍C语言的数组,数组本质上是一段连续的内存空间,了解数组5个重要内容:数组所在的内存地址、数组的内容、数组的类型、数组元素的类型、数组元素的个数;然后介绍数组的几个地址—— a、&a、&a[0];数组的初始化、字符串等。

如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁
相关文章:
【C语言 | 数组】C语言数组详解(经典,超详细)
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...
第三十三节——组合式API生命周期
一、基本使用 组合式api生命周期几乎和选项式一致。注意组合式api是从挂载阶段开始 <template><div></div> </template> <script setup> import {onBeforeMount, onMounted,onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted, } from …...
【Linux】Alibaba Cloud Linux 3 安装 PHP8.1
一、系统安装 请参考 【Linux】Alibaba Cloud Linux 3 中第二硬盘、MySQL8.、MySQL7.、Redis、Nginx、Java 系统安装 二、安装源 rpm -ivh --nodeps https://rpms.remirepo.net/enterprise/remi-release-8.rpm sed -i s/PLATFORM_ID"platform:al8"/PLATFORM_ID&q…...
【容器化】Kubernetes(k8s)
文章目录 概述Docker 的管理痛点什么是 K8s云架构 & 云原生 架构核心组件K8s 的服务注册与发现组件调用流程部署单机版部署主从版本Operator来源拓展阅读 概述 Docker 虽好用,但面对强大的集群,成千上万的容器,突然感觉不香了。 这时候就…...
stm32 HSUSB
/ stm32f407xx.h #define USB_OTG_HS_PERIPH_BASE 0x40040000UL #define USB_OTG_HS ((USB_OTG_GlobalTypeDef *) USB_OTG_HS_PERIPH_BASE) // // 定义全局变量 USBD_HandleTypeDef hUsbDeviceHS;并默认全零初始化/* USB Device handle structure */ typedef struct _USB…...
C# String.Trim 方法
String.Trim()方法定义: 命名空间:System 程序集:System.Runtime.dll 返回结果:返回一个新字符串,它相当于从当前字符串中删除了一组指定字符的所有前导匹配项和尾随匹配项。 Trim方法有三个重载的方法,…...
<Linux>(极简关键、省时省力)《Linux操作系统原理分析之Linux 进程管理 4》(8)
《Linux操作系统原理分析之Linux 进程管理 4》(8) 4 Linux 进程管理4.4 Linux 进程的创建和撤销4.4.1 Linux 进程的族亲关系4.4.2 Linux 进程的创建4.4.3 Linux 进程创建的过程4.4.4 Linux 进程的执行4.4.5 Linux 进程的终止和撤销 4 Linux 进程管理 4.…...
RT-Thread STM32F407 PWM
为了展示PWM效果,这里用ADC来采集PWM输出通道的电平变化 第一步,进入RT-Thread Settings配置PWM驱动 第二步,进入board.h,打开PWM宏 第三步,进入STM32CubeMX,配置时钟及PWM 第四步,回到R…...
idea中把spring boot项目打成jar包
打jar包 打开项目,右击项目选中Open Module Settings进入project Structure 选中Artifacts,点击中间的加号(Project Settings->Artifacts->JAR->From modules with dependencies ) 弹出Create JAR from Modules&#…...
levelDB之基础数据结构-Slice
Slice是levelDB中用于操作字符串的数据结构,以字节为单位。 定义与实现 namespace leveldb {class LEVELDB_EXPORT Slice {public:// Create an empty slice.Slice() : data_(""), size_(0) {}// Create a slice that refers to d[0,n-1].Slice(const c…...
上位机模块之通用重写相机类
在常用的视觉上位机中,我们通常会使用单个上位机匹配多个相机或者多品牌相机,所以在此记录一个可重写的通用相机类,用于后续长期维护开发。 先上代码。 using HalconDotNet; using System.Collections.Generic;namespace WeldingInspection.M…...
机器人导航+OPENCV透视变换示例代码
透视变换又称四点变换,所以不能用于5边形这样的图形变换,不是真正的透视变换,但是这个方法可以把机器人看到的图像转换为俯视图,这样就可以建立地图,要不然怎么建立地图呢。 void CrelaxMyFriendDlg::OnBnClickedOk()…...
KofamScan-KEGG官方推荐的使用系同源和隐马尔可夫模型进行KO注释
文章目录 简介安装使用输入蛋白序列输出detail-tsv格式输出detail格式输出mapper格式 输出结果detail和detail-tsv格式mapper格式常用命令tmp目录 与emapper结果比较其他参数参考 简介 KofamScan 是一款基于 KEGG 直系同源和隐马尔可夫模型(HMM)的基因功…...
代码随想录算法训练营第五十五天丨 动态规划part16
583. 两个字符串的删除操作 思路 #动态规划一 本题和动态规划:115.不同的子序列 (opens new window)相比,其实就是两个字符串都可以删除了,情况虽说复杂一些,但整体思路是不变的。 这次是两个字符串可以相互删了,这…...
【Linux】kernel与应用消息队列的一种设计
Linux进程间通讯的方式有很多种,这里介绍一种通过消息队列的方式来实现kernel与APP之间的消息收发实现方式,这种方式特别适用于,kernel中发送消息,应用层收取消息。 消息队列设备驱动 该方法的设计思路即是创建一个消息队列的设…...
我们常说的网络资产,具体是如何定义的?
文章目录 什么叫网络资产?官方定义的网络资产网络资产数字化定义推荐阅读 什么叫网络资产? 通过百度查询搜索什么叫网络资产?大体上都将网络资产归类为计算机网络中的各类设备。 基本上会定义网络传输通信架构中用到的主机、网络设备、防火…...
WPF中可冻结对象
在WPF(Windows Presentation Foundation)中,"可冻结对象"指的是那些在创建之后可以被设置为不可更改状态的对象。这种特性允许这些对象更有效地被共享和复制,并且可以增加性能。 例如,Brushes,P…...
【人工智能实验】A*算法求解8数码问题 golang
人工智能经典问题八数码求解 实际上是将求解转为寻找最优节点的问题,算法流程如下: 求非0元素的逆序数的和,判断是否有解将开始状态放到节点集,并设置访问标识位为true从节点集中取出h(x)g(x)最小的节点判断取出的节点的状态是不…...
Kafka学习笔记(二)
目录 第3章 Kafka架构深入3.3 Kafka消费者3.3.1 消费方式3.3.2 分区分配策略3.3.3 offset的维护 3.4 Kafka高效读写数据3.5 Zookeeper在Kafka中的作用3.6 Kafka事务3.6.1 Producer事务3.6.2 Consumer事务(精准一次性消费) 第4章 Kafka API4.1 Producer A…...
Typora for Mac:打造全新文本编辑体验
Typora for Mac是一款与众不同的文本编辑器,它不仅拥有直观易用的界面,还融合了Markdown语法和富文本编辑的功能,为用户带来了前所未有的写作和编辑体验。 一、简洁明了的界面设计 Typora for Mac的界面简洁明了,让用户可以专注…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
