C语言指针与数组的深度应用与内存解析

C语言指针与数组的深度应用与内存解析

C语言指针与数组的深度应用与内存解析

在这里插入图片描述

💡 学习目标:掌握指针与数组的等价性原理,熟练运用指针操作数组元素,理解二者在内存中的存储本质,解决实际开发中数组遍历、数据拷贝的高效实现问题。
💡 学习重点:指针与数组名的区别、指针算术运算操作数组、二维数组的指针访问方式、内存视角下的数组与指针关系。

48.1 指针与数组的核心关联:本质与等价性

在C语言中,指针和数组的关系密不可分。很多初学者会混淆数组名和指针的概念,实际上二者既有联系又有本质区别。

48.1.1 数组名的“隐式转换”特性

当数组名出现在表达式中时,它会隐式转换为指向数组首元素的指针。我们可以通过一个简单的例子来验证这个特性:

#include<stdio.h>intmain(){int arr[5]={10,20,30,40,50};// 输出数组首元素地址printf("数组名arr的地址:%p\n", arr);// 输出数组首元素的指针地址printf("&arr[0]的地址:%p\n",&arr[0]);// 用数组名访问首元素printf("arr[0] = %d\n", arr[0]);// 用指针方式访问首元素printf("*arr = %d\n",*arr);return0;}

运行结果

数组名arr的地址:0x7ffeefbff560 &arr[0]的地址:0x7ffeefbff560 arr[0] = 10 *arr = 10 

从结果可以看出,arr&arr[0] 指向的是同一块内存地址。这就是数组名的隐式转换特性。

⚠️ 注意事项

  1. 数组名不是真正的指针变量,它是一个地址常量,不能被修改。比如 arr++ 这种写法是非法的。
  2. 当数组名作为 sizeof 操作符的参数时,不会发生隐式转换,此时 sizeof(arr) 计算的是整个数组的内存大小。

48.1.2 指针算术运算操作数组元素

指针的算术运算(加减整数)是操作数组的核心技巧。指针每加1,偏移的字节数等于其指向数据类型的大小。
我们可以用指针替代数组下标,实现更高效的数组遍历:

#include<stdio.h>intmain(){int arr[5]={10,20,30,40,50};// 定义指针指向数组首元素int*p = arr;int i;for(i =0; i <5; i++){// 指针算术运算:p+i 指向第i个元素printf("arr[%d] = %d,*(p+%d) = %d\n", i, arr[i], i,*(p+i));}return0;}

运行结果

arr[0] = 10,*(p+0) = 10 arr[1] = 20,*(p+1) = 20 arr[2] = 30,*(p+2) = 30 arr[3] = 40,*(p+3) = 40 arr[4] = 50,*(p+4) = 50 

从代码中可以得出结论:arr[i] 等价于 *(arr+i),也等价于 *(p+i)

💡 性能技巧:在循环遍历数组时,使用指针操作的效率略高于下标操作。因为下标操作需要计算 arr+i 的地址,而指针可以直接通过自增实现偏移。

48.2 二维数组的指针访问:多维数组的内存布局

二维数组是C语言开发中处理表格数据的常用结构。理解二维数组的内存布局,才能用指针灵活操作它。

48.2.1 二维数组的内存本质

二维数组在内存中是连续存储的,不存在“行”和“列”的物理分隔。比如 int arr[2][3] = {{1,2,3},{4,5,6}},它的内存布局是:

地址偏移 → 0 4 8 12 16 20 元素值 → 1 2 3 4 5 6 

其中每个 int 类型占4个字节,所以相邻元素的地址偏移量为4。

二维数组的数组名 arr 可以看作是指向一维数组的指针arr 指向第一行的一维数组 arr[0]arr+1 指向第二行的一维数组 arr[1]

48.2.2 用指针访问二维数组元素

我们可以通过三种方式访问二维数组的元素:下标法、数组名指针法、普通指针法。

