C语言指针与数组的深度关联及实战应用

C语言指针与数组的深度关联及实战应用

C语言指针与数组的深度关联及实战应用

在这里插入图片描述

💡 学习目标:掌握指针与数组的内在联系,熟练运用指针操作数组元素,解决实际开发中的数组遍历、数据交换等问题;学习重点:数组名的本质、指针算术运算操作数组、指针数组与数组指针的区别及应用。

38.1 数组名与指针的关系

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

38.1.1 数组名的本质

💡 数组名在大多数情况下会被编译器隐式转换为指向数组首元素的常量指针
我们来看一段简单的代码:

#include<stdio.h>intmain(){int arr[5]={10,20,30,40,50};printf("数组首元素地址:%p\n", arr);printf("数组首元素地址:%p\n",&arr[0]);printf("数组首元素值:%d\n",*arr);return0;}

运行结果:

数组首元素地址:0x7ffeefbff560 数组首元素地址:0x7ffeefbff560 数组首元素值:10 

从结果可以看出,arr&arr[0] 表示的是同一个地址,都是数组首元素的地址。
使用 *arr 可以直接访问数组的首元素,这就验证了数组名可以被当作指针使用。

⚠️ 注意:数组名是常量指针,不能被修改。
以下代码是错误的:

int arr[5]; arr++;// 错误,数组名是常量,不能进行自增操作

38.1.2 数组下标与指针的等价关系

💡 C语言规定,数组下标访问 arr[i] 等价于指针访问 *(arr + i)
这个等价关系是指针操作数组的核心,我们可以通过指针算术运算来访问数组的任意元素。
示例代码:

#include<stdio.h>intmain(){int arr[5]={10,20,30,40,50};int i;for(i =0; i <5; i++){printf("arr[%d] = %d, *(arr + %d) = %d\n", i, arr[i], i,*(arr + i));}return0;}

运行结果:

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

可以看到,两种访问方式的结果完全一致。
指针算术运算 arr + i 会根据数组元素的类型自动计算偏移量,int 类型的元素每个占4字节,arr + 1 就会偏移4字节,指向数组的下一个元素。

38.2 指针操作数组的实战案例

掌握了数组和指针的关系后,我们就可以用指针来实现各种数组操作,让代码更简洁高效。

38.2.1 案例1:指针遍历数组并求和

🔧 需求:定义一个整型数组,使用指针遍历数组所有元素,计算元素总和。

#include<stdio.h>intmain(){int arr[6]={1,2,3,4,5,6};int sum =0;int*p = arr;// 指针p指向数组首元素int len =sizeof(arr)/sizeof(arr[0]);// 计算数组长度// 使用指针遍历数组for(int i =0; i < len; i++){ sum +=*p; p++;// 指针自增,指向下一个元素}printf("数组元素总和:%d\n", sum);return0;}

运行结果:

数组元素总和:21 

💡 技巧:sizeof(arr) / sizeof(arr[0]) 是计算数组长度的通用方法,适用于任意类型的数组。

38.2.2 案例2:指针实现数组元素逆序存放

🔧 需求:定义一个整型数组,使用指针将数组元素逆序存放,要求不使用额外数组空间。

#include<stdio.h>voidreverseArray(int*arr,int len){int*left = arr;// 指向数组首元素int*right = arr + len -1;// 指向数组尾元素int temp;while(left < right){// 交换两个指针指向的元素 temp =*left;*left =*right;*right = temp; left++;// 左指针右移 right--;// 右指针左移}}intmain(){int arr[5]={10,20,30,40,50};int len =sizeof(arr)/sizeof(arr[0]);int*p = arr;printf("原数组:");for(int i =0; i < len; i++){printf("%d ",*(p + i));}printf("\n");reverseArray(arr, len);printf("逆序数组:");for(int i =0; i < len; i++){printf("%d ",*(p + i));}printf("\n");return0;}

运行结果:

原数组:10 20 30 40 50 逆序数组:50 40 30 20 10 

