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

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

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

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

在这里插入图片描述


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

    目录

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

    字符指针⁉️

    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.hqwc.cn/news/14906.html

    如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

    相关文章

    交叉熵、Focal Loss以及其Pytorch实现

    交叉熵、Focal Loss以及其Pytorch实现 本文参考链接&#xff1a;https://towardsdatascience.com/focal-loss-a-better-alternative-for-cross-entropy-1d073d92d075 文章目录 交叉熵、Focal Loss以及其Pytorch实现一、交叉熵二、Focal loss三、Pytorch1.[交叉熵](https://pyto…

    SpringCloud入门实战(十二)-Sleuth+Zipkin分布式请求链路跟踪详解

    &#x1f4dd; 学技术、更要掌握学习的方法&#xff0c;一起学习&#xff0c;让进步发生 &#x1f469;&#x1f3fb; 作者&#xff1a;一只IT攻城狮 &#xff0c;关注我&#xff0c;不迷路 。 &#x1f490;学习建议&#xff1a;1、养成习惯&#xff0c;学习java的任何一个技术…

    Keras-5-深度学习用于文本和序列-处理文本数据

    深度学习用于文本和序列 说明: 本篇学习记录为&#xff1a;《Python 深度学习》第6章第1节&#xff08;处理文本数据&#xff09; 知识点: 深度学习处理文本或序列数据的基本方法是&#xff1a;循环神经网络 (recurrent neural network) 和 一维卷积神经网络 (1D convert)&…

    SpringBoot—统一功能处理

    SpringBoot—统一功能处理 &#x1f50e;小插曲(通过一级路由调用多种方法)&#x1f50e;使用拦截器实现用户登录权限的统一校验自定义拦截器将自定义拦截器添加至配置文件中拦截器的实现原理统⼀访问前缀添加 &#x1f50e;统一异常的处理&#x1f50e;统一数据格式的返回统一…

    天天刷题-->LeetCode(两数相加)

    个人名片&#xff1a; &#x1f405;作者简介&#xff1a;一名大二在校生&#xff0c;热爱生活&#xff0c;爱好敲码&#xff01; \ &#x1f485;个人主页 &#x1f947;&#xff1a;holy-wangle ➡系列内容&#xff1a; &#x1f5bc;️ tkinter前端窗口界面创建与优化 &…

    oracle启动/关闭/查看监听+启动/关闭/查看数据库实例命令

    启动oracle第一步启动监听&#xff0c;第二步启动数据库实例 &#xff08;1&#xff09;输入su oracle进入oracle用户状态 &#xff08;2&#xff09;这里的密码是你的root密码 1 启动/关闭/查看监听命令 &#xff08;1&#xff09;启动监听—— lsnrctl start &am…

    Permission denied (publickey,password)问题的解决办法

    [15:29:00.146] Terminal shell path: C:\WINDOWS\System32\cmd.exe [15:29:01.703] > root59.110.21.45: Permission denied (publickey,password). 解决&#xff1a; RSA key 登录方法/home/user/ 目录下建立 .ssh/ 文件夹 cd ~/ mkdir .ssh # 注意.ssh文件夹的权限 ch…

    GIT版本控制常规性操作演示汇总

    文章目录 GIT基本操作GIT配置个人信息配置&#xff1a;GIT查看个人信息配置&#xff1a;GIT的三大区域GIT回滚&#xff1a;git resetGIT恢复日志&#xff1a;git reflogGIT三大区域转换GIT新建分支GIT合并分支GIT删除分支码云上创建项目GIT变基&#xff1a;git rebase合并提交记…

    随机产生50个100以内的不重复的整数,设计位图排序算法进行排序。

    1.问题 随机产生50个100以内的不重复的整数&#xff0c;设计位图排序算法进行排序。 2.设计思路 阶段1&#xff1a; 初始化一个空集合    for i[0,n)    bit[i]0 阶段2&#xff1a; 读入数据i&#xff0c;并设置bit[i]1    for each i in the input file    bit[i]1…

    3.6.共享内存的学习

    目录 前言1. 共享内存2. shared memory案例3. 补充知识总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习精简 CUDA 教程-共享…

    基于C++、GDAL、OpenCV的矢量数据骨架线提取算法

    基于C、GDAL、OpenCV的矢量数据骨架线提取算法 CGAL已经实现了该功能&#xff0c;但由于CGAL依赖于Boost库&#xff0c;编译后过大&#xff0c;因此本文所采用的这套方式实现骨架线提取功能。 效果&#xff1a; 思路&#xff1a; 1、将导入shp按照要素逐一拆分成新的shp 2、…

    类Twitter风格的RSS阅读器

    本文完成于 2 月中旬&#xff0c;其中的反代还是 frp npm 方案&#xff1b; 什么是 RSS ? RSS 是用 PHP、Laravel、Inertia.js、Tailwind 和 Vue.js 编写的简单的类Twitter 风格的 RSS阅读器&#xff0c;支持 RSS和ATOM 格式。 命令行安装 在群晖上以 Docker 方式安装。 官…