深度刨析指针Advanced 1

news2024/12/23 18:12:14

作者主页:paper jie的博客_CSDN博客-C语言,算法详解领域博主

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文录入于《系统解析C语言》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将C语言基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《C语言》《算法详解》《C语言-语法篇》

内容分享:本期对C语言中的指针的进阶知识进行进行具体讲解,各位看官姥爷快搬好小板凳坐好叭。

    -------- 不要998,不要98,只要一键三连,三连买不了吃亏,买不了上当

目录

😄前言

🤣回顾知识

🫠字符指针

😜指针数组

🤫 数组指针

🤔数组指针的定义

😶‍🌫️ &数组名和数组名

🤓数组指针的使用

😴 数组参数,指针参数

🤤一维数组传参

🫥二维数组传参

🤕一级指针传参

🤯二级指针传参

🥹总结


😄前言

在前面的《指针不可怕,请爱它呵护它》http://t.csdn.cn/m7yf2 这篇文章中,已经对指针的基础知识:指针是什么,指针的类型,野指针,二级指针指针的运算与使用这些知识进行了基础且具体的讲解。学完这些知识大家对平常中的指针问题已经基本可以解决了。但是指针的知识远远不止这些,接下来的内容可以在帮助大家对C语言中的指针再提高一个理解。

🤣回顾知识

1. 指针就是一个变量,用来存放地址,地址唯一标识一块内存空间。

2. 指针的大小就是固定的4/8个字节(32位平台/64位平台)

3. 指针是有类型,指针的类型决定了指针的+-整数的步长,指针解引用的权限。

4. 指针的运算

🫠字符指针

在指针的类型中我们知道有一种指针类型为字符指针char*,它一般这么使用

 还有一种方式大家看看:

 这个代码大家就是容易把const char* pstr认为里面存的是hello bit,但其实本质上里面存的是字符串首元素的地址。所以它解引用出来肯定也是首元素。用const是因为hello bit 是一个常量,不能被修改,就要用const限定。

 理解了上面的内容的话,我们看下面一道代码:

#include <stdio.h>
int main()
{
 char str1[] = "hello bit.";
 char str2[] = "hello bit.";
 const char *str3 = "hello bit.";
 const char *str4 = "hello bit.";
 if(str1 ==str2)
 printf("str1 and str2 are same\n");
 else
 printf("str1 and str2 are not same\n");
 
 if(str3 ==str4)
 printf("str3 and str4 are same\n");
 else
 printf("str3 and str4 are not same\n");
 
 return 0;
}

我们来分析一下为什么是这个结果:

C语言中,常量字符串一般都是储存到一块单独的内存空间。当几个指针同时指向这个字符串的时候,就是指向同一块内存,同一个地址。所以str3==str4

但是同相同的常量字符串去初始化不同的数组,因为数组随时都有可以发生不同的改变,为了安全起见,就会开辟不同的内存块。所以str1!=str2

😜指针数组

在《指针不可怕,请爱它呵护它》中我们也讲过了指针数组,它就是一个存放指针的数组。

🤫 数组指针

🤔数组指针的定义

数组指针是数组还是指针呢?答案当然是指针啦。我们在之前的文章中已经知道:

整型指针:int *p 能够指向整数据的指针

浮点数指针:float *pf 能够指针浮点数数据的指针

所以数组指针:能够指向数组的指针

判断一下,哪个是数组指针:

 解释:

注意:[]的优先级是高于*的,所以要加上()保证p和*先结合

😶‍🌫️ &数组名和数组名

这里有一个数组 int arr[10] ,我们知道arr是数组名,数组名是首元素地址。那这样的话,&arr又是什么捏?

通过代码观察:

 我们发现arr和&arr的地址都是一样的,难道它们是一样的含义吗?

接下来我们再看一段代码:

#include <stdio.h>
int main()
{
 int arr[10] = { 0 };
 printf("arr = %p\n", arr);
 printf("&arr= %p\n", &arr);
 printf("arr+1 = %p\n", arr+1);
 printf("&arr+1= %p\n", &arr+1);
 return 0;
}

通过代码,我们发现,虽然它们的地址一样,但是意义是不一样的。

实际上:&arr是数组的地址,不是数组首元素的地址。&arr加一是跳过整个数组,而arr加一是跳过一个元素 。

int(*arr)[10]中&arr的类型是int(*)[10],是一种数组指针。

🤓数组指针的使用

数组指针指向的是数组,那里面存放的就是数组的地址。

代码:

 一个数组指针的正常使用场景:

