那些 C语言指针 你不知道的小秘密 (3)

本篇会加入个人的所谓‘鱼式疯言’
❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言
而是理解过并总结出来通俗易懂的大白话,
我会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.
🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!
在这里插入图片描述

前言

在上一篇文章中小编主要讲解了

  • 野指针:小编总结了野指针出现的情况并说明其应对 对策

  • assert 断言:小编带着大家试着怎么用 assert 并体会了 assert 防止野指针的益处

  • 传值调用与传址调用: 理解了 传值传址 调用的不同,并说明分别用于哪些 使用场景 更好

  • 二级指针:二级指针的理解,同时并知晓如何 定义解引用

在本篇文章中将继续 和友友们一起探访 指针 的小秘密, 这次咱们只要围绕着 指针数组 的关系展开更进一步的理解

那么友友们让我们开始这次美好的指针之旅吧 💕 💕 💕

目录

  1. 数组名的含义
  2. 数组名的实际运用
  3. 一维数组传参的本质
  4. 指针数组
  5. 指针数组的实际运用

一. 数组名的含义

<1>. 数组名的简介

小爱同学就有疑问了 🤔 🤔 🤔,数组名不就是个名字么,不是相当于 变量名 一样的么,怎么还有含义呢 ? ? ?
是的,是有含义的 ❤️ ❤️ ❤️

数组名啊 !一般而言,本质上的含义就是 首元素的地址
但也有 特殊情况 的出现,下面宝子们就和小编一起去发现吧

我们可以先来做个测试

<2>. 举个栗子

#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 中单独放数组名,这里的数组名表示 整个数组 ,计算的是 整个数组 的大小, 单位是 字节

& 数组名,这里的数组名表示整个数组,取出的是 整个数组 的地址 (整个数组的地址数组首元素的地址 是有区别的) 除此之外,任何地方使用数组名,数组名都表示首元素的地址。

鱼式疯言

&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 };
	
	//取地址首元素并 +1
	printf("&arr[0] = %p\n", &arr[0]);
	printf("&arr[0]+1 = %p\n", &arr[0] + 1);
	
	//数组名并 +1
	printf("arr = %p\n", arr);
	printf("arr+1 = %p\n", arr + 1);
	
	//取地址数组名并 +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 就是跳过 4个字节(一个元素)。

但是 &arr&arr+1 相差 40(十六进制的地址就相差28) 个字节

这就是因为 &arr是数组的地址,+1 操作是跳过整个数组的。

到这里大家应该搞清楚 数组名 的意义了吧。
数组名是 数组首元素 的地址,但是有 2种 特殊情况

二. 数组名的实际运用

当我们需要输入输出数组时 , 我猜小爱同学可能会这样写

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	//输入

	int i = 0;
	
	int sz = sizeof(arr) / sizeof(arr[0]);
	//输入

	for (i = 0; i < sz; i++)
	{

		scanf("%d", &arr[i]);

	}

	//输出
	for (i = 0; i < sz; i++)
	{

		printf("%d ",arr[i]);

	}
	return 0;
}

在这里插入图片描述
当我们好学的小爱同学,看看小编这样写是不是也可以呢 💕 💕 💕

#include <stdio.h>
int main()
{
	int arr[10] = { 0 };
	//输入

	int i = 0;
	
	int sz = sizeof(arr) / sizeof(arr[0]);
	//输入

	for (i = 0; i < sz; i++)
	{
		//利用数组名是首元素地址
		//数组名在 + i 地址进行右移
		scanf("%d", arr + i);
		//scanf("%d", &arr[i]);
		//也可以这样写
	}

	//输出
	for (i = 0; i < sz; i++)
	{
		//得到每个元素的地址
		//解引用打印数据
		printf("%d ", *(arr + i));
		
		//printf("%d ",arr[i]);
		//也可以这样写
	}
	return 0;
}

在这里插入图片描述
是的,友友们这下就明白原来我们数组的输入输出还能这样玩啊 😎 😎 😎
输入时

  1. 对该下标的元素进行 &
  1. 利用数组名是 首元素 的地址,进行 指针加减偏移 来操作

输出时:

  1. 除了我们想数组的下标访问
  1. 利用数组名是 首元素的地址 ,再 指针加减偏移 ,我们也可以通过得到我们 *每一个元素的的地址 *,来 * 解引用访问

鱼式疯言

*(arr+i) <==> &arr[i]

arr+i <==> &arr[i]

三. 一维数组传参的本质

数组我们学过了,之前也讲了,数组是可以传递给函数的,这个小节我们讨论一下一维数组传参的本质。
首先小伙伴可以思考一个问题 ? ? ?
我们之前都是在 函数外部 计算数组的元素个数
那我们可以把函数传给一个函数后, 函数内部 求数组的元素个数吗?
不妨让我们试一下吧 😃 😃 😃

