当前位置: 首页 > backend >正文

C语言数组遍历的方法(包含二维数组)

数组遍历的方法(包含二维数组)

文章目录

    • 数组遍历的方法(包含二维数组)
      • 一维数组的遍历
        • 1.下标法(`[]`运算符)
        • 2.指针法(`*(ptr + i)`)
        • 3. 指针递增法`(ptr++)`
        • 4. 尾后指针法`(begin/end模式)`
      • 二维数组的遍历
        • 1.双重下标法(`arr[i][j]`)
        • 2.行指针法(指向一维数组的指针)
        • 3.列指针法(一维化指针访问)
        • 4.指针数组法(非连续内存场景)
      • 关键对比与性能分析

一维数组的遍历

1.下标法([]运算符)
  • 特点:直观易懂,符合数组常规访问的习惯。
  • 示例代码:
int arr[] = {1, 2, 3, 4, 5};
int len = sizeof(arr) / sizeof(arr[0]);for (int i = 0; i < len; i++) 
{printf("%d ", arr[i]);  // 输出:1 2 3 4 5
}
2.指针法(*(ptr + i)
int arr[] = {1, 2, 3, 4, 5};
int *ptr = arr;
int len = sizeof(arr) / sizeof(*ptr);for (int i = 0; i < len; i++) 
{printf("%d ", *(ptr + i));  // 输出:1 2 3 4 5
}
  • 代码解析:
    • 指针初始化:ptr指向数组首地址(arr隐式转换为指针)。偏移计算:ptr + i表示在ptr基础上偏移i * sizeof(int)字节(本例为i * 4)。
    • 等价性:*(ptr + i)完全等价于ptr[i]和arr[i]。
  • 性能分析:与下标法本质相同,但部分编译器可直接优化为寄存器操作,在高频访问时可能略快。
3. 指针递增法(ptr++)
int arr[] = {1, 2, 3, 4, 5}; // ① 定义并初始化一维整型数组,包含5个元素
int* ptr = arr; // ② 将数组名`arr`赋值给指针`ptr`,数组名隐式转换为指向首元素的指针(int*类型),ptr指向arr[0](地址0x7fff...)
int len = sizeof(arr) / sizeof(*ptr); // ③ 计算数组长度:// sizeof(arr)获取数组总字节数(5*4=20字节),sizeof(*ptr)为单个元素字节数(4字节),len=20/4=5for (int i = 0; i < len; i++, ptr++) // ④ 循环条件:// i从0开始,当i<5时执行循环体// 每次循环后i自增1,ptr自增1(指针移动步长为sizeof(int)=4字节,指向下一个元素)
{printf("%d ", *ptr); // ⑤ 解引用指针ptr,输出当前指向的元素值// 第一次循环:ptr指向arr[0],输出1;第二次循环:ptr指向arr[1],输出2;依此类推
}
// 恢复指针(如需再次使用):ptr = arr; // ⑥ 循环结束后,ptr指向arr[5](数组末尾的下一个位置)// 若需再次遍历,需将ptr重置为数组首地址arr(指向arr[0])
  • 代码解析:
    • 指针移动:每次循环ptr自增,直接指向下一个元素(步长为4字节)
    • 副作用:遍历结束后ptr指向数组末尾的下一个位置(如&arr[5]),需重置才能再次使用。
4. 尾后指针法(begin/end模式)
int arr[] = {1, 2, 3, 4, 5}; // ① 定义并初始化一维整型数组,包含5个元素(静态分配,内存连续)
int *begin = arr; // ② 将数组名`arr`赋值给指针`begin`,数组名隐式转换为指向首元素的指针(int*类型)// begin指向arr[0](地址0x7fff...),作为遍历起点
int *end = arr + sizeof(arr)/sizeof(arr[0]); // ③ 计算尾后指针`end`:// sizeof(arr)/sizeof(arr[0])得到数组元素个数(5)// arr + 5 指向arr[5](数组最后一个元素的下一个位置,即尾后位置)// end不可解引用(访问该地址会导致越界),仅用于边界判断for (int *ptr = begin; ptr < end; ptr++) // ④ 循环条件:// ptr初始化为begin(指向arr[0])// 每次循环检查ptr是否小于end(即是否未到达尾后位置)// 每次循环结束后ptr自增1(指向下一个元素,步长为4字节)
{printf("%d ", *ptr); // ⑤ 解引用指针ptr,输出当前指向的元素值// 第一次循环:ptr指向arr[0],输出1;第二次循环:ptr指向arr[1],输出2;依此类推
}
// 循环结束后,ptr == end(指向arr[5])
  • 代码解析:
    • 尾后指针:end指向数组最后一个元素的下一个位置(不指向有效数据)。
    • 安全边界:ptr < end确保不会越界,即使数组长度动态变化也无需修改循环条件。

二维数组的遍历

1.双重下标法(arr[i][j]
int arr[3][4] = 
{{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12}
};for (int i = 0; i < 3; i++) 
{for (int j = 0; j < 4; j++) {printf("%d ", arr[i][j]);  // 逐行输出}printf("\n");
}
  • 内存布局

    • C 语言中二维数组按行优先存储,内存中排列:1,2,3,4,5,6,7,8,9,10,11,12。
  • 访问原理:

    • arr[i][j]等价于*(*arr + i) + j)
    • 计算步骤:
      • arr + i:偏移i行(每行4 * 4 = 16字节)
      • *(arr + i):解引用得到第i行的首地址
      • *(arr + i) + j:在第i行基础上偏移j个元素
      • *(*(arr + i) + j):解引用得到具体元素
2.行指针法(指向一维数组的指针)
int arr[3][4] = {...};
int (*row_ptr)[4] = arr;  // 行指针,指向包含4个int的一维数组for (int i = 0; i < 3; i++) 
{for (int j = 0; j < 4; j++) {printf("%d ", (*row_ptr)[j]);  // 解引用行指针后取下标}row_ptr++;  // 指向下一行
}
  • 代码解析:
  • 行指针声明:int (*row_ptr)[4]表示row_ptr是一个指针,指向包含4个int的数组。
  • 行偏移:row_ptr++会使指针跳过4 * 4 = 16字节(一行的大小)。
  • 等价写法:(*row_ptr)[j]等价于row_ptr[0][j],即当前行的第j个元素。
  • 优势:保持二维结构的逻辑,适合按行处理数据(如矩阵转置)。
3.列指针法(一维化指针访问)
int arr[3][4] = {...};
int *col_ptr = &arr[0][0];  // 指向首元素
int rows = 3, cols = 4;for (int i = 0; i < rows * cols; i++)
{printf("%d ", col_ptr[i]);  // 等价于*(col_ptr + i)
}
  • 内存映射:

    • 将二维数组视为长度为rows * cols的一维数组。

    • 元素arr[i][j]对应一维索引i * cols + j(本例中arr[1][2]对应1 * 4 + 2 = 6)。

  • 性能分析

    • 内存连续访问,缓存命中率高。
    • 但需手动计算行列坐标(如需还原)
int row = i / cols;
int col = i % cols;
4.指针数组法(非连续内存场景)
// 动态分配3行,每行4列
int **arr = (int **)malloc(3 * sizeof(int *));
for (int i = 0; i < 3; i++)
{arr[i] = (int *)malloc(4 * sizeof(int));for (int j = 0; j < 4; j++){arr[i][j] = i * 4 + j + 1;  // 赋值}
}// 遍历
for (int i = 0; i < 3; i++) 
{for (int j = 0; j < 4; j++) {printf("%d ", arr[i][j]);}free(arr[i]);  // 释放每行内存
}
free(arr);  // 释放指针数组
  • 内存结构:

    • arr是一个指针数组,每个元素arr[i]指向一行数据。
    • 每行内存可动态分配不同长度(如arr[0]指向 2 个元素,arr[1]指向 3 个元素)。
  • 访问过程:

    • arr是一级指针,指向指针数组首地址。
    • arr[i]是二级指针,指向第i行的一维数组。
    • arr[i][j]通过两次解引用访问具体元素。
  • 注意事项:

    • 每行内存地址可能不连续,随机访问效率较低。
    • 必须严格按顺序释放内存(先释放每行,再释放指针数组)。

关键对比与性能分析

在这里插入图片描述

http://www.xdnf.cn/news/9312.html

相关文章:

  • 如何构建一个高效的 iOS 应用日志体系?从开发调试到使用KeyMob上线排查的实践经验
  • vmvare 虚拟机内存不足
  • npm/yarn/pnpm安装时Sharp模块报错解决方法
  • 商品条形码查询接口如何用C#进行调用?
  • 001 flutter学习的注意事项及前期准备
  • leetcode hot100刷题日记——20.爬楼梯
  • Ubuntu实现和主机的复制粘贴 VMware-Tools(open-vm-tools)
  • pikachu靶场通关笔记04-暴力破解之Token绕过
  • 阿里云云网络论文:Nezha,计算网络解耦下的vSwitch池化架构
  • 大模型(6)——语义分割
  • 人工智能模型方面有哪些优化措施,可以提升模型的准确率
  • Java 反射机制深度解析:从原理到实战应用
  • TS.43规范-1
  • SAAS架构设计-1-模块说明
  • doucker 挂载卷
  • Fast-DDS Spy 工具
  • 2025CCPC河北省赛题解
  • (五)MMA(OpenTelemetry/Rabbit MQ/)
  • 图论学习笔记 4 - 仙人掌图
  • ROS云课三分钟-3D性能测试supertuxkart和游戏推荐等-国际象棋
  • 子序列相关题目总结
  • 数据结构与算法Day3:绪论第三节抽象数据类型、算法及其描述
  • 图论回溯
  • Linux基本指令篇 —— touch指令
  • SOC-ESP32S3部分:16-I2C
  • java常用工具类:生成唯一id
  • 对称二叉树
  • STM32F407VET6学习笔记5:STM32CubeMX配置串口工程_HAL库
  • 互联网大厂Java求职面试:从Spring到微服务的技术探讨
  • go tour方法和接口