C语言进阶:数组

发布时间:2026/7/19 2:15:26
C语言进阶:数组 C语言进阶数组—— 从一维到多维数组名与指针sizeof 的陷阱前言学完变量、分支和循环之后你第一个遇到的数据结构就是数组。它是 C 语言中最基础、最常用的复合类型——没有之一。但数组也是新手最容易出问题的地方。sizeof 算出来不是你想要的数传个数组进函数结果全乱了二维数组的指针绕得头晕——这些问题几乎每个人都会遇到。这篇我们从头讲清楚数组怎么声明、怎么存、怎么用、sizeof 什么时候背叛你、数组名和指针到底什么关系。一、一维数组从声明到内存1.1 声明与初始化数组就是一组相同类型的变量的集合。声明数组时你需要指定类型、名字和大小int arr[10]; // 10 个 int未初始化char name[20]; // 20 个 char可以存 19 个字符 \0声明时可以同时初始化int a[5] {1, 2, 3, 4, 5}; // 完整初始化int b[5] {1, 2}; // 部分初始化剩余为 0int c[] {1, 2, 3, 4, 5}; // 自动推算大小 5int d[5] {0}; // 全部初始化为 0二、sizeof 的陷阱2.1 sizeof(数组名)sizeof 操作符写在数组名前面时返回的是整个数组占用的字节数——不是元素个数。int arr[10];sizeof(arr); // 4010 个 int × 4 字节sizeof(arr) / sizeof(arr[0]); // 10 —— 这才是元素个数2.2 sizeof 在哪里背叛你当你把数组作为函数参数传递时数组名“退化”为指针。此时 sizeof 计算的是指针大小——在 64 位系统上是 8。void func(int arr[]) { sizeof(arr); } // 8不是 40void func(int arr[], int len) { /* 用 len */ } // 正确三、数组名与指针的区别3.1 三个等价式数组名在大多数上下文中会隐式转换为首元素地址。因此以下三种写法等价arr[i] *(arr i) *(i arr) i[arr]是的i[arr] 也能编译通过——C 语言的 [] 操作符只是 *(ab) 的语法糖。3.2 两个例外① sizeof(arr) —— 返回整个数组的大小不是指针大小。② arr —— 取整个数组的地址类型是 int(*)[N]不是二级指针。int arr[5];int *p arr; // int*1 跳 4 字节int (*q)[5] arr; // int(*)[5]1 跳 20 字节四、二维数组4.1 声明与存储二维数组就是“数组的数组”。在内存中仍然是连续排列的——按行优先存储。int mat[3][4] {{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}};4.2 二维数组的指针类型对于 int mat[3][4]· mat 的类型是 int(*)[4]——指向“包含 4 个 int 的一维数组”的指针。· mat[0] 的类型是 int*——第一行的首元素地址。· sizeof(mat) 483×4×4sizeof(mat[0]) 164×4。4.3 二维数组传参二维数组传参时第二维的大小必须指定void func(int mat[][4], int rows); // 正确void func(int (*mat)[4], int rows); // 等价为什么因为编译器要知道 mat[i][j] 中 i 跳过多少字节。你不告诉它列数编译器就算不出偏移量。五、常见错误汇总1. 忘记传数组长度——函数里 sizeof(arr) 返回的是指针大小。2. 数组越界——arr[10] 实际上只有 0~9arr[10] 已经越界了。C 语言不检查越界。3. 用 复制数组——arr2 arr1 不会复制内容只是指针赋值。正确用 memcpy 或循环。4. sizeof 和 strlen 搞混——sizeof 编译期算字节数含 \0strlen 运行期算字符数不含 \0。5. 返回局部数组的指针——函数返回后数组被销毁指针变悬空。写在最后数组是简单的——一段连续的内存一个名字一个类型。但它的简单恰恰是它复杂的原因。你不需要记住数组和指针的所有等价变换但你需要知道两件事① sizeof 会背叛你② 数组名在大多数时候等于首元素地址。这两件事记住了至少不会掉进数组最大的坑里。小说就是把自己和别人混在一起。—— 杨德昌《恐怖分子》— END —