C语言 —— 此去经年梦浪荡魂音 - 深入理解指针(卷二)

news2025/3/18 6:56:30

目录

1. 数组名与地址

2. 指针访问数组

3.一维数组传参本质

4.二级指针

5. 指针数组

6. 指针数组模拟二维数组 


1. 数组名与地址

我们先看下面这个代码:

int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

int* p = &arr[0];

这里我们使用 &arr[0] 的方式拿到了数组第⼀个元素的地址,但是其实数组名本来就是地址,而且是数组首元素的地址

  

数组名就是数组首元素(第⼀个元素)的地址,但是有两个例外:

1. sizeof(数组名):sizeof中单独放数组名,这⾥的数组名表示整个数组,计算的是整个数组的大小,单位是字节

#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;
}

 

 

2. &数组名:这⾥的数组名表示整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素的地址是有区别的)

#include <stdio.h>

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

	printf("%p\n", &arr);
	printf("%p\n", &arr + 1);//增加了40个字节,也就是整个数组的大小

	return 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[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]和&arr[0]+1相差4个字节,arr和arr+1 相差4个字节,是因为&arr[0] 和 arr 都是⾸元素的地址,+1就是跳过⼀个元素

    
但是&arr 和 &arr+1相差40个字节,这就是因为&arr是数组的地址,+1 操作是跳过整个数组的


2. 指针访问数组

#define _CRT_SECURE_NO_WARNINGS
#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));
      //printf("%d ", p[i]);也可以这样写
	}

	return 0;
}

将 *(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) 计算的是⼀个地址的大小(单位字节)而不是数组的大小(单位字节),因为函数的参数部分是本质是指针,所以在函数内部是没办法求的数组元素个数的

总结:⼀维数组传参,形参的部分可以写成 int * arr 的指针形式,也可以写成 arr[ ] 的数组形式

 


4.二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪⾥?答案是⼆级指针

  

一个常见的指针是一级指针,那么在一个指针里面再嵌套一个指针就是二级指针

 

*ppa 通过对ppa中的地址进⾏解引⽤,这样找到的是 pa , *ppa 其实访问的就是 pa 

int b = 20;
*ppa = &b;//等价于 pa = &b;

 **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]就是整型⼀维数组中的元素 


完结撒花~ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2317069.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python实现简单的图片去水印工具

python实现简单的图片去水印工具 使用说明&#xff1a; 点击"打开图片"选择需要处理的图片 在图片上拖拽鼠标选择水印区域&#xff08;红色矩形框&#xff09; 点击"去除水印"执行处理 点击"保存结果"保存处理后的图片 运行效果 先简要说明…

使用dify+deepseek部署本地知识库

使用difydeepseek部署本地知识库 一、概述二、安装windows docker desktop1、确认系统的Hyper-v功能正常启用2、docker官网下载安装windows客户端3、安装完成后的界面如下所示 三、下载安装ollama四、部署本地deepseek五、本地下载部署dify5.1 下载dify的安装包5.2 将dify解压到…

【算法day13】最长公共前缀

最长公共前缀 https://leetcode.cn/problems/longest-common-prefix/submissions/612055945/ 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 “”。 class Solution { public:string longestCommonPrefix(vector<string&g…

Java高频面试之集合-13

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;为什么 hash 函数能降哈希碰撞&#xff1f; 哈希函数通过以下核心机制有效降低碰撞概率&#xff0c;确保不同输入尽可能映…

RGV调度算法(三)--遗传算法

1、基于时间窗 https://wenku.baidu.com/view/470e9fd8b4360b4c2e3f5727a5e9856a57122693.html?_wkts_1741880736197&bdQuery%E7%8E%AF%E7%A9%BF%E8%B0%83%E5%BA%A6%E7%AE%97%E6%B3%95 2.2019年MathorCup高校数学建模挑战赛B题 2019-mathorcupB题-环形穿梭机调度模型&a…

YOLOv8轻量化改进——Coordinate Attention注意力机制

现在针对YOLOv8的架构改进越来越多&#xff0c;今天尝试引入了Coordinate Attention注意力机制以改进对小目标物体的检测效率。 yolov8的下载和安装参考我这篇博客&#xff1a; 基于SeaShips数据集的yolov8训练教程_seaships处理成yolov8-CSDN博客 首先我们可以去官网找到CA注…

基于SpringBoot+Vue的驾校预约管理系统+LW示例参考

1.项目介绍 系统角色&#xff1a;管理员、普通用户、教练功能模块&#xff1a;用户管理、管理员管理、教练管理、教练预约管理、车辆管理、车辆预约管理、论坛管理、基础数据管理等技术选型&#xff1a;SpringBoot&#xff0c;Vue等测试环境&#xff1a;idea2024&#xff0c;j…