#include<stdio.h>intmain(){int arr[2][3]={{1,2,3},{4,5,6}};// 方式1:下标法printf("下标法访问:arr[1][2] = %d\n", arr[1][2]);// 方式2:数组名指针法:arr[i][j] 等价于 *(*(arr+i)+j)printf("数组名指针法:*(*(arr+1)+2) = %d\n",*(*(arr+1)+2));// 方式3:普通指针法:将二维数组看作一维数组int*p =&arr[0][0];printf("普通指针法:*(p+5) = %d\n",*(p+5));return0;}

运行结果

下标法访问:arr[1][2] = 6 数组名指针法:*(*(arr+1)+2) = 6 普通指针法:*(p+5) = 6 

⚠️ 注意事项

  1. 二维数组的指针 arr 是指向一维数组的指针,其类型为 int (*)[3],不能直接赋值给 int * 类型的指针。
  2. 只有当普通指针指向二维数组的首元素地址时,才能用 *(p+i) 的方式访问元素。

48.3 实战案例:指针实现数组的高效拷贝与逆序

掌握指针与数组的关联后,我们可以用指针实现更高效的数组操作。下面是两个实际开发中常用的案例。

48.3.1 案例1:指针实现数组拷贝函数

要求:编写一个函数,用指针将源数组的内容拷贝到目标数组,要求不使用下标。

#include<stdio.h>#include<string.h>// 数组拷贝函数:src源数组,dest目标数组,len数组长度voidarr_copy(int*src,int*dest,int len){int*p_src = src;int*p_dest = dest;// 循环拷贝每个元素while(len--){*p_dest++=*p_src++;}}intmain(){int src_arr[5]={1,2,3,4,5};int dest_arr[5]={0};int i;// 调用拷贝函数arr_copy(src_arr, dest_arr,5);// 打印目标数组printf("拷贝后的目标数组:");for(i =0; i <5; i++){printf("%d ", dest_arr[i]);}return0;}

运行结果

拷贝后的目标数组:1 2 3 4 5 

💡 技巧解析:函数中使用 *p_dest++ = *p_src++,先执行赋值操作,再将两个指针自增,实现了简洁高效的拷贝。

48.3.2 案例2:指针实现数组逆序

要求:编写一个函数,用指针将数组元素逆序排列,要求不使用额外数组空间。

#include<stdio.h>// 数组逆序函数:arr待逆序数组,len数组长度voidarr_reverse(int*arr,int len){// 指向数组首元素int*start = arr;// 指向数组尾元素int*end = arr + len -1;int temp;// 首尾交换,直到指针相遇while(start < end){ temp =*start;*start =*end;*end = temp; start++; end--;}}intmain(){int arr[5]={1,2,3,4,5};int i;printf("逆序前的数组:");for(i =0; i <5; i++){printf("%d ", arr[i]);}// 调用逆序函数arr_reverse(arr,5);printf("\n逆序后的数组:");for(i =0; i <5; i++){printf("%d ", arr[i]);}return0;}

运行结果

逆序前的数组:1 2 3 4 5 逆序后的数组:5 4 3 2 1 

💡 技巧解析:通过首尾两个指针向中间移动,交换对应位置的元素,空间复杂度为O(1),是最优的数组逆序实现方式。

48.4 内存视角的总结:指针与数组的核心区别

很多开发者会混淆指针和数组,我们从内存角度总结二者的核心区别:

对比维度数组名指针变量
内存属性地址常量,不能修改指向变量,可以修改指向
sizeof计算计算整个数组的内存大小计算指针本身的大小(32位系统4字节,64位系统8字节)
初始化方式int arr[5] = {1,2,3,4,5}int *p = arr

本章核心结论

  1. 数组名在表达式中会隐式转换为指向首元素的指针,但它不是真正的指针变量。
  2. arr[i] 等价于 *(arr+i),指针算术运算是操作数组的高效方式。
  3. 二维数组在内存中连续存储,可通过指向一维数组的指针或普通指针访问。

Read more

机器人架构搭建核心准则:先论文论证,后工程落地

机器人架构搭建核心准则:先论文论证,后工程落地

