【C语言】指针进化 !!!

news2024/11/15 10:51:16

前言
🎈大家好,我是何小侠🎈
🍃大家可以叫我小何或者小侠🍃
💐希望能通过写博客加深自己对于学习内容的理解💐
🌸也能帮助更多人理解和学习🌸

兰生幽谷,不为莫服而不芳。舟在江海,不为莫乘而不浮。君子行义,不为莫知而止休。— 出自《淮南子·说山训》

解释:兰花生长在无人的山谷,不会因为没人佩戴而不散发芳香;船在江河湖海上,不会因为没有人乘坐而不浮在水上;君子行使自己的道义,不因没有人理解而停止。

在这里插入图片描述


    这篇博客我们将会深入的理解指针和学习指针的用法。
    在这里插入图片描述

    目录

    • 字符指针⁉️
    • 指针数组🐽
    • 数组指针🦑
      • &数组名与数组名的区别
    • 数组指针的用法
    • 总结🍊

    字符指针⁉️

    1. 字符指针最基本的用法如下。
    int main()
    {
    	char ch = 'w';
    	char* p = &ch;
    	*p = 'a';
    
    	return 0;
    }
    

    这确实是一个本基本的代码我们都会使用。
    我们看看在内存中是怎么变化的。
    在这里插入图片描述

    首先将’ w ‘的对应的ASCII值存在ch中,然后用 p这个指针变量存放ch的地址,通过给解引用p赋值,成功改变ch中的字符由’ w ‘变成’ a ’
    在这里插入图片描述
    当然这都是16进制的表示方法,自己算一算便可知道。

    1. 字符指针的第二种用法。
    int main()
    {
    	char* p = "abcdefg";
    	printf(p);
    	printf("\n%c", *p);
    	return 0;
    }
    

    我们看第一行代码时要注意,这里是将一个常量字符串"abcdefg"的首地址放在了p中,我们通过这个首地址找到这个常量字符串。并不是把这个字符串放在p里面。
    那么打印的结果就应该是 :
    abcdefg
    a
    在这里插入图片描述
    没错确实是这样。
    那我们是否能够改变*p的内容呢?

    int main()
    {
    	char* p = "abcdefg";
    	printf(p);
    	printf("\n%c", *p);
    	*p = 'w';
    	printf("\n%c", *p);
    
    	return 0;
    }
    

    其实 * p = ‘w’;这种写法是不对的,为什么呢?因为我们的"abcdefg"是一个常量字符串常量字符串是不能够修改的!!

    指针数组🐽

    我们都知道,整型数组是存放整型的数组,字符数组是存放字符的数组
    那么指针数组就比较明显,肯定是存放指针的数组。

    1. 那么它的一般形式是什么呢?
    int main()
    {
    	char* pc = "abcde";
    	char* p1 = pc;
    	char* p2 = pc+1;
    	char* p3 = pc + 2;
    	char* p4 = pc + 3;
    	char* p5 = pc + 4;
    	char* p[5] = { p1,p2,p3,p4,p5 };
    	for (int i = 0; i < 5; i++)
    	{
    		printf("%c\n", *p[i]);//[]先结合,因为优先级最高。
    	}
    	return 0;
    }
    

    我们为了与上面的字符指针对应,例子举的相似一点。
    我们知道p1 ~ p5 存储的就是对应的abcde的地址,而类型决定应该放什么元素,而这里指针数组是字符指针数组,所以类型就是char *.
    我们想一下,在我们传参的时候,arr数组名就是用char * 来接受的,为什么呢?就是因为实参就是地址,char * 类型也就是需要地址来作为数组元素,那么这里的初始化就应该很好理解了。

    在这里插入图片描述

    1. 但是我们一般会这样来使用它
    int main()
    {
    	int arr1[] = { 1,2,3,4,5 };
    	int arr2[] = { 2,3,4,5,6 };
    	int arr3[] = { 3,4,5,6,7 };
    
    	int* p[3] = { arr1,arr2,arr3 };
    	int i = 0;
    	int j = 0;
    	for (i = 0; i < 3; i++)
    	{
    		for (j = 0; j < 5; j++)
    		{
    			printf("%d", *(*(p + i) + j));
    		}
    		printf("\n");
    	}
    	return 0;
    }
    

    在这里插入图片描述

    我们这里要讲的是最后的输出部分

    	printf("%d", *(*(p + i) + j));
    
    

    这里为什么要这样写呢?还有没有其他写法?
    我们知道arr[3] = *(arr +3); 为什么呢? arr[3]其实是下标为3的元素,那么
    arr+3就是下标为3的元素的地址,我解引用不就是这个元素吗?
    这里也差不多。
    在这里插入图片描述
    我们可以这样理解,先看成是一个一维数组,那么*(p+i)不就是拿到arr1,或者arr2,arr3的地址吗?加入我们拿到arr1的地址。
    在这里插入图片描述
    那么*(p )就是arr1这个数组的首地址, * (arr1+j)也就很明显了。
    那么我们换一种写法呢?
    这样写:*( p[ i ]+j )
    在这里插入图片描述

    这样写:p[ i ][ j ]
    在这里插入图片描述
    为什么可以当作二维数组看呢?因为二维数组其实也可以理解为多个一维数组的拼接。但是我觉得还是我上面描述的要更清晰一些。

    这样写: (*(p + i))[ j]
    在这里插入图片描述

    数组指针🦑

    我们上面讲的是指针数组,是数组。因为最后是数组这个名词,而数组指针是指针,是指向数组的指针。

    1. 区分指针数组和数组指针
    int *p1[10];
    int (*p2)[10];
    //p1, p2分别是什么?
    

    p1是指针数组,为什么呢?我们讲过,p1先与[ ]结合确认是一个数组,再与结合说明是指针数组。
    而p2就是我们要讲到的数组指针,用()让
    p2 优先结合说明是一个指针,然后确认指针类型,是int [ 10 ],也就是数组指针

    &数组名与数组名的区别

    这真的是一个非常重要的知识点。
    我们先来看一段代码

    int main()
    {
    	int arr[] = { 1,2,3,4,5,6 };
    	printf("%p\n", arr);
    	printf("%p\n", arr+1);
    	printf("%p\n", &arr);
    	printf("%p\n", &arr+1);
    
    	return 0;
    }
    

    在这里插入图片描述
    我们用计算机一算便知。
    在这里插入图片描述
    这里为什么是这样呢?

    • 实际上&arr,取出的是整个数组的地址,整个数组的地址+1也就应该跳过一个数组。
    • arr是首元素地址,+1当然只会跳过一个元素。
      大家觉得这和我们的指针是不是有点类似呢?
      我们知道 arr传参我们可以用 int * arr这个指指来接受,这个我们已经是老生常谈了,上面也解释过了。
      那么&arr用什么来接收?
      当然用数组指针
      整型指针变量存储的是一个整型元素的地址!
      那么数组指针变量应该存储的是数组的首元素地址,由于类型是数组指针,+1当然就会跳过一个数组的大小。

    那么我们就可以得出结论,&arr的数组名就是 int (*p)[ ]。

    数组指针的用法

    int main()
    {
        int arr[10] = {1,2,3,4,5,6,7,8,9,0};
        int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量p
        //但是我们一般很少这样写代码
        return 0;
    }
    

    我们一般这么写。

    void print(int(*p)[5],int i ,int j )
    {
    	for (i = 0; i < 3; i++)
    	{
    		for (j = 0; j < 5; j++)
    		{
    			printf("%d ",(*(p+i))[j]);//不要写成 *p+i,
    			//因为*比加号的优先级要高
    			//printf("%d ", *(*(p + i) + j));
    	  }
    		printf("\n");
    	}
    
    
    }
    
    int main()
    {
    	int arr[][5] = { {1 ,3 ,4} ,{2,3,4,5,6}, {1,2,3,4} };
    	print(arr,3,5);
    	return 0;
    }
    

    可能有点跳跃不过没有关系,为什么二维数组传首地址能够用数组指针接收呢?
    我们知道二维数组的数组名代表第一行的地址,第一行就相当于是一个一维数组,所以说可以。

    学了指针数组和数组指针我们来一起回顾并看看下面代码的意思 :

    int arr[5];
    int *parr1[10];
    int (*parr2)[10];
    int (*parr3[10])[5];
    
    1. 是一个普通的整型数组,5个元素,每个元素是int
    2. 是一个指针数组,存放的是整型指针,每个元素是int *
    3. 是一个数组指针,指向的是整型数组,数组每个元素是int
    4. 是一个指针数组,指针的类型是数组指针,也就是说是一个存放指向数组的指针的数组在这里插入图片描述

    总结🍊

    这篇博客值得我们学习了指针进化的第一部分,后续还有几部分我也会陆续发出来,请大家期待。

    最后如果这篇博客有帮助到你,欢迎点赞关注加收藏

    在这里插入图片描述在这里插入图片描述
    如果本文有任何错误或者有疑点欢迎在评论区评论
    在这里插入图片描述

    在这里插入图片描述

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

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

    相关文章

    Redis 五种基本数据结构及基本使用

    一、数据结构 二、使用 2.1 String 的使用 Redis String 一个键对应一个值&#xff0c;并且是二进制安全的&#xff0c;值可以是图片或者序列化后的对象。 一个键最大能存储 512 MB。 2.1.1 set 命令的使用 set key value127.0.0.1:6379> set name yunhu OK 127.0.0.1:…

    【Docker】docker基础使用

    文章目录 docker概念什么是dockerdocker引擎迭代docker与虚拟机docker版本发展 docker基础docker架构docker Registry(镜像仓库)镜像仓库使用流程实际研发镜像仓库使用不同镜像仓库的拉取 docker常用命令镜像仓库命令docker logindocker pulldocker pushdocker searchdocker lo…

    Github的加速访问(解决github进不去)

    1.下载Steam Steam 现更名为 Watt Toolkit 并在 Microsoft Store 中已可用 2.打开Steam 3.勾选github 一键加速

    java试题1

    1、哪些问题是HTTPS无法解决的&#xff1f; Http是基于TCP协议的&#xff0c;在网络层的传输耗时比较长&#xff0c;https没有解决这个问题&#xff1b;http头是不能压缩的&#xff0c;每次要传递很大的数据包&#xff0c;每个连接也只能支持一个请求。同时https应用了很多加密…

    Docker - 基本概念、与虚拟机的区别、架构、镜像操作、容器操作、数据卷挂载

    目录 一、对 Docker 的理解 1、Docker 基本概念 2、Docker 与 虚拟机的区别 3、何为镜像和容器&#xff1f; 4、Docker 主要架构 二、Docker 基本操作 1、Docker 镜像操作 2、案例&#xff08;镜像&#xff09;&#xff1a;去 DockerHub 搜索并拉取一个 Nginx 镜像&am…

    第一百天学习记录:线性代数:行列式(宋浩板书)

    n阶行列式 注&#xff1a;二阶行列式和三阶行列式以及排列和逆序数见高等数学自学向量篇中间穿插的线性代数知识点补充。 行列式的性质 性质7&#xff08;☆☆☆&#xff09; 行列式按行展开 拉普拉斯 行列式相乘 行列式的计算 Cramer法则 题外话&#…

    【unity实战】制作类元气骑士、挺进地牢——俯视角射击游戏多种射击效果(一)(附源码)

    文章目录 本期目标前言欣赏开始1. 角色移动和场景搭建2. 绑定枪械2.1 首先将各种枪械的素材添加给人物作为子物体2.2 给枪械也分别添加两个子物体用作标记枪口和弹仓位置 3. 枪械动画4. 切换枪械5. 发射功能5.1 手枪(1) 枪械随着鼠标旋转(2) 射击时间间隔(3) 创建好子弹、弹壳和…

    xilinx zc706 10/100/100M以太网完整性测试说明

    一&#xff1a;概述 最近接触FPGA比较多&#xff0c;本次是一款zc706芯片的FPGA&#xff0c;开发版是长这样的&#xff0c;基本上开发也是安装开发版的模块组合进行开发。 开发版上以太网芯片使用的是Marvell 881116R。 本次只是验证下控制以太网进行模式测试的说明&#xf…

    子集 (力扣)数学推理 JAVA

    给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[],[1],[2],[1,2],[3],[…

    Windows10上Docker和Kubernetes的安装

    官网&#xff1a;https://www.docker.com/products/docker-desktop/ 历史版本&#xff1a;https://download.docker.com/linux/static/stable/ 1、去Docker官网下载Docker Desktop&#xff0c;并一键安装 2、安装k8s所需的镜像 下载k8s-for-docker-desktop包 git clone http…

    WAIC2023记录

    汤晓鸥 学生与工作&#xff1a; 微软布局大模型方向

    Vue3+Vite 项目配置 vue-router,并完成路由模块化

    前言 我的技术栈&#xff1a;Vue3 Vite TypeScirpt我的包管理工具&#xff1a;pnpm&#xff08;v8.6.6&#xff09;我的 node.js 版本&#xff1a;v16.14.0 一、安装vue-router pnpm install vue-router二、创建页面 在 /src/views 文件夹下创建 home、login、test文件夹…

    Chat2DB-开源AI智能数据库客户端工具 能够将自然语言转换为SQL

    一、Chat2DB是什么 Chat2DB 是一款有开源免费的多数据库客户端工具&#xff0c;支持windows、mac本地安装&#xff0c;也支持服务器端部署&#xff0c;web网页访问。和传统的数据库客户端软件Navicat、DBeaver 相比Chat2DB集成了AIGC的能力&#xff0c;能够将自然语言转换为SQ…

    论文笔记--SentEval: An Evaluation Toolkit for Universal Sentence Representations

    论文笔记--SentEval: An Evaluation Toolkit for Universal Sentence Representations 1. 文章简介2. 文章概括3 文章重点技术3.1 evaluation pipeline3.2 使用 4. 代码4.1 数据下载4.2 句子嵌入4.3 句子嵌入评估 5. 文章亮点6. 原文传送门7. References 1. 文章简介 标题&…

    windows PE 指南(基础部分)(一)

    windows PE 指南&#xff08;基础部分&#xff09;&#xff08;一&#xff09; 查找软件注册码64位汇编和编译连接PE和COFF文件简介PE和COFF文件布局简介源代码的作用obj的作用PE的作用 COFF格式文件布局概览PE格式文件布局概览COFF格式和PE格式的布局总结 COFF头COFF File Hea…

    linux的磁盘分区管理思路

    1、基本分区管理 1.1、磁盘划分思路 进入分区 新建分区 fdisk 更新分区表&#xff08;刷新&#xff09;partprobe /dev/sda 格式化 &#xff08;文件系统&#xff09; 挂载使用 - -> mount(开机自动挂载||autofs自动挂载) 1.2、使用fdisk分区 n创建新分区&#xff08;…

    一、VMware虚拟机安装以及centos7镜像安装

    目录 一、安装VMware虚拟机 二、centos7安装 (模板机&#xff09; 2.1 虚拟机安装 2.2 虚拟机配置 三、配置服务器 IP 地址 1. VMware中配置 2. window服务器 3. 在虚拟机中&#xff08;centos0&#xff09; 资源包网盘链接&#xff1a;链接&#xff1a;https://pan.bai…

    ActiveMQ消息中间件应用场景

    一、ActiveMQ简介 ActiveMQ是Apache出品&#xff0c;最流行的&#xff0c;能力强劲的开源消息总线。ActiveMQ是一个完全支持JMS1.1和J2EE1.4规范的JMS Provide实现。尽管JMS规范出台已经是很久的事情了&#xff0c;但是JMS在当今的J2EE应用中仍然扮演这特殊的地位。 二、Active…

    速成版-带您一天学完vue2框架

    vue是一个前端js框架&#xff0c;可以简化Dom操作&#xff0c;实现响应式数据驱动。前面全是废话&#xff0c;哈哈&#xff0c;接下来一起学习吧。 目录 一、vue基础 1.1、vue简介 1.2、第一个Vue程序 1.3、vue基础-el挂载点 1.4、data数据对象 二、本地应用-指令篇 2.…

    DESCN:用于个体治疗效果估计的深度全空间交叉网络

    英文题目&#xff1a;DESCN: Deep Entire Space Cross Networks for Individual Treatment Effect Estimation 翻译&#xff1a;用于个体治疗效果估计的深度全空间交叉网络 单位&#xff1a;阿里 论文链接&#xff1a; 代码&#xff1a;https://github.com/kailiang-zhong/…