理解arr是数组首元素的地址,在二维数组中,首元素的地址就是第一行的地址,就可以用数组指针来接收。

//用数组指针打印二维数组
void print_arr2(int(*arr)[5], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf("%d ", *(*(arr + i)+j));
			//我们可以这么理解
			//*(arr+i)就是就是数组的地址&arr解引用得到了数组arr
			//arr在解引用就得到了元素
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15} };
	print_arr1(arr, 3, 5);
	//数组名arr,表示首元素的地址
	//但是二维数组的首元素是二维数组的第一行
	//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
	//可以数组指针来接收
	print_arr2(arr, 3, 5);
	return 0;
}

现在我们就可以理解下面代码的意思了:

😴 数组参数,指针参数

在写代码的时候难免要把数组或者指针传给函数,那函数的参数怎么写呢?

🤤一维数组传参

#include <stdio.h>
void test(int arr[])//ok?
//ok
//数组传参,数组接受,空格不影响,本质上函数是接受的首元素的地址,不会创建
{}
void test(int arr[10])//ok?
//ok
//理由同上
{}
void test(int* arr)//ok?
//ok
//arr就是一个整型地址,可以拿一个整型指针接收
{}
void test2(int* arr[20])//ok?
//ok
//指针数组传参,指针数组接收
{}
void test2(int** arr)//ok?
//ok
//arr2是指针数组首元素的地址就是==指针的地址==地址的地址
//拿二级指针接收
{}
int main()
{
	int arr[10] = { 0 };
	int* arr2[20] = { 0 };
	test(arr);
	test2(arr2);
}

🫥二维数组传参

void test(int arr[3][5])//ok?
//ok
//二维数组传参 二维数组接收
{}
void test(int arr[][])//ok?
//err
//不可以省略列
{}
void test(int arr[][5])//ok?
//ok
{}
//总结:二维数组传参,函数形参的设计只能省略第一个[]的数字。
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。
//这样才方便运算。
void test(int* arr)//ok?
//err
//arr是二维数组第一行的地址,是一个一维数组,不能用int类型的指针接收
{}
void test(int* arr[5])//ok?
//err
//参数只可以用二维数组或者数组指针接收
//他是指针数组
{}
void test(int(*arr)[5])//ok?
//ok
//他就是数组指针
{}
void test(int** arr)//ok?
//err
//它是二级指针
//arr是二维数组第一行的地址,只能用数组指针接收或者二维数组
{}
int main()
{
	int arr[3][5] = { 0 };
	test(arr);
}

🤕一级指针传参

#include <stdio.h>
void print(int* p, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		//p+i就是相当与指针指向的地址不断向后加一
		printf("%d\n", *(p + i));
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9 };
	//一级指针p存放的是arr首元素的地址
	int* p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	//一级指针p,传给函数
	print(p, sz);
	//p==arr
	return 0;
}

当函数参数部分为一级指针的时候,函数可以接收什么参数呢?

看代码:

void test1(int* p)
{}
//test1函数能接收什么参数?
//可以接收 arr数组的数组名 整型变量的地址 一级指针
void test2(char* p)
{}
//test2函数能接收什么参数?
//字符变量的地址 一级指针
int main()
{
	int a = 0;
	int arr[10] = { 0 };
	int* pa = &a;
	test1(&a);//整型变量的地址
	test1(pa);//pa就是整型a的地址
	test1(arr);//arr是首元素的地址

	char ch = 'w';
	char* p = &ch;
	test2(&ch); //字符变量的地址
	test2(p); // p这个指针变量中就存放了字符的地址
	return 0;
}

🤯二级指针传参

#include <stdio.h>
void test(int** ptr)//用二级指针接收
{
	printf("num = %d\n", **ptr);
}
int main()
{
	int n = 10;
	int* p = &n;//一级指针 存的是n的地址
	int** pp = &p;//二级指针 存的是一级指针p的地址
	test(pp);//传二级指针 就是传的一级指针的地址
	test(&p);// &p 取出的是一级指针p的地址
	return 0;
}

当函数的参数部分为二级指针时,函数可以接收什么参数呢?

代码:

void test(char** p)//二级指针接收
{

}
int main()
{
	char c = 'b';
	char* pc = &c;
	char** ppc = &pc;
	char* arr[10];//指针数组
	test(&pc); // &pc时取出一级指针pc的地址就是二级指针
	test(ppc);//ppc 是二级指针
	test(arr);//Ok?
	//ok
	//arr是指针数组首元素的地址,首元素是一级指针 所以它也相当于一个二级指针
	return 0;
}