<1>. 函数外部求数组长度

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	
	//在 test 函数外部求数组长度
	int sz1 = sizeof(arr) / sizeof(arr[0]);
	
	// 验证其大小
	printf("数组长度为 : %d\n", sz1);
	
	//test(arr);
	
	return 0;
}

在这里插入图片描述
在函数外部是完全正确的,没有问题 。

<2>. 函数内部

void test(int arr[10])
{
	int sz1 = sizeof(arr) / sizeof(arr[0]);
	printf("数组长度为 : %d\n", sz1);
}

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

在这里插入图片描述
我们发现在函数内部是没有正确获得数组的元素个数。
小爱同学就深思了,这到底是什么原因呢 ? ? ?
竟然我们今天要学习 数组传参的本质 ,那这个 内在的原因 肯定 和 数组传参 脱不了干系

友友们可以思考下
我们上一节提过数组名本质上是啥,是首元素的地址吧
那么有没有一种可能数组名在传参的时候根本没有把整个数组传过去,而是传了 首元素的地址
居然我们提出了猜想,不妨我们用代码来验证下吧

#include<stdio.h>

// 参数写成数组形式,本质上还是指针
void test(int arr[])
{
	//验证一下
	//在 X86 的环境下 
	//一个指针大小是4个字节
	printf("%d\n", sizeof(arr));
}


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

	test(arr);
	return 0;
}

在这里插入图片描述
猜想验证成功,宝子们真聪明 💖 💖 💖

实践证明,我们本质上数组传参本质上传递的是数组首元素的地址

如果是这样子的话,那么我们的代码以后是否可以这样写呢 ! ! !

#include<stdio.h>
// 参数写成指针形式
void test1(int* arr)
{
	printf("%d\n", sizeof(arr));
	//计算一个指针变量的大小

	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(arr + i));
	}

}


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

	test1(arr);
	return 0;
}

在这里插入图片描述
小伙伴快看这样写是不是也是种思路呢! ! !

但是,我们知道了本质,

这不禁也知道sizeof(arr) 计算的是一个地址的大小(单位字节)而不是数组的大小(单位字节)。

正是因为函数的参数部分是本质是 指针,所以在函数内部是没办法求的 数组元素个数

那我们该怎么解决呢,如果是这样的 😣 😣 😣

<3>. 传参方案

唯一的解决办法就是把对应的数组长度现在函数外部求好,利用 参数 传过去。

#include<stdio.h>

// 参数写成指针形式
// sz 来接收数组长度
void test1(int* arr,int sz)
{
	//利用最大长度来输出打印我们的数组元素
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", *(arr + i));
	}

}


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

	// 函数外部求数组长度
	int slz = sizeof(arr) / sizeof(arr[0]);
	
	// 传入 slz 长度
	test1(arr, slz);
	
	return 0;
}

在这里插入图片描述

鱼式疯言

一维数组传参还是 首元素地址 ,数组长度先算好,额外加一份 参数再传

四. 指针数组

<1>. 指针数组的简介

首先我们来思考一个问题

指针数组是指针还是数组?

友友们可以类比一下

整型数组 ,是存放 整型 的数组

字符数组 是存放 字符 的数组

指针数组 呢?是存放 指针 的数组。

C语言中,指针数组是指一个数组,它的每个元素都是一个指针变量。每个指针变量可以指向不同的数据类型或对象
指针数组可以声明为以下形式:

dataType *arrayName[size];

dataType 表示指针变量所指向的 数据类型

arrayName 是数组的 名称

size 是数组的 大小

在这里插入图片描述
小爱同学是不是还是有点困惑呢 😣 😣 😣
没关系 没关系
不妨我们画个图理解一下吧 ! ! !
在这里插入图片描述

  • 指针数组的每个元素都是用来存放 地址(指针) 的。
    如下图 :
    在这里插入图片描述

指针数组的每个 元素地址 ,又可以 指向 一块区域。

鱼式疯言

很多个 相同类型指针 哪里放,指针数组 管饭吃

五. 指针数组的实际运用

想必大家都学过二维数组吧,如果让宝子们写个二维数组,你可能会这样写 ! ! !

<1>. 二维数组

 #include<stdio.h>

int main()
{
	//二维数组初始化
	int a[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };
	
	int i = 0,j=0;

	//外循环为行数
	for ( i = 0; i < 3; i++)
	{
		//内循环为列数
		for ( j = 0; j < 4; j++)
		{
			printf("%d ", a[i][j]);
		}
		printf("\n");
	}

	return 0;
}

