嵌入式Linux(day08)学习笔记|C语言(day05)数组核心知识点(数组存储+字符数组+多维数组+杨辉三角练习)
📝 今日学习主题:C语言数组核心用法(嵌入式开发基础必备)
💡 学习目标:掌握数组存储结构、字符数组与字符串的区别、多维数组原理,能独立完成杨辉三角编程练习,夯实嵌入式编程基础。
数组是嵌入式开发中最常用的数据结构之一,无论是存储传感器数据、缓冲区数据,还是实现简单算法,都离不开数组的灵活运用。今天系统梳理数组相关知识点,结合实例拆解难点,方便后续复习和项目调用。
一、数组的存储结构(核心重点)
数组的核心特性的是“连续存储”,这也是它高效访问的关键,尤其适合嵌入式中对内存效率和访问速度有要求的场景。
1.1 数组的存储本质
-
核心结论:数组中的所有元素地址一定是连续的,编译器会为数组分配一块连续的内存空间,元素按下标顺序依次存储(下标从0开始)。
-
补充说明:连续存储的优势的是可以通过“首地址+偏移量”快速访问任意元素,无需遍历,这也是嵌入式开发中数组比链表更常用的原因之一。
-

1.2 数组名的核心作用(重中之重)
数组名是数组的“灵魂”,理解数组名的特性,能轻松搞定数组的地址访问、元素操作,避免嵌入式编程中常见的内存访问错误。
❓ 常见问题拆解(嵌入式高频考点)
-
数组名是什么?
-
核心答案:数组名本质是数组首元素的地址(注意:数组名≠指针,但在大多数表达式中会退化为首元素指针)。
-
补充:数组名并非普通指针,它是编译器识别数组的符号,没有独立的存储空间,与指针常量(T* const)行为相似但类型不同。
-
-
数组名有类型吗?
-
有,数组名的类型是“数组元素的指针类型”,由数组元素的类型决定:
-
若元素是int类型(如int arr[5]),则数组名的类型是int*(指向int的指针);
-
若元素是char类型(如char str[10]),则数组名的类型是char*(指向char的指针)。
-
-
数组名的运算能力(偏移量计算)
-
数组名的运算能力由其类型决定,本质是“每偏移1个单位,跳过的字节数”(即元素的大小):
-
int*类型(数组元素为int):运算能力为4(32位系统中,int占4个字节);
-
char*类型(数组元素为char):运算能力为1(char占1个字节)。
-
示例:int arr[5]; arr+1 表示跳过第一个int元素,指向arr[1]的地址(偏移4个字节)。
-
-
数组名是变量吗?
-
不是变量,是一个常量值(地址常量)。
-
注意:不能对数组名进行赋值操作(如arr = &arr[1]; 是非法的),因为数组名的地址是编译时确定的,无法修改,这一点与指针变量有本质区别。
-
-
取值运算符(*)与数组访问
-
*arr:从数组名(首元素地址)开始,取出对应类型大小的字节数,具体取多少字节由数组元素类型决定;
-
核心等价式:arr[n] == *(arr + n)(嵌入式编程中常用*(arr + n)访问元素,尤其在循环中更灵活)。
-
示例:int arr[3] = {1,2,3}; arr[2] 与 *(arr+2) 均表示访问第三个元素(值为3)。
-
二、字符数组和字符串(嵌入式字符串操作基础)
嵌入式开发中,字符串常用于串口通信、日志打印、配置信息存储等场景,而C语言中没有专门的字符串类型,需通过字符数组实现,这是高频易错点。
2.1 字符数组
-
定义:专门用于存储char类型变量的数组(char是C语言中最小的字符存储单位,占1字节);
-
核心用途:存储单个字符,或存储字符串(是C语言中唯一能存储字符串的数据类型)。
2.2 字符串的定义与特性
-
定义:由0个或多个字符组成,必须以'\0'(空字符,ASCII值为0)结尾的一组字符,称为字符串;
-
关键细节:
-
空串:"" 表示空串,内部仅包含一个'\0'(无其他字符);
-
字符串常量:如"hello",编译器会自动在末尾添加'\0'(我们编写时可省略,但编译器会自动补充);
-
字符串变量:C语言中没有“字符串”数据类型,若需使用字符串变量,必须借助字符数组实现。
-
2.3 存储字符串的数组(易错点解析)
并非所有字符数组都是字符串,只有以'\0'结尾的字符数组,才能被当作字符串使用,以下3个示例对比,彻底分清区别:
-
示例1:char str1[10] = "hello";
-
解析:数组str1有10个字节空间,"hello"共5个字符,编译器自动在末尾添加'\0',因此str1是字符数组,也可看作字符串变量;
-
内存分布:h e l l o \0 (剩余4个空间默认为'\0')。
-
-
示例2:char str2[2] = {'h', 'i'};
-
解析:str2是字符数组,但不是字符串变量;
-
原因:数组空间仅2个字节,刚好存储'h'和'i',没有多余空间存储'\0',不符合字符串“以'\0'结尾”的要求,无法作为字符串使用(如用strlen计算长度会出错)。
-
-
示例3:char str3[2] = "hi";
-
解析:数组越界(嵌入式编程中致命错误!);
-
原因:"hi"作为字符串,包含'h'、'i'和'\0'共3个成员,而数组str3仅分配2个字节空间,无法容纳'\0',会导致内存越界,可能破坏其他数据。
-
2.4 字符串的常用操作(嵌入式必备)
-
长度:字符串的长度是“不包含'\0'的字符个数”,可通过strlen()函数计算(需包含头文件<string.h>),strlen()的实现原理是遍历字符直到'\0',返回计数器值;
-
复制:将一个字符串复制到另一个字符数组中,常用函数strcpy()、strncpy()(推荐用strncpy(),可限制复制长度,避免缓冲区溢出);
-
拼接:将一个字符串追加到另一个字符串末尾,常用函数strcat()、strncat(),注意目标数组需有足够空间容纳拼接后的结果;
-
比较:逐字符比较两个字符串的ASCII值,第一个不相等的字符,ASCII码值大的字符串整体更大(常用函数strcmp(),返回值为负数、0、正数,分别表示小于、等于、大于);
-
示例1:"hello" > "hi" → 错误!实际是"hello" < "hi",因为第一个不同字符'e'(ASCII=101)< 'i'(ASCII=105);
-
示例2:"hello" == "hello" → 正确,所有字符完全一致;
-
示例3:"hello" < "helloa" → 正确,"hello"长度为5,"helloa"长度为6,前5个字符一致,短字符串更小。
-
三、多维数组(以二维数组为例)
嵌入式开发中,多维数组常用于存储矩阵数据、坐标信息等(如LCD屏幕像素矩阵、传感器采集的二维数据),核心是理解“多维数组的本质是数组的数组”。
3.1 多维数组的定义与理解
以int类型为例,通过对比一维数组和二维数组,理解多维数组的存储逻辑:
-
一维数组的“多维表示”:
-
int arr[6] = {1,2,3,4,5,6};
-
若每两个成员表示一个坐标(如(1,2)、(3,4)、(5,6)),用一维数组表示不够直观,此时可使用二维数组。
-
-
二维数组的正确定义:
-
int arr[3][2] = {1,2,3,4,5,6};
-
解析:
-
arr是一个二维数组,包含3个成员(即3个一维数组);
-
每个成员都是一个包含2个int类型变量的一维数组;
-
存储结构:仍为连续存储,顺序为arr[0][0]、arr[0][1]、arr[1][0]、arr[1][1]、arr[2][0]、arr[2][1],地址依次连续。
-
-
3.2 二维数组名的深层解析(难点)
-
arr是什么?
-
arr表示二维数组的首地址,本质是&arr[0](即第一个一维数组的地址);
-
补充:&arr[0]表示整个一维数组的地址,其类型是int(*)[2](指向包含2个int的数组的指针),运算能力为8字节(32位系统中,2个int共8字节),因此arr的运算能力也为8字节。
-
-
arr[0]是什么?
-
arr[0]是二维数组的第一个成员,本质是一个包含2个int类型变量的一维数组;
-
arr[0]的作用:表示该一维数组中首元素的地址(即&arr[0][0]);
-
访问示例:(arr[0])[0] 等价于 arr[0][0],表示第一个一维数组的第一个元素(值为1)。
-
-
arr[0]的类型:int*(因为arr[0]是一维数组的首地址,该一维数组的元素是int类型)。
-
补充:整个数组的大小
-
对于int arr[3][2],整个数组的大小 = 3(一维数组个数) × 2(每个一维数组的元素个数) × 4(int字节数) = 24字节;
-
单个一维数组(如arr[0])的大小 = 2 × 4 = 8字节,与&arr[0]的运算能力一致。
-
四、实战练习:打印10行杨辉三角(二维数组应用)
杨辉三角是二维数组的经典实战案例,嵌入式开发中可通过该练习掌握二维数组的初始化、元素赋值和格式输出,同时理解循环逻辑的优化技巧。
4.1 杨辉三角核心规律
-
每行首尾元素固定为1;
-
中间元素 = 上一行相邻两个元素之和(如第i行第j列元素 = 第i-1行第j-1列 + 第i-1行第j列);
-
第i行(从0开始计数)有i+1个元素。
4.2 10行杨辉三角预期输出
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
4.3 规范实现代码(嵌入式风格,带注释)
/******************************
* 功能:打印10行杨辉三角(二维数组实现)
* 适用场景:嵌入式C语言基础练习、数组操作实战
* 核心思路:1. 边界初始化(每行首尾为1);2. 中间元素递推;3. 格式输出
*****************************/
#include <stdio.h>
#define ROW 10 // 宏定义行数,便于修改(嵌入式开发常用技巧)
int main() {
int yanghui[ROW][ROW] = {0}; // 初始化二维数组为0,避免随机值干扰
int i, j;
// 步骤1:生成杨辉三角数据
for (i = 0; i < ROW; i++) {
yanghui[i][0] = 1; // 每行首元素为1(边界条件)
yanghui[i][i] = 1; // 每行尾元素为1(边界条件)
if (i > 1) { // 前两行无中间元素,无需计算
// 中间元素:j从1到i-1,避免越界
for (j = 1; j < i; j++) {
yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
}
}
}
// 步骤2:按三角格式输出(嵌入式常用格式优化)
printf("杨辉三角(前10行):\n");
for (i = 0; i < ROW; i++) {
for (j = 0; j <= i; j++) { // 第i行仅输出i+1个元素
printf("%4d", yanghui[i][j]); // 占4位输出,保证三角对齐
}
printf("\n"); // 每行结束换行
}
return 0;
}
4.4 代码解析(嵌入式重点)
-
宏定义ROW=10:嵌入式开发中常用宏定义统一常量,后续修改行数只需修改宏定义,无需逐行调整;
-
数组初始化:yanghui[ROW][ROW] = {0},避免未赋值元素为随机值,防止打印异常;
-
循环优化:j < i 避免无效循环(如i=3时,j无需遍历到9),提升代码效率(嵌入式开发对效率要求较高);
-
格式输出:%4d 保证每个元素占4位,使杨辉三角呈现标准的三角形态,提升可读性。
五、今日学习总结
-
数组核心:连续存储、数组名是首元素地址(常量),掌握arr[n]与*(arr+n)的等价关系;
-
字符数组与字符串:重点区分“字符数组”和“字符串”(是否以'\0'结尾),避免数组越界;
-
多维数组:本质是“数组的数组”,理解数组名的类型和运算能力,避免地址访问错误;
-
实战重点:杨辉三角练习,掌握二维数组的初始化、元素递推和格式输出,贴合嵌入式编程规范。
📌 备注:数组是嵌入式开发的基础,后续学习指针、缓冲区、算法时都会用到,建议多敲代码练习,重点掌握地址访问和边界判断,避免内存越界(嵌入式开发中内存越界会导致程序崩溃)。
更多推荐



所有评论(0)