🥹总结

对于指针的进阶,里面的内容还是很多的,我打算分两篇文章来介绍。这篇文章我们重点介绍了数组指针和数组的传参,指针的传参。以代码的形式具体的分析了其中知识点,想必大家对于数组指针应该可以清楚的理解它,数组和指针的传参也知道什么可以传参,什么可以接收参数。接下来我们还会继续对进阶指针剩下的内容完善的,敬请期待!

 

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

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

相关文章

浅谈智能微电网供电系统的谐波治理

摘要&#xff1a;智能微电网供电系统的特性容易引发谐波&#xff0c;而谐波导致电力损耗加大&#xff0c;降低供电质量。本文从谐波的产 生原因和危害做出详细阐述&#xff0c;并结合智能微电网提出了治 理谐波的方法和措施。 关键词&#xff1a;智能微电网&#xff1b;谐波危害…

手术麻醉信息管理系统源码:全面监护,支持多设备采集

手术、麻醉是医院非常重要的一个组成部分&#xff0c;外科医生为病人进行手术的好与坏直接会危及到病人的生命&#xff0c;所以病人在手术麻醉过程中每一个环节都是非常重要的。随着现在高科技的发展&#xff0c;大量的医疗监视辅助仪器设备在手术过程中也得到广泛的应用&#…

Jenkins使用Docker(Podman)安装部署web应用

https://blog.csdn.net/onePageKownAll/article/details/128182290 https://blog.csdn.net/weixin_45647685/article/details/127825728 https://zhuanlan.zhihu.com/p/562495608 最终效果&#xff1a;在jenkins对某个项目进行构建&#xff0c;jenkins先通过git拉取最项目的…

MySQL基本知识复习补充

MySQL基本知识复习补充 SQL分类 DDL&#xff1a;数据定义语言。create、alter、drop、rename、truncate(清空表) DML&#xff1a;数据操作语言。insert、delete、update、select DCL&#xff1a;数据控制语言。commit、rollback、savepoint、grant、revoke 因为查询语句使…

最后机会!桥接 LAND 可以获得返还奖励!

经过 1 年的服务&#xff0c;The Sandbox 向我们的社区成员分发了超过 40 万 SAND&#xff0c;LAND 桥接返还奖励计划即将结束。 该计划是为了减轻土地持有者从以太坊桥接到 Polygon 的成本。每块土地的桥接都可获得 10 SAND 的奖励。 最后机会&#xff01;再次呼吁各位桥接 LA…

从小白到大神之路之学习运维第36天---第三阶段---mysql数据库之企业级mysql部署方案

第三阶段基础 时 间&#xff1a;2023年6月8日 参加人&#xff1a;全班人员 内 容&#xff1a; 企业级mysql部署方案 目录 企业级MySQL部署方案 企业级mysql部署主要步骤 Linux系统初始化设置&#xff08;做公司服务器&#xff09; 企业级MySQL高可用集群部署方案 企业…

Keysight是德MSOS604A高清晰度示波器1 GH

Keysight是德MSOS604A S系列示波器配备 6 GHz 存储器、15 英寸 XGA 电容触摸屏和 10 位模数转换器。主要特性与技术指标 1 GHz带宽和平坦的频率响应确保高信号保真度 20 GSa/s 最大采样率 10 位模数转换器&#xff08;ADC&#xff09;保证高垂直分辨率 低噪声前端&#xff…

【React】setState原理,SCU,不可变对象,Ref,受控组件,高阶组件

❤️ Author&#xff1a; 老九 ☕️ 个人博客&#xff1a;老九的CSDN博客 &#x1f64f; 个人名言&#xff1a;不可控之事 乐观面对 &#x1f60d; 系列专栏&#xff1a; 文章目录 setState原理setState异步更新 SCU不可变对象RefRef获取DOMRef获取组件 受控组件高阶组件(HOC)作…

告别 Spread 运算符:使用默认 Composer

在 JavaScript 中处理对象时&#xff0c;通常需要为空的strings// objects、或属性设置默认值。在处理嵌套对象时&#xff0c;这会变得更加复杂并且需要复杂的编程逻辑。然而&#xff0c;有了“ default-composer ”库&#xff0c;这项任务变得简单易行。arraysnullundefined …

零瑕疵全核心,这份RocketMQ笔记仅用330页直接封神

RocketMQ天生为金融互联网领域而生&#xff0c;追求高可靠、高可用、高并发、低延迟 RocketMQ在阿里集团也被广泛应用在订单&#xff0c;交易&#xff0c;充值&#xff0c;流计算&#xff0c;消息推送&#xff0c;日志流式处理&#xff0c;binglog分发等场景 其主要功能有&am…

