一、什么是数组数组就是相同类型数据的集合这些数据在内存中连续存放数组里的每个位置叫元素用下标来访问。特别注意数组的下标从0开始。以下代码就是一个简单的数组应用二、数组的基本操作2.1 定义与初始化输出结果如下2.2 遍历数组遍历是数组最常见的操作通常配合 for 循环输出常见的错误循环条件写成 i 5这会访问到 nums[5]造成越界。三、数组的大小3.1 获取数组长度例如以下代码int arr[10];int len sizeof(arr) / sizeof(arr[0]); // 总字节数 / 单个元素字节数 元素个数sizeof 是运算符不是函数。sizeof(arr) 返回整个数组占用的字节数sizeof(arr[0]) 返回第一个元素的字节数相除得到元素个数。注意这个方法只对定义时的原始数组有效。如果数组作为参数传给函数就不能这么用了我也是在这上面出过很多次问题。3.2 数组在内存中的样子假设 int 占4字节数组 int a[4] {10, 20, 30, 40} 在内存中是这样排列的每个元素紧挨着下一个中间没有空隙。这就是为什么数组访问速度快——CPU可以顺序读取缓存命中率高。四、多维数组4.1 二维数组二维数组可以看作表格或矩阵matrix[2][3] 的值是 12。第一个下标是行第二个是列。4.2 遍历二维数组4.3 二维数组的初始化五、字符数组与字符串5.1 字符数组C语言没有专门的字符串类型字符串本质就是以 \0 结尾的字符数组。\0 是空字符ASCII码为0标记字符串结束。5.2 更方便的字符串写法5.3 字符串处理函数字符串处理函数有很多常见的有strlen,strcpy,strcat,strcmp等注意使用这些函数需要包含头文件 string.hstrcpy 和 strcat 不检查目标数组是否够大容易造成越界。更安全的版本是 strncpy 和 strncat它们带长度限制。六、数组作为函数参数数组传给函数时通常会丢失长度信息所以需要额外传递长度// 函数声明接收数组和长度// 调用方括号里的数字可以写也可以不写写了编译器也忽略这是为了兼容旧代码。七、常见错误与注意事项7.1 数组越界int arr[5];arr[5] 100; // 严重错误合法下标只有0~4C语言不会检查下标是否越界,越界访问可能1.覆盖其他变量的数据2.导致程序崩溃Segmentation Fault3.产生难以调试的随机错误防御建议写循环时仔细检查边界条件。7.2 定义时长度必须是常量int n 10;int arr[n]; // 错误C89标准不允许C99允许但不推荐#define SIZE 10int arr[SIZE]; // 正确宏定义是常量const int size 10;int arr[size]; // 错误const变量不是编译期常量标准C要求数组长度在编译时确定。需要动态大小的情况需要使用其他机制如 malloc这属于后续学习内容。7.3 不能整体赋值int a[5] {1, 2, 3, 4, 5};int b[5];b a; // 错误数组不能整体赋值只能逐个元素复制// 正确做法循环复制for (int i 0; i 5; i) {b[i] a[i];}八、sizeof 与 strlen详解这两个函数是初学者最容易踩的坑之一sizeof 和 strlen 看起来都像是求长度但本质完全不同。8.1 sizeof求占用字节数sizeof 是运算符在编译时计算返回变量或类型占用的字节数。例如输出对于字符数组sizeof 包含结尾的 \08.2 strlen求字符串长度strlen 是函数在运行时计算返回字符串中字符的个数不含 \0。例如输出8.3 对比总结核心区别sizeof 问的是你占多少内存空间strlen 问的是你的字符串内容有多长对于空格、换行、缩进这两个函数也是都会算进去。九、写数组的好习惯远离Bug9.1 用宏定义数组长度不要直接把数字写在代码里用宏统一管理好处改一处全局生效代码可读性高不容易抄错数字。9.2 遍历用 而不是 例证如下// 好习惯for (int i 0; i MAX_STUDENTS; i) { ... }// 坏习惯容易越界for (int i 0; i MAX_STUDENTS; i) { ... } // 危险会访问到 arr[MAX_STUDENTS]数组有 N 个元素合法下标是 0 到 N-1所以循环条件是 N不是 N。9.3 初始化时顺手清零定义数组时顺手初始化避免使用未初始化的垃圾值int buffer[100] {0}; // 全部置0// 或者针对字符数组char input[256] {0}; // 清空避免残留数据干扰9.4 数组长度用 sizeof 计算不要硬编码int arr[] {3, 1, 4, 1, 5, 9, 2, 6};// 好习惯让编译器帮你算长度for (int i 0; i sizeof(arr) / sizeof(arr[0]); i) {printf(%d , arr[i]);}这样后续修改数组内容时循环边界自动适应不用手动改数字。9.5 字符数组留够 \0 的位置// 错误存不下 Hello 的 \0char str[5] Hello; // 实际占用6字节越界写入// 正确char str[6] Hello; // 5个字母 1个 \0 刚好6字节// 或更保险char str[20] Hello; // 留足余量9.6 函数传数组时同时传长度// 好习惯长度作为参数一起传void print_scores(int scores[], int count) {for (int i 0; i count; i) {printf(%d , scores[i]);}}// 调用int scores[MAX_STUDENTS];print_scores(scores, MAX_STUDENTS);不要在函数内部试图用 sizeof 算数组长度——传进来的数组已经退化为指针sizeof 只能得到指针大小不是数组长度。9.7 用 const 保护只读数组如果函数不需要修改数组内容加上 const 约束void print_array(const int arr[], int len) {// arr[i] 100; // 编译报错防止误修改for (int i 0; i len; i) {printf(%d , arr[i]);}}这是防御性编程的好习惯编译器会帮你拦住意外修改。9.8 二维数组初始化不要偷懒// 好习惯每层都加花括号清晰直观int matrix[2][3] {{1, 2, 3},{4, 5, 6}};// 坏习惯虽然合法但容易搞混行列int matrix[2][3] {1, 2, 3, 4, 5, 6};十、实用技巧10.1 求数组最大值/最小值输出的 max 现在是 8910.2 数组排序冒泡排序输出结果{1, 2, 3, 5, 8}十一、结语数组是C语言最基础的数据结构我们要理解它的核心要点1.连续存储元素在内存中挨着放2.下标从0开始arr[0] 是第一个元素3.不检查越界自己负责边界安全4.长度需额外传递传给函数时要带上长度养成好习惯——用宏定义长度、初始化清零、 代替 、区分 sizeof 和 strlen——能让你少踩很多坑。掌握数组后后续学习指针会轻松很多但那是另一个阶段的故事了。
C语言数组:从基础到实践
发布时间:2026/5/24 1:24:27
一、什么是数组数组就是相同类型数据的集合这些数据在内存中连续存放数组里的每个位置叫元素用下标来访问。特别注意数组的下标从0开始。以下代码就是一个简单的数组应用二、数组的基本操作2.1 定义与初始化输出结果如下2.2 遍历数组遍历是数组最常见的操作通常配合 for 循环输出常见的错误循环条件写成 i 5这会访问到 nums[5]造成越界。三、数组的大小3.1 获取数组长度例如以下代码int arr[10];int len sizeof(arr) / sizeof(arr[0]); // 总字节数 / 单个元素字节数 元素个数sizeof 是运算符不是函数。sizeof(arr) 返回整个数组占用的字节数sizeof(arr[0]) 返回第一个元素的字节数相除得到元素个数。注意这个方法只对定义时的原始数组有效。如果数组作为参数传给函数就不能这么用了我也是在这上面出过很多次问题。3.2 数组在内存中的样子假设 int 占4字节数组 int a[4] {10, 20, 30, 40} 在内存中是这样排列的每个元素紧挨着下一个中间没有空隙。这就是为什么数组访问速度快——CPU可以顺序读取缓存命中率高。四、多维数组4.1 二维数组二维数组可以看作表格或矩阵matrix[2][3] 的值是 12。第一个下标是行第二个是列。4.2 遍历二维数组4.3 二维数组的初始化五、字符数组与字符串5.1 字符数组C语言没有专门的字符串类型字符串本质就是以 \0 结尾的字符数组。\0 是空字符ASCII码为0标记字符串结束。5.2 更方便的字符串写法5.3 字符串处理函数字符串处理函数有很多常见的有strlen,strcpy,strcat,strcmp等注意使用这些函数需要包含头文件 string.hstrcpy 和 strcat 不检查目标数组是否够大容易造成越界。更安全的版本是 strncpy 和 strncat它们带长度限制。六、数组作为函数参数数组传给函数时通常会丢失长度信息所以需要额外传递长度// 函数声明接收数组和长度// 调用方括号里的数字可以写也可以不写写了编译器也忽略这是为了兼容旧代码。七、常见错误与注意事项7.1 数组越界int arr[5];arr[5] 100; // 严重错误合法下标只有0~4C语言不会检查下标是否越界,越界访问可能1.覆盖其他变量的数据2.导致程序崩溃Segmentation Fault3.产生难以调试的随机错误防御建议写循环时仔细检查边界条件。7.2 定义时长度必须是常量int n 10;int arr[n]; // 错误C89标准不允许C99允许但不推荐#define SIZE 10int arr[SIZE]; // 正确宏定义是常量const int size 10;int arr[size]; // 错误const变量不是编译期常量标准C要求数组长度在编译时确定。需要动态大小的情况需要使用其他机制如 malloc这属于后续学习内容。7.3 不能整体赋值int a[5] {1, 2, 3, 4, 5};int b[5];b a; // 错误数组不能整体赋值只能逐个元素复制// 正确做法循环复制for (int i 0; i 5; i) {b[i] a[i];}八、sizeof 与 strlen详解这两个函数是初学者最容易踩的坑之一sizeof 和 strlen 看起来都像是求长度但本质完全不同。8.1 sizeof求占用字节数sizeof 是运算符在编译时计算返回变量或类型占用的字节数。例如输出对于字符数组sizeof 包含结尾的 \08.2 strlen求字符串长度strlen 是函数在运行时计算返回字符串中字符的个数不含 \0。例如输出8.3 对比总结核心区别sizeof 问的是你占多少内存空间strlen 问的是你的字符串内容有多长对于空格、换行、缩进这两个函数也是都会算进去。九、写数组的好习惯远离Bug9.1 用宏定义数组长度不要直接把数字写在代码里用宏统一管理好处改一处全局生效代码可读性高不容易抄错数字。9.2 遍历用 而不是 例证如下// 好习惯for (int i 0; i MAX_STUDENTS; i) { ... }// 坏习惯容易越界for (int i 0; i MAX_STUDENTS; i) { ... } // 危险会访问到 arr[MAX_STUDENTS]数组有 N 个元素合法下标是 0 到 N-1所以循环条件是 N不是 N。9.3 初始化时顺手清零定义数组时顺手初始化避免使用未初始化的垃圾值int buffer[100] {0}; // 全部置0// 或者针对字符数组char input[256] {0}; // 清空避免残留数据干扰9.4 数组长度用 sizeof 计算不要硬编码int arr[] {3, 1, 4, 1, 5, 9, 2, 6};// 好习惯让编译器帮你算长度for (int i 0; i sizeof(arr) / sizeof(arr[0]); i) {printf(%d , arr[i]);}这样后续修改数组内容时循环边界自动适应不用手动改数字。9.5 字符数组留够 \0 的位置// 错误存不下 Hello 的 \0char str[5] Hello; // 实际占用6字节越界写入// 正确char str[6] Hello; // 5个字母 1个 \0 刚好6字节// 或更保险char str[20] Hello; // 留足余量9.6 函数传数组时同时传长度// 好习惯长度作为参数一起传void print_scores(int scores[], int count) {for (int i 0; i count; i) {printf(%d , scores[i]);}}// 调用int scores[MAX_STUDENTS];print_scores(scores, MAX_STUDENTS);不要在函数内部试图用 sizeof 算数组长度——传进来的数组已经退化为指针sizeof 只能得到指针大小不是数组长度。9.7 用 const 保护只读数组如果函数不需要修改数组内容加上 const 约束void print_array(const int arr[], int len) {// arr[i] 100; // 编译报错防止误修改for (int i 0; i len; i) {printf(%d , arr[i]);}}这是防御性编程的好习惯编译器会帮你拦住意外修改。9.8 二维数组初始化不要偷懒// 好习惯每层都加花括号清晰直观int matrix[2][3] {{1, 2, 3},{4, 5, 6}};// 坏习惯虽然合法但容易搞混行列int matrix[2][3] {1, 2, 3, 4, 5, 6};十、实用技巧10.1 求数组最大值/最小值输出的 max 现在是 8910.2 数组排序冒泡排序输出结果{1, 2, 3, 5, 8}十一、结语数组是C语言最基础的数据结构我们要理解它的核心要点1.连续存储元素在内存中挨着放2.下标从0开始arr[0] 是第一个元素3.不检查越界自己负责边界安全4.长度需额外传递传给函数时要带上长度养成好习惯——用宏定义长度、初始化清零、 代替 、区分 sizeof 和 strlen——能让你少踩很多坑。掌握数组后后续学习指针会轻松很多但那是另一个阶段的故事了。