ONNX:统一深度学习工作流的关键枢纽

引言 在深度学习领域&#xff0c;模型创建与部署的割裂曾是核心挑战。不同框架训练的模型难以在多样环境部署&#xff0c;而 ONNX&#xff08;Open Neural Network Exchange&#xff09;作为开放式神经网络交换格式&#xff0c;搭建起从模型创建到部署的统一桥梁&#xff0c;完…

蓝桥杯————23年省赛 ——————平方差

3.平方差 - 蓝桥云课 一开始看题我还没有意识到问题的严重性 我丢&#xff0c;我想 的是用两层循环来做&#xff0c;后来我试了一下最坏情况&#xff0c;也就是l1 r 1000000000 结果运行半天没运行出来&#xff0c;我就知道坏了&#xff0c;孩子们&#xff0c;要出事&#…

一、串行通信基础知识

一、串行通信基础知识 1.处理器与外部设备通信有两种方式 并行通信&#xff1a;数据的各个位用多条数据线同时传输。&#xff08;传输速度快&#xff0c;但占用引脚资源多。&#xff09; 串行通信&#xff1a;将数据分成一位一位的形式在一条数据线上逐个传输。&#xff08;线路…

自带多个接口,完全免费使用!

做自媒体的小伙伴们&#xff0c;是不是经常为语音转文字的事儿头疼&#xff1f; 今天给大家推荐一款超实用的语音转文字软件——AsrTools&#xff0c;它绝对是你的得力助手&#xff01; AsrTools 免费的语音转文字软件 这款软件特别贴心&#xff0c;完全免费&#xff0c;而且操…

Qt QML解决SVG图片显示模糊的问题

前言 在QML中直接使用SVG图片&#xff0c;使用Image控件加载资源&#xff0c;显示出来图片是模糊的&#xff0c;很影响使用体验。本文介绍重新绘制SVG图片&#xff0c;然后注册到QML中使用。 效果图&#xff1a; 左边是直接使用Image加载资源显示的效果 右边是重绘后的效果 …

【Linux我做主】基础命令完全指南上篇

Linux基础命令完全指南【上篇】 Linux基础命令完全指南github地址前言命令行操作的引入Linux文件系统树形结构的根文件系统绝对路径和相对路径适用场景Linux目录下的隐藏文件 基本指令目录和文件相关1. ls2. cd和pwdcdpwd 3. touch4. mkdir5. cp6. mv移动目录时覆盖写入的两种特…

Designing Dashboards with SAP Analytics Cloud

Designing Dashboards with SAP Analytics Cloud

项目实战系列:基于瑞萨RA6M5构建多节点OTA升级-系统设计<一>

项目背景 原嵌入式控制系统采用分布式模块化架构&#xff0c;由12个功能板卡&#xff08;通信控制、信号采集、驱动执行等&#xff09;组成。系统维护阶段存在以下痛点&#xff1a; 低效的本地烧录机制&#xff1a;各板卡固件升级需通过JTAG接口逐一手动连接JLINK仿真器&#x…

《AI大模型趣味实战》 No3:快速搭建一个漂亮的AI家庭网站-相册/时间线/日历/多用户/个性化配色/博客/聊天室/AI管家(下)

《AI大模型趣味实战》 No3&#xff1a;快速搭建一个漂亮的AI家庭网站-相册/时间线/日历/多用户/个性化配色/博客/聊天室/AI管家(下) 摘要 本文介绍了家庭网站V1.3版本的更新内容&#xff0c;主要聚焦于AI管家功能的优化与完善。V1.3版本对AI管家模块进行了全面升级&#xff0…

c++基础知识-图论进阶

一、拓扑排序 1、基础知识 1&#xff09;什么是拓扑排序 对一个有向无环图G进行拓扑排序&#xff0c;是将G中所有顶点排成一个线性序列&#xff0c;使得图中任意一对顶点u和v&#xff0c;若&#xff0c;则u在线性序列中出现在v之前。 2&#xff09;拓扑排序的操作方法 重复执行…

[Java实战]Spring Boot服务CPU 100%问题排查:从定位到解决

Spring Boot服务CPU 100%问题排查&#xff1a;从定位到解决 1. 引言 当Spring Boot服务出现CPU占用率100%时&#xff0c;系统性能会急剧下降&#xff0c;甚至导致服务不可用。本文将通过真实代码案例&#xff0c;详细讲解如何快速定位问题根源&#xff0c;并提供解决方案。无…

1.6 极限存在准则

1.夹逼定理&#xff08;迫敛定理&#xff09; 1.1 数列型 1.1.1 准则 1.2 函数型 2. 两个重要极限