怎样快速选择正确的可视化图表?

数据可视化的图表类型十分丰富&#xff0c;好的图表可以有效、清晰地呈现数据的信息。对于用户而言&#xff0c;选择正确的图表是十分关键的&#xff0c;不仅可以达到“一图胜千言”的效果&#xff0c;而且会直接影响分析的结果。 用户选择正确的数据可视化图表前&#xff0c;…

银河麒麟服务器ZYJ操作系统,文件储存inode节点占用根目录/空间满了解决办法

【问题描述】 今天发现业务系统运转异常&#xff0c;df -h 检查服务器发现磁盘根目录空间未满&#xff0c;df -i 检查发现根目录文件满了。inode节点中&#xff0c;记录了文件的类型、大小、权限、所有者、文件连接的数目、创建时间与更新时间等重要的信息&#xff0c;还有一个…

蓝奥声核心技术分享——无线同步数据传输技术

1、技术背景 无线同步数据传输技术指基于对目标场景状态变化的协同感知而获得触发响应并进行智能决策&#xff0c;属于蓝奥声核心技术--边缘协同感知(EICS&#xff09;技术的关键支撑性技术之一。该项技术主要涉及网络服务节点与目标对象设备之间的无线通信方式及服务机制与流…

flask做图书管理系统

一.Flask框架是一个轻量级的Web应用程序框架&#xff0c;它提供了一种简单的方法来创建Web应用程序。在本文中&#xff0c;我们将使用Flask框架来开发一个图书管理系统。在使用 Flask 开发时&#xff0c;建议使用虚拟环境来隔离不同项目的依赖关系&#xff0c;避免冲突。 摘要 …

阿里元境郭旷野:多端时代,云渲染在为元宇宙开发降本

当“AI进入iPhone时代”时&#xff0c;创造iPhone的苹果带着Vision Pro来了。在元宇宙初创企业今年上半年融资&#xff08;6.64亿美元&#xff09;较去年同期&#xff08;29.3亿美元&#xff09;大幅下降的背景下&#xff0c;苹果硬件新产品的问世被视作元宇宙赛道的“提气”之…

【MySQL】JDBC编程 (Java的数据库编程:JDBC 导入驱动包 MySQL Connector Java 编写JDBC代码 插入操作 查询操作)

文章目录 Java的数据库编程&#xff1a;JDBC导入驱动包MySQL Connector Java 编写JDBC代码插入操作查询操作 Java的数据库编程&#xff1a;JDBC 真正在工作中操作数据库,99.9%都是通过代码来操作,很少会手动在客户端里输入sql语句.各种数据库,MySQL,Oracle,SQL Server 在开发的…

必须了解的不同地区的支付方式FP独立站安全收款方式

跨境收款是跨境电商自建站系统最重要的功能之一&#xff0c;其收款方式一直是众多独立站卖家特别是做fp独立站的最为关注的问题之一&#xff0c;加上chatgpt出现&#xff0c;对fp独立站的检测审核更加严格&#xff0c;那么&#xff0c;你知道要怎么做才能安全收款吗&#xff1f…

深度估计阅读记录

VolSDF(neurips 2021) 题目&#xff1a;Volume Rendering of Neural Implicit Surfaces 链接&#xff1a;https://arxiv.org/pdf/2106.12052.pdf 目标&#xff1a;使用SDF这种表示方式替换NeRF中的MLP&#xff0c;使得在几何形状上获得更准确的结果。我们通过将体密度建模为几…

Python实现Fleiss Kappa一致性分析,并计算Z值和p值等相关统计量

参考资料 Fleiss Kappa的定义 Fleiss Kappa的原论文因为要付费才能阅读&#xff0c;我这里就不放链接了 Fleiss kappa - Wikipediahttps://en.wikipedia.org/wiki/Fleiss%27_kappa Fleiss Kappa相关统计量 Z值&#xff0c;p值&#xff0c;95%置信区间 属性一致性分析 的 …

如何使用切片辅助超推理 SAHI 技术对 YOLOv8 进行推理过程和代码实现

前面章节已经详细描述了 切片辅助超推理(SAHI )技术原理介绍 引入SAHI,这是一种专为小物体检测而设计的尖端流水线。SAHI 利用切片辅助推理和微调技术的力量,彻底改变了检测对象的方式。SAHI 物体检测的与众不同之处在于它与任何物体检测器的无缝集成,无需进行繁琐的微调…