在这里插入图片描述
但今天小编的主要想法还是带着小伙伴一起用指针数组 来模拟咱们的 二维数组
小伙伴都眼睛睁大咯,可不要眨眼哦 😁 😁 😁

<2>. 模拟二维数组

宝子们请先看代码哦


//指针数组模拟二维数组
#include<stdio.h>

int main()
{
	int a1[5] = {1,2,3,4,5};
	int a2[5] = {2,3,4,5,6};
	int a3[5] = {3,4,6,7,8};
	
	//将每个一维数组的首地址放入指针数组中
	int* a[3] = { {a1},{a2},{a3} };
	
	int i = 0, j = 0;
	
	//先找到第几个 一维数组
	for (i = 0; i < 3; i++)
	{
		//再找到该 一维数组中的每一个元素
		for ( j = 0; j < 5; j++)
		{
		
			printf("%d ", a[i][j]);
		}
		printf("\n");
	}

	return 0;
}

在这里插入图片描述
友友们是不是也都看到了

我们的把每个一维数组的地址都放在指针数组中,通过指针数组的下标 i 我们可以访问 哪个一维数组

再通过该一维数组的下标 j 来访问具体元素,从而达到 二维数组 的效果 。

鱼式疯言

人狠话不多
看图说话
在这里插入图片描述

先走指针,后走一维数组

总结

  • 数组名的含义 :知晓了数组名的一般含义,以及他的两种特殊情况
  • 数组名的实际运用 : 我们通过指针的形式更进一步利用数组名自身含义的特点来输入输出
  • 一维数组传参的本质 : 传参的本质还是数组名的自身含义,以及数组长度如何解决的办法
  • 指针数组 : 我们更了解了指针数组的基本概念
  • 指针数组的实际运用 : 通过我们了解的指针数组的基本概念来对实践我们的理解

如果觉得小编写的还不错的咱可支持三连下 (定有回访哦) , 不妥当的咱请评论区指正

希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大动力 💖 💖 💖

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vscode连接ssh报错

关于vscode更新版本至1.86后&#xff0c;导致无法连接服务器问题的记录 原因&#xff1a;vscode1.86更新了对glibc的要求&#xff0c;需要最低2.28版本&#xff0c;导致各种旧版本的linux发行版&#xff08;比如最常见的centos 7&#xff09;都无法用remote-ssh来连接了&#…

Linux探秘之旅:透彻理解路径、命令与系统概念

目录 如何远程连接 远程登录简明指南 linux区别 1.严格区分大小写 2.linux的命令返回结果判断 3.如何查看网络信息 4.关于后缀名&#xff08;Linux不关心文件后缀&#xff09; 4.1 需要记忆的后缀 5.echo命令 6.linux一切皆文件 6.1比如磁盘的文件 6.2可执行文件 …

nginx + DNS域名解析

配置链接: Nginx 安装配置 | 菜鸟教程 安装完nginx后&#xff0c;访问&#xff1a; cd /usr/local/nginx/sbin/ 然后使用./nginx可使用nginx。 访问:http://服务器的ip地址后出现 因为访问IP地址很繁琐&#xff0c;需要记忆ip的数字地址&#xff0c;因此需要给它一个通俗的…

如何在Sprint中管理UI测试?

作为iOS团队&#xff0c;我们编写3种类型的UI测试。如果你问这些是什么&#xff1b;快照、冒烟和回归测试。那么这些测试到底是什么&#xff1f;让我们稍微谈谈这些。 快照测试快照测试是检查UI中的某些内容是否损坏的测试。 首先&#xff0c;它将所需的视图图像保存在某处&am…

Lombok 高级说明

优质博文&#xff1a;IT-BLOG-CN 一、痛点 【1】代码臃肿&#xff1a;POJO中的getter/setter/equals/hashcode/toString等&#xff1b; 【2】样板式代码&#xff1a;I/O流的关闭操作等&#xff1b; Lombok是一个可以通过注解简化Java代码开发的工具&#xff0c;能够在我们编…

string容器

1. string基本概念 1.1 本质&#xff1a; string是C风格的字符串&#xff0c;而string本质上是一个类 string和char * 区别&#xff1a; char * 是一个指针 string是一个类&#xff0c;类内部封装了char*&#xff0c;管理这个字符串&#xff0c;是一个char*型的容器。 1.2 特点…

书生·浦语大模型全链路开源体系

参考&#xff1a;https://www.bilibili.com/video/BV1Rc411b7ns/?spm_id_from333.788&vd_source3bbd0d74033e31cbca9ee35e111ed3d1 背景&#xff1a; 人工智能的发展从针对特定任务&#xff0c;用一个模型解决一个问题过渡到一个模型来应对多模态、多任务&#xff0c;大模…

K210如何下载程序