⚠️ 注意:函数参数中的数组名会被直接当作指针处理,在函数内部使用 sizeof(arr) 得到的是指针的大小,而不是数组的实际大小。

38.3 指针数组与数组指针的区别

在实际开发中,指针数组和数组指针是两个容易混淆的概念,二者的用途截然不同。

38.3.1 指针数组

💡 指针数组是存放指针的数组,数组的每个元素都是一个指针变量。
定义格式类型 *数组名[数组长度];
示例:定义一个指针数组存放3个字符串的地址

#include<stdio.h>intmain(){char*strArr[3]={"C语言","指针","数组"};// 指针数组for(int i =0; i <3; i++){printf("%s\n", strArr[i]);}return0;}

运行结果:

C语言 指针 数组 

指针数组的核心是数组,数组的每个元素都是指针类型,常用于存放多个字符串或者多个一维数组的地址。

38.3.2 数组指针

💡 数组指针是指向整个数组的指针,它指向的是一个数组整体,而不是单个元素。
定义格式类型 (*指针名)[数组长度];
示例:使用数组指针遍历二维数组

#include<stdio.h>intmain(){int arr[2][3]={{1,2,3},{4,5,6}};int(*p)[3]= arr;// 数组指针,指向包含3个int元素的数组// 遍历二维数组for(int i =0; i <2; i++){for(int j =0; j <3; j++){printf("%d ",*(*(p + i)+ j));}printf("\n");}return0;}

运行结果:

1 2 3 4 5 6 

⚠️ 注意:数组指针的定义中,(*p) 的括号不能省略。
如果省略括号,int *p[3] 就变成了指针数组,二者的含义完全不同。

38.4 常见问题与解决方案

38.4.1 问题1:指针越界访问数组

❌ 错误代码:

int arr[3]={1,2,3};int*p = arr;for(int i =0; i <5; i++){printf("%d\n",*p++);// 越界访问,会读取到随机值}

✅ 解决方案:

  1. 严格根据数组长度控制指针的访问范围,避免循环次数超过数组元素个数。
  2. 使用 sizeof 计算数组长度,确保遍历范围准确。

38.4.2 问题2:混淆指针数组与数组指针

❌ 错误原因:定义时缺少括号,或者对二者的指向对象理解不清。
✅ 解决方案:

  1. 牢记定义格式:指针数组是类型 *数组名[],数组指针是类型 (*指针名)[]
  2. 指针数组的元素是指针,数组指针指向的是整个数组。

38.5 本章小结

✅ 数组名在大多数情况下会被转换为指向首元素的常量指针,arr[i] 等价于 *(arr + i)
✅ 可以通过指针算术运算高效操作数组,实现遍历、求和、逆序等功能。
✅ 指针数组是存放指针的数组,数组指针是指向整个数组的指针,二者定义和用途不同。
✅ 操作数组时要避免指针越界,严格控制访问范围。

Read more

【GitHub项目推荐--ORB-SLAM3:开源视觉、视觉惯性及多地图SLAM库】

简介 ORB-SLAM3 是由UZ-SLAMLab开发的开源实时SLAM(Simultaneous Localization And Mapping,同时定位与建图)库,于2021年12月22日发布V1.0版本。作为ORB-SLAM系列的最新演进,它是首个能够使用单目、双目和RGB-D相机,结合针孔与鱼眼镜头模型,执行视觉、视觉惯性及多地图SLAM的实时库。在各类传感器配置下,ORB-SLAM3均展现出与文献中最佳系统相当的鲁棒性,并在精度上显著超越。该项目不仅为学术界提供了强大的研究基准,也为工业界提供了可直接部署的高精度定位与建图解决方案。 核心价值: * 多模态融合:首次统一支持纯视觉、视觉惯性及多地图SLAM * 传感器全面:兼容单目、双目、RGB-D相机,支持针孔与鱼眼模型 * 精度领先:在多个标准数据集上实现当前最高的定位精度 * 实时性能:在普通计算机上即可实现实时处理 技术定位:ORB-SLAM3代表了视觉SLAM技术的前沿水平,通过引入惯性测量单元(IMU)融合和多地图系统,解决了长期运行中的尺度漂移、累积误差和场景变化适应等关键挑战。其开源特性促进了

By Ne0inhk

从SVN到Git的平滑迁移:svn2git工具完整实践指南

从SVN到Git的平滑迁移:svn2git工具完整实践指南 【免费下载链接】svn2git 项目地址: https://gitcode.com/gh_mirrors/sv/svn2git 还在为版本控制系统迁移而烦恼吗?传统的SVN到Git迁移过程复杂且容易出错,但有了svn2git这个强大的自动化工具,你可以在几分钟内完成整个迁移过程。svn2git是一个基于Ruby开发的智能迁移工具,能够将SVN仓库完整转换为Git格式,同时保留分支、标签和提交历史的完整性。 🎯 迁移痛点与解决方案 常见迁移问题分析: * 分支结构混乱,难以识别主干和分支 * 标签信息丢失,版本追踪困难 * 提交记录不完整,历史追溯受阻 * 需要大量手动配置和人工干预 svn2git的智能应对: * 自动识别SVN标准布局(trunk、branches、tags) * 智能转换分支为Git原生分支 * 准确映射标签为Git标签对象 * 保持完整的提交历史记录 🚀 核心迁移流程详解 svn2git的核心迁移逻辑基于两个关键模块:lib/svn2git.rb和lib/svn2

By Ne0inhk
Anthropic 的“围墙花园”:为何 Claude Code 突然封杀第三方工具?一场关于成本、控制权与开源的战争

Anthropic 的“围墙花园”:为何 Claude Code 突然封杀第三方工具?一场关于成本、控制权与开源的战争

近期,Anthropic 对其 Claude Code 订阅服务的 API 使用政策进行了激进调整,引发了全球开发者社区的强烈震荡。这场突如其来的“封杀”,表面上是一次服务条款(ToS)的合规执行,实则揭示了顶级 AI 厂商在算力成本高企、商业化压力剧增的当下,对于生态控制权和用户入口的深层焦虑。 本文将深入剖析这一事件的始末,透过技术表象,探讨其背后的经济逻辑与战略意图。 突如其来的“封杀令”:从默许到禁止 事件的导火索在于 Anthropic 发布的一项强制性更新。用户突然发现,他们购买的 Pro 或 Team 计划订阅凭证(OAuth token)无法再用于 Cursor、OpenCode 等第三方开发工具。系统直接弹出警告:“此凭证仅授权用于 Claude Code,不得用于其他 API 请求”,。 在此之前,开发者利用订阅计划(如每月

By Ne0inhk

Docker部署iptvnator:打造家庭媒体中心的开源解决方案

Docker部署iptvnator:打造家庭媒体中心的开源解决方案 【免费下载链接】iptvnator 项目地址: https://gitcode.com/GitHub_Trending/ip/iptvnator 在数字化时代,家庭媒体中心已成为现代生活的重要组成部分。然而,许多用户面临IPTV播放不稳定、广告干扰和功能受限等问题。本文将介绍如何使用Docker部署iptvnator开源播放器,构建一个稳定、可控的IPTV服务器,实现家庭媒体中心的高效搭建。通过Docker容器化技术,即使是基础Linux知识的用户也能轻松部署和管理这一开源播放器,享受个性化的媒体体验。 IPTV媒体中心的价值与架构解析 iptvnator作为一款基于Tauri和Angular构建的开源IPTV播放器,支持m3u/m3u8播放列表格式,为用户提供了构建个人媒体中心的理想选择。其核心价值体现在三个方面:首先,开源特性确保了代码的透明度和可定制性;其次,跨平台支持让用户可以在多种设备上无缝使用;最后,丰富的功能集满足了从简单播放到高级管理的全场景需求。 系统架构解析 iptvnator采用现代

By Ne0inhk