C语言指针与数组(不适合初学者版):一篇文章带你深入了解指针与数组!
🎈个人主页:JAMES别扣了
💕在校大学生一枚。对IT有着极其浓厚的兴趣
✨系列专栏目前为C语言初阶、后续会更新c语言的学习方法以及c题目分享.
😍希望我的文章对大家有着不一样的帮助,欢迎大家关注我,我也会回关,大家一起交流一起互动,感谢大家的多多支持哈!🎉欢迎 👍点赞✍评论⭐收藏
前言
指针在C语言的版块中是有着极其重要的作用,通过两篇关于指针基础文章以及读者不断的代码实现可以很好掌握指针的基础知识,接下来我将结合C语言中数组方面的知识给读者们展示不一样的指针内容,这个系列文章我会写三篇左右,谢谢大家支持哈!
往期相关内容高质量文章(93+质量分)
C语言数组:一篇文章让你秒懂基础!-CSDN博客
C语言指针(上):一篇文章让你秒懂基础!-CSDN博客
C语言指针(下):一篇文章让你秒懂基础!(5000字)-CSDN博客
1.数组名的理解
在之前的数组文章中,我们一起探讨过数组的基本知识,现在让我们更深一步理解数组的相关概念。
这⾥我们使⽤ &arr[0] 的⽅式拿到了数组第⼀个元素的地址,但是其实数组名本来就是地址,⽽且 是数组⾸元素的地址,我们来做个测试。
#include <stdio.h>int main(){int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("&arr[0] = %p\n", &arr[0]);printf("arr = %p\n", arr)return 0;
}
输出结果:
我们发现数组名和数组⾸元素的地址打印出的结果⼀模⼀样,数组名就是数组⾸元素(第⼀个元素)的地 址。
这时候有读者会有疑问?数组名如果是数组⾸元素的地址,那下⾯的代码怎么理解呢?
#include <stdio.h>int main(){int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("%d\n", sizeof(arr));return 0;}
输出的结果是:40,如果arr是数组⾸元素的地址,那输出应该的应该是4/8才对。 其实数组名就是数组⾸元素(第⼀个元素)的地址是对的,但是有两个例外:
• sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩, 单位是字节
• &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素 的地址是有区别的)
除此之外,任何地⽅使⽤数组名,数组名都表⽰⾸元素的地址。
这时有好奇的同学,在试⼀下这个代码:
#include <stdio.h>int main(){int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("&arr[0] = %p\n", &arr[0]);printf("arr = %p\n", arr);printf("&arr = %p\n", &arr);return 0;
)
哈哈,这时会有读者问那么arr与&arr有什么区别么?
#include <stdio.h>int main(){int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("&arr[0] = %p\n", &arr[0]);printf("&arr[0]+1 = %p\n", &arr[0]+1);
printf("arr = %p\n", arr);printf("arr+1 = %p\n", arr+1);
printf("&arr = %p\n", &arr);
printf("&arr+1 = %p\n", &arr+1);
return 0;}
输出结果:
&arr[0] = 0077F820
&arr[0]+1 = 0077F824
arr=0077F820
arr+1=0077F824
&arr=0077F820
&arr+1 = 0077F848
这⾥我们发现&arr[0]和&arr[0]+1相差4个字节,arr和arr+1相差4个字节,是因为&arr[0]和arr都是 ⾸元素的地址,+1就是跳过⼀个元素。 但是&arr和&arr+1相差40个字节,这就是因为&arr是数组的地址,+1操作是跳过整个数组的。 到这⾥⼤家应该搞清楚数组名的意义了吧。
2. 使⽤指针访问数组
有了前⾯知识的⽀持,再结合数组的特点,我们就可以很⽅便的使⽤指针访问数组了。
#include <stdio.h>int main(){int arr[10] = {0}; //输⼊int i = 0;int sz = sizeof(arr)/sizeof(arr[0]); //输⼊int* p = arr;for(i=0; i<sz; i++){scanf("%d", p+i);//scanf("%d", arr+i);//也可以这样写} //输出for(i=0; i<sz; i++){printf("%d ", *(p+i));}return 0;}
这个代码搞明⽩后,我们再试⼀下,如果我们再分析⼀下,数组名arr是数组⾸元素的地址,可以赋值 给p,其实数组名arr和p在这⾥是等价的。那我们可以使⽤arr[i]可以访问数组的元素,那p[i]是否也可 以访问数组呢?
#include <stdio.h>int main(){int arr[10] = {0}; //输⼊int i = 0;int sz = sizeof(arr)/sizeof(arr[0]); //输⼊int* p = arr;for(i=0; i<sz; i++){scanf("%d", p+i);//scanf("%d", arr+i);//也可以这样写} //输出for(i=0; i<sz; i++){printf("%d ", p[i]);}return 0;}
将*(p+i)换成p[i]也是能够正常打印的,所以本质上p[i]是等价于*(p+i)。
同理arr[i] 应该等价于*(arr+i),数组元素的访问在编译器处理的时候,也是转换成⾸元素的地址+偏移 量求出元素的地址,然后解引⽤来访问的。
3. ⼀维数组传参的本质
数组我们学过了,之前也讲了,数组是可以传递给函数的,这个⼩节我们讨论⼀下数组传参的本质。 ⾸先从⼀个问题开始,我们之前都是在函数外部计算数组的元素个数,那我们可以把函数传给⼀个函 数后,函数内部求数组的元素个数吗?
#include <stdio.h>void test(int arr[]){int sz2 = sizeof(arr)/sizeof(arr[0]);printf("sz2 = %d\n", sz2);}int main(){int arr[10] = {1,2,3,4,5,6,7,8,9,10};int sz1 = sizeof(arr)/sizeof(arr[0]);printf("sz1 = %d\n", sz1);test(arr);return 0;}
输出的结果:
我们发现在函数内部是没有正确获得数组的元素个数。
这就要学习数组传参的本质了,上个⼩节我们学习了:数组名是数组⾸元素的地址;那么在数组传参 的时候,传递的是数组名,也就是说本质上数组传参本质上传递的是数组⾸元素的地址。 所以函数形参的部分理论上应该使⽤指针变量来接收⾸元素的地址。那么在函数内部我们写 sizeof(arr) 计算的是⼀个地址的⼤⼩(单位字节)⽽不是数组的⼤⼩(单位字节)。正是因为函 数的参数部分是本质是指针,所以在函数内部是没办法求的数组元素个数的。
void test(int arr[])//参数写成数组形式,本质上还是指针printf("%d\n", sizeof(arr));}void test(int* arr)//参数写成指针形式{printf("%d\n", sizeof(arr));//计算⼀个指针变量的⼤⼩}int main(){int arr[10] = {1,2,3,4,5,6,7,8,9,10};test(arr);return 0;}{
结论:⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。
4.⼆级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪⾥?答案是:更高级别的指针!
这就是 ⼆级指针。
对于⼆级指针的运算有:
1.*ppa 通过对ppa中的地址进⾏解引⽤,这样找到的是
int b = 20;
*ppa = &b;// 等价于 pa = &b; pa , *ppa 其实访问的就是 pa .
2.**ppa 先通过 *ppa 找到 pa ,然后对pa进行解应用操作:*pa,那找到的是a。
**ppa = 30;
// 等价于 *pa = 30;
// 等价于 a = 30;
5. 指针数组
指针数组是指针还是数组? 我们类⽐⼀下,整型数组,是存放整型的数组,字符数组是存放字符的数组。 那指针数组呢?是存放指针的数组.
指针数组的每个元素都是⽤来存放地址(指针)的。 如下图:
指针数组的每个元素是地址,⼜可以指向⼀块区域.
6. 指针数组模拟⼆维数组
#include <stdio.h>int main(){int arr1[] = {1,2,3,4,5};int arr2[] = {2,3,4,5,6};int arr3[] = {3,4,5,6,7};//数组名是数组⾸元素的地址,类型是int*的,就可以存放在parr数组中int* parr[3] = {arr1, arr2, arr3};int i = 0;int j = 0;for(i=0; i<3; i++){for(j=0; j<5; j++){printf("%d ", parr[i][j]);}printf("\n");}
return 0;}
parr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型⼀维数组,parr[i][j]就是整型⼀维数 组中的元素。 上述的代码模拟出⼆维数组的效果,实际上并⾮完全是⼆维数组,因为每⼀⾏并⾮是连续的。
总结
C语言中数组与指针的深入探索
在C语言编程中,数组和指针是两个紧密相关的概念。数组是一种数据结构,用于存储相同类型的元素集合;而指针则是一种变量,用于存储另一个变量的内存地址。理解数组和指针之间的关系,对于深入掌握C语言至关重要。
一、数组名的理解
在C语言中,数组名实际上是一个指向数组首元素的常量指针。这意味着数组名本身并不表示整个数组,而是指向数组第一个元素的地址。因此,我们不能对数组名进行赋值操作,但可以获取其地址或进行解引用操作。
二、使用指针访问数组
通过指针,我们可以直接访问数组中的元素。假设我们有一个整型数组int arr[5];,我们可以使用指针int *p = arr;来指向数组的首元素。此时,*p就表示数组的第一个元素,*(p+1)表示第二个元素,以此类推。通过这种方式,我们可以遍历整个数组。
三、一维数组传参的本质
在C语言中,当我们将一维数组作为参数传递给函数时,实际上传递的是数组首元素的地址。因此,函数内部接收到的参数实际上是一个指针,指向数组的首元素。这使得我们可以在函数内部通过指针来访问和修改数组的元素。
四、二级指针
二级指针是指向指针的指针。它的声明形式为int **pp;,其中pp是一个指向整型指针的指针。二级指针常用于动态内存分配、函数返回多个值以及处理指针数组等场景。
五、指针数组
指针数组是指数组的每个元素都是指针。例如,int *pArr[5];表示一个包含5个整型指针的数组。每个指针可以指向一个整型变量或整型数组的首元素。指针数组常用于存储多个字符串的地址或处理多个动态分配的数组。
六、指针数组模拟二维数组
在C语言中,二维数组在内存中是连续存储的,但我们可以使用指针数组来模拟二维数组的行为。通过为每个指针分配一个一维数组,我们可以创建一个不规则的“二维数组”。这种方式在处理稀疏矩阵或动态调整数组大小时非常有用。
通过上述内容的阐述,我们可以看到数组和指针在C语言中的紧密关系。理解并掌握这些知识点,不仅有助于我们更加灵活地操作数组和指针,还能提升我们的编程能力和代码质量。希望本文对你有所帮助,祝你学习进步!
相关文章:

C语言指针与数组(不适合初学者版):一篇文章带你深入了解指针与数组!
🎈个人主页:JAMES别扣了 💕在校大学生一枚。对IT有着极其浓厚的兴趣 ✨系列专栏目前为C语言初阶、后续会更新c语言的学习方法以及c题目分享. 😍希望我的文章对大家有着不一样的帮助,欢迎大家关注我,我也会回…...
springboot Mongo大数据查询优化方案
前言 因为项目需要把传感器的数据保存起来,当时设计的时是mongo来存储,后期需要从mongo DB里查询传感器的数据记录。由于传感器每秒都会像mongo数据库存500条左右的数据,1天就有4320万条数据,要想按照时间条件去查询,…...

Ollama管理本地开源大模型,用Open WebUI访问Ollama接口
现在开源大模型一个接一个的,而且各个都说自己的性能非常厉害,但是对于我们这些使用者,用起来就比较尴尬了。因为一个模型一个调用的方式,先得下载模型,下完模型,写加载代码,麻烦得很。 对于程…...

Linux--基本知识入门
一.几个基本知识 终端: CtrlAltT 或者桌面/文件夹右键,打开终端切换为管理员: sudo su 退出:exit查看内核版本号: uname -a内核版本号含义: 5 代表主版本号;13代表次版本号;0代表修订版本号;30代表修订版本的第几次微调;数字越大表示内核越新. 二.目录…...