一、打开资料包里提供的K-Flash程序烧录软件 二、选择串口 三、选择波特率 四、选择In-Chip&#xff0c;烧录到Flash芯片里面&#xff0c;重新上电还会运行程序 五、如果选择In - Memory&#xff0c;这次可以运行&#xff0c;但下次重新上电就不会保持这次的程序了。 六、选择固…

springboot+vue居民小区设备报修系统

小区报修系统可以提高设施维护的效率&#xff0c;减少机构的人力物力成本&#xff0c;并使得维修人员可以更好地了解维护设备的情况&#xff0c;及时解决问题。 对于用户来说&#xff0c;报修系统也方便用户的维修请求和沟通&#xff0c;提高了用户的满意度和信任。其次小区报修…

在PyTorch中,如何查看深度学习模型的每一层结构?

这里写目录标题 1. 使用print(model)2. 使用torchsummary库3.其余方法&#xff08;可以参考&#xff09; 在PyTorch中&#xff0c;如果想查看深度学习模型的每一层结构&#xff0c;可以使用print(model)或者model.summary()&#xff08;如果你使用的是torchsummary库&#xff0…

网关中全局过滤器实现jwt校验

意味着有很多相同接口的实现类&#xff0c;那么必定会有优先级的问题。于是Spring就提供了Ordered这个接口&#xff0c;来处理相同接口实现类的优先级问题。 public class AuthorizeFilter implements Ordered, GlobalFilter {Overridepublic Mono<Void> filter(ServerW…

网络游戏租用价格表,一年、1个月收费明细表

游戏服务器租用多少钱一年&#xff1f;1个月游戏服务器费用多少&#xff1f;阿里云游戏服务器26元1个月、腾讯云游戏服务器32元&#xff0c;游戏服务器配置从4核16G、4核32G、8核32G、16核64G等配置可选&#xff0c;可以选择轻量应用服务器和云服务器&#xff0c;阿腾云atengyu…

springboot170图书电子商务网站的设计与实现

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

Android Studio无法安装Git问题解决(折中方案)

安装配置好studio&#xff0c;往往会使用git克隆github上面的项目&#xff0c;但是却发现git无法正确安装&#xff0c;本文将介绍如何解决git无法安装这一问题。 对于git安装&#xff0c;实际比较复杂&#xff0c;可以参考这一篇博客。 Git 详细安装教程&#xff08;详解 Gi…

jvm问题自查思路

本文聊一下最近处理了一些jvm的问题上&#xff0c;将这个排查和学习过程分享一下&#xff0c;看了很多资料&#xff0c;最终都会落地到几个工具的使用&#xff0c;本文主要是从文档学习、工具学习和第三方技术验证来打开认知和实践&#xff0c;希望有用。 一、文档 不仅知道了…

以用户为中心,酷开科技荣获“消费者服务之星”

在企业顺应消费升级的道路中&#xff0c;企业自身不仅要着力强化对于消费者服务意识的提升&#xff0c;并且要树立诚信自律的行业示范带头作用&#xff0c;助力消费环境稳中向好&#xff0c;不断满足人民群众对美好生活的期待。企业的发展需要消费者的认可&#xff0c;酷开科技…

Window环境下使用go编译grpc最新教程

网上的grpc教程都或多或少有些老或者有些问题&#xff0c;导致最后执行生成文件时会报很多错。这里给出个人实践出可执行的编译命令与碰到的报错与解决方法。&#xff08;ps:本文代码按照煎鱼的教程编写&#xff1a;4.2 gRPC Client and Server - 跟煎鱼学 Go (gitbook.io)&…

【Java八股面试系列】JVM-常见参数设置

目录 堆内存相关 显式指定堆内存–Xms和-Xmx 显式新生代内存(Young Generation) 显式指定永久代/元空间的大小 垃圾收集相关 垃圾回收器 GC 日志记录 处理 OOM JDK监控和故障处理工具总结 堆内存相关 Java 虚拟机所管理的内存中最大的一块&#xff0c;Java 堆是所有线…

Python 数据可视化之山脊线图 Ridgeline Plots

文章目录 一、前言二、主要内容三、总结 &#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、前言 JoyPy 是一个基于 matplotlib pandas 的单功能 Python 包&#xff0c;它的唯一目的是绘制山脊线图 Joyplots&#xff08;也称为 Ridgeline Plots&…

【JavaScript 漫游】【012】ES5 规范中 String 对象方法汇总

文章简介 本文为【JavaScript 漫游】专栏的第 012 篇文章&#xff0c;记录的内容包含了 ES5 规范中String 对象的所有方法。 笔者认为要掌握的方法包括&#xff1a; String.prototype.concat()String.prototype.slice()String.prototype.substring()String.prototype.substr…