原创声明:本文为原创技术干货,基于真实工程实践总结,未经授权严禁转载与篡改。 本文写给那些正在或将要主导机器人架构的技术决策者与一线工程师——无论你是CTO、架构师,还是嵌入式开发、算法工程师,只要你关心如何让机器人项目不再烂尾,这篇文章值得你读完。 注意:文中反复出现的“论文”,特指“工程论文”(区别于学术论文),是一份写给团队自己的工程蓝图。请务必读完第二部分的定义,再决定是否认同。 核心观点 在机器人架构设计与实施过程中,先完成系统性论文论证,再开展工程化架构落地,是保障项目可行、流程闭环、资源高效利用的核心前提,也是区分专业机器人架构师与无序开发的关键标准。 金句:先论文后落地,本质上是用确定性的逻辑推导,去对抗不确定性的物理世界。 一、行业普遍认知误区 当前机器人领域从业者普遍存在开发误区:直接跳过前期规划与逻辑论证,盲目开展硬件采购、框架搭建、代码开发与接口调试,将功能拼接等同于架构设计。这种模式缺乏顶层逻辑支撑与可行性验证,本质是无方向的盲目实施,也是多数机器人项目停滞、返工、烂尾的核心诱因。 这种开发就像农村自建房,凭感觉垒砖,从不考虑地质勘测和结构力学

By Ne0inhk
宇树科技Go2机器人强化学习(RL)开发实操指南

宇树科技Go2机器人强化学习(RL)开发实操指南

在Go2机器人的RL开发中,环境配置、模型训练、效果验证与策略部署的实操步骤是核心环节。本文基于宇树科技官方文档及开源资源,以Isaac Gym和Isaac Lab两大主流仿真平台为核心,提供从环境搭建到实物部署的全流程操作步骤,覆盖关键命令与参数配置,帮助开发者快速落地RL开发。 一、基础准备:硬件与系统要求 在开始操作前,需确保硬件与系统满足RL开发的基础需求,避免后续因配置不足导致训练中断或性能瓶颈。 类别具体要求说明显卡NVIDIA RTX系列(显存≥8GB)需支持CUDA加速,Isaac Gym/Isaac Lab均依赖GPU进行仿真与训练操作系统Ubuntu 18.04/20.04/22.04推荐20.04版本,兼容性最佳,避免使用Windows系统(部分依赖不支持)显卡驱动525版本及以上需与CUDA版本匹配(如CUDA 11.3对应驱动≥465.19.01,CUDA 11.8对应驱动≥520.61.05)软件依赖Conda(

By Ne0inhk
【FPGA】Vivado 保姆级安装教程 | 从官网下载安装包开始到安装完毕 | 每步都有详细截图说明 | 支持无脑跟装

【FPGA】Vivado 保姆级安装教程 | 从官网下载安装包开始到安装完毕 | 每步都有详细截图说明 | 支持无脑跟装

安装包下载:Xilinx_Vivado Download Link(下好后可直接安装) 目录 (有安装包后,可直接跳转至 Step5,免得去官网下了,比较麻烦) Step1:进入官网 Step2:注册账号 Step3:进入下载页面 Step4:下载安装包 Step5:安装 Step6:等待软件安装完成 安装完成 Step1:进入官网 ① 我们可以选择在 XILINX 官网下载其公司旗下的产品 Vivado 🔍 官网地址:www.xilinx.com           (英文)www.china.xilinx.com  (官方中文网站) 👉 点击直达:Xilinx - Adaptable. Intelligent | together we advance_    (英文)

By Ne0inhk
【 AR眼镜】核心技术详解:硬件架构、核心算法、应用场景与发展趋势

【 AR眼镜】核心技术详解:硬件架构、核心算法、应用场景与发展趋势

文章目录 * 目录 * 引言 * 一、AI眼镜核心硬件架构 * 二、AI眼镜核心技术栈(软件+算法) * 2.1 环境感知技术(核心:计算机视觉) * 2.2 AI计算技术(核心:边缘智能) * 2.3 人机交互技术(核心:自然交互) * 三、AI眼镜软件生态与应用场景 * 3.1 软件生态架构 * 3.2 核心应用场景(行业+消费) * 四、AI眼镜关键技术挑战与解决方案 * 五、AI眼镜未来发展趋势 * 5.1 技术趋势 * 5.2 行业趋势 * 六、总结 目录 引言 若对您有帮助的话,请点赞收藏加关注哦,

By Ne0inhk