基于springboot+vue实现的大学计算机课程管理平台的设计与实现(全套资料)
一、系统架构 前端:vue | antv 后端:springboot | mybatis-plus 环境:jdk17 | mysql | maven | node | redis 二、代码及数据库 三、功能介绍 01. 登录页 02. 首页 03. 系统基础模块-用户管理 04. 系统基础模块-部门…...

LeetCode2115. 从给定原材料中找到所有可以做出的菜
拓扑排序 题面 题目链接:2115. 从给定原材料中找到所有可以做出的菜 - 力扣(LeetCode) 你有 n 道不同菜的信息。给你一个字符串数组 recipes 和一个二维字符串数组 ingredients 。第 i 道菜的名字为 recipes[i] ,如果你有它 所有…...

项目性能优化—性能优化的指标、目标
项目性能优化—性能优化的指标、目标 性能优化的终极目标是什么 性能优化的目标实际上是为了更好的用户体验: 一般我们认为用户体验是下面的公式: 用户体验 产品设计(非技术) 系统性能 ≈ 系统性能 快 那什么样的体验叫快呢…...
蓝桥杯刷题(三)
一、P8752 [蓝桥杯 2021 省 B2] 特殊年份(洛谷) 题目描述 今年是 2021 年,2021 这个数字非常特殊, 它的千位和十位相等, 个位比百位大 1,我们称满足这样条件的年份为特殊年份。 输入 5 个年份,请计算这里面有多少个…...
20240312-算法复习打卡day21||● 530.二叉搜索树的最小绝对差 ● 501.二叉搜索树中的众数 ● 236. 二叉树的最近公共祖先
530.二叉搜索树的最小绝对差 1.中序遍历得到升序数组 class Solution { private:vector<int> vec;void traversal(TreeNode* root) {if (root NULL) return;if (root->left) traversal(root->left);vec.push_back(root->val);if (root->right) traversal(r…...

今天我们来学习一下关于MySQL数据库
目录 前言: 1.MySQL定义: 1.1基础概念: 1.1.1数据库(Database): 1.1.2表(Table): 1.1.3记录(Record)与字段(Field): …...

长期护理保险可改善老年人心理健康 | CHARLS CLHLS CFPS 公共数据库周报(3.6)...
欢迎报名2024年“真实世界临床研究”课程! 本周郑老师开讲:“真实世界临床研究”培训班,3月16-17日两天,欢迎报名! CHARLS公共数据库 CHARLS数据库简介中国健康与养老追踪调查(China Health and Retirement Longitud…...

49、C++/友元、常成员函数和常对象、运算符重载学习20240314
一、封装类 用其成员函数实现(对该类的)数学运算符的重载(加法),并封装一个全局函数实现(对该类的)数学运算符的重载(减法)。 代码: #include <iostream…...

SQL Server错误:15404
执行维护计划失败,提示SQL Server Error 15404 无法获取有关... 异常如下图: 原因:数据库用户名与计算机名称不一致 解决办法:1.重名称数据库用户名 将前缀改成计算机名 2.重启SQL Server代理...

Halcon文件操作
1、Region读写操作 region(区域)是一种重要的数据类型,用于表示图像中的特定区域。这些区域可以代表图像中的目标、感兴趣的区域、边缘、形状等等 read_image (Image, printer_chip/printer_chip_01) dev_open_window (0, 0, 512, 512, black…...
【测试知识】业务面试问答突击版1
高内聚低耦合 高内聚指的是将相关的功能或数据组织在一起,使得模块内部的各个元素紧密地联系在一起,完成特定的任务。 低耦合指的是模块之间的依赖关系尽可能地降低,模块之间的接口简单清晰,减少模块之间的相互影响。 文章目录 整…...

使用el-row及el-col页面缩放时出现空行解决方案
问题: 当缩放到90%或者110%,选中下拉后,下方就会出现空行 如下图所示: 关于el-row 和 el-col : 参数说明类型可选值默认值span栅格占据的列数number—24offset栅格左侧的间隔格数number—0push栅格向右移动格数number…...

java中几种对象存储(文件存储)中间件的介绍
一、前言 在博主得到系统中使用的对象存储主要有OSS(阿里云的对象存储) COS(腾讯云的对象存储)OBS(华为云的对象存储)还有就是MinIO 这些玩意。其实这种东西大差不差,几乎实现方式都是一样&…...

网络工程师——2024自学
一、怎样从零开始学习网络工程师 当今社会,人人离不开网络。整个IT互联网行业,最好入门的,网络工程师算是一个了。 什么是网络工程师呢,简单来说,就是互联网从设计、建设到运行和维护,都需要网络工程师来…...

SwiftUI的Picker
SwiftUI的Picker 本章来记录一下SwiftUI中三种不同Picker的用法 ,分别为normalPicker , wheelPicker, segmentedPicker 。可以根据不同需求展示不同的Picker import SwiftUIstruct PickerBootCamp: View {State var selection: String &quo…...

物联网技术助力智慧城市转型升级:智能、高效、可持续
目录 一、物联网技术概述及其在智慧城市中的应用 二、物联网技术助力智慧城市转型升级的路径 1、提升城市基础设施智能化水平 2、推动公共服务智能化升级 3、促进城市治理现代化 三、物联网技术助力智慧城市转型升级的成效与展望 1、成效显著 2、展望未来 四、物联网技…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
生成 Git SSH 证书
🔑 1. 生成 SSH 密钥对 在终端(Windows 使用 Git Bash,Mac/Linux 使用 Terminal)执行命令: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 参数说明: -t rsa&#x…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...