一篇文章了解指针变量

字符指针变量

在指针的类型中我们知道有一种指针叫做字符指针

它的使用情况如下:

#include<stdio.h>
int main()
{char pa = 'w';char*p1=&pa;*p1 = 'a';printf("%c\n", *p1);return 0;
}

在这段代码当中,我们将‘w’字符的地址传到了p1里面,而p1就是一个字符指针。

除了上面这种使用方法,还有一种关于字符指针变量的使用方法如下:

#include<stdio.h>
int main()
{char* p1 = "abced";printf("%s\n", p1);return 0;
}

有没有感到很好奇,对于这段代码的解释,大家有什么想法吗?

咱们的第一个反应应该是,这个是不是把字符串“abced”放到字符指针p1里面啊,但真实情况不是这样的,这个是将“abced”中的首字母的地址放到了p1的指针变量当中,从而在打印的时候,可以通过p1找到字符串首字母的地址,从而顺藤摸瓜地打印出整个字符串。

下面呢,我们来看一段代码,这段代码是一道经典的面试题,来自《剑指offer》

#include<stdio.h>
int main()
{char arr3[] = "hello,bit.";char arr4[] = "hello,bit.";char* p1 = "hello,bit.";char* p2 = "hello,bit.";if (arr3 == arr4){printf("arr3 and arr4 are the same\n");}elseprintf("arr3 and arr4 are not same\n");if (p1 == p2){printf("p1 and p2 are the same\n");}elseprintf("p1 and p2 are not same\n");return 0;
}

下面是这段代码运行的结果

这个结果大家想到了吗??

其中的原理如下:

在数组中,用相同的常量字符串初始化数组时,系统会开辟不同的内存空间。

而在指针当中,两个指针指向的是同一个常量字符串,也就是指向同一个开辟下的内存空间。这个就是上面答案的原理所在。

数组指针变量

前面我们讲了指针数组,指针数组是一个数组,存放的是指针(地址),而数组指针是一个指针,存放的是数组的地址,看下面两个:

//指针数组和数组指针
//1.int*arr[10]
// 
//2.int(*arr)[10]

大家可以看看这两个,哪个是指针数组,哪个是数组指针。

很明显,第一个是指针数组,数组名是arr,数组中存放有10个元素,每个元素是int*类型

然后第二个是一个数组指针,根据优先级考虑,在这个当中,首先arr应该与*结合,构成一个指针,然后指向的是一个10个元素的数组,数组中的每个元素都是int类型

数组指针变量的初始化

数组指针是一个指针,存放的应该是数组的地址,那我们怎么可以得到数组的地址呢,&arr,通过这个便可以得到数组的地址

#include<stdio.h>
int main()
{int arr[10] = { 0 };int(*pte)[10] = &arr;return 0;
}

 

从这个当中我们可以看到,&arr和pte的地址是相同的,二者指向了同一块内存空间,这个就是数组指针变量的初始化。

二维数组传参的本质

有了前面的数组指针变量的基础,我们就可以好好地了解一下二维数组传参的内容,之前,我们写过二维数组传参的内容,请看下面的代码:
 

#include<stdio.h>
void print(int arr[3][4], int r, int j)
{for (int i = 0; i < r; i++){for (int h = 0; h < j; h++){printf("%d ", arr[i][h]);}printf("\n");}}
int main()
{int arr[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };print(arr, 3, 4);return 0;
}

 我们在之前的代码当中,形参是数组形式,实参也是数组的形式,除了这个写法,我们还有其他的写法吗?

我们再来看二维数组,二维数组其实可以看成是每个元素都是一维数组的数组,然后数组名是数组首元素的地址,也就是说,实参的第一个参数的意思是二维数组第一行的四个元素的地址,所以,我们可以在形参部分写成这样:

#include<stdio.h>
void print(int (*ptr)[4], int r, int j)
{for (int i = 0; i < r; i++){for (int h = 0; h < j; h++){printf("%d ", *(*(ptr+i)+h));}printf("\n");}}
int main()
{int arr[3][4] = { {1,2,3,4},{2,3,4,5},{3,4,5,6} };print(arr, 3, 4);return 0;
}

在这里,我们在详细讲一个*(*(ptr+i)+h),首先,先看最里面的那个括号,ptr是数组首元素的地址,ptr+i代表着二维数组的第几行的地址,然后再加*找到第几行的元素,也就是arr[i],然后用arr[i]+j代表的是第i行第j列的地址,然后在使用解引用符,就可以找到该地址所代表的元素,然后打印出来,就是数组。

数组名,是数组首元素的地址

&数组名,是数组的地址

函数名,是函数的地址

&函数名,也是函数的地址

二维数组传参,形参可以形成数组形式,也可以写成指针形式。

函数指针变量

通过前面对于指针变量的理解,我们大概可以知道,函数指针变量应该是一个指针变量,指向的应该是函数的地址,那么问题来了,函数有地址吗?让我们来看一下:

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

从上面的结果,我们可以看到,函数是有地址的,函数名就是函数的地址,那我们也可以通过&函数名来获得函数的地址,那我们也可以通过函数地址的调用实现对于函数的调用。

如果我们将函数变量的地址存放起来,就可以创建函数指针了,函数指针其实和数组指针是极其相似的。

void test()
{printf("hehe");
}
void (*ptr1)() = test;
void(*ptr2)() = &test;int Add(int x, int y)
{return x + y;
}
int (*ptr3)(int, int) = Add;
int (*ptr4)(int x, int y) = &Add;//加不加 x,y都是可以的

 函数指针类型分析:

函数指针变量的使用

通过函数指针调用指针所指向的函数

#include<stdio.h>
int Add(int x,int y)
{return x + y;
}
int main()
{int (*ptr)(int, int) = Add;printf("%d\n", (*ptr)(3, 4));printf("%d\n", ptr(3, 4));return 0;
}

 

两段有趣的代码

接下来,我们来看两段出自《C陷阱和缺陷》这本书中的代码:

(*(void(*)())0)() 

//第一段:
//(*(void(*)())0)()
/*在这段代码当中:
* 第一步:void(*)()这个是函数指针的类型
* 第二步:(void(*)())0----这个是对0的强制类型转换,使0转换成函数指针类型
* 第三步:(*(void(*)())0)()----是一个指针
*/

第二段:

第二段:
void (*signal(int, void(*)(int)))(int);
第一步:signal是一个函数名
第二步:函数名后面的(int, void(*)(int))是函数参数
第三步:整个又是一个函数指针,参数类型是int

typedef关键字

typedef是关键字没在C语言当中可以起到重命名的作用

 

typedef int* unit;
typedef void(*ptr)(int);
typedef void(*deff)();

函数指针数组

我们之前学了指针数组,同理,函数指针数组是将函数指针放入数组当中,那么这个该怎么实现呢??

//函数指针数组
void (*)()ptr[10] =; 

 

 

 

 

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

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

相关文章

vue3 自己写一个月的日历

效果图 代码 <template><div class"monthPage"><div class"calendar" v-loading"loading"><!-- 星期 --><div class"weekBox"><div v-for"(item, index) in dayArr" :key"index&q…

2.修改列名与列的数据类型

修改字段名与字段数据类型 1.修改字段名 有时&#xff0c;在我们建好一张表后会突然发现&#xff0c;哎呀&#xff01;字段名貌似写错了&#xff01;怎么办&#xff1f;要删了表再重新建一个新表吗&#xff1f;还是要删了这个字段再新建一个新的字段&#xff1f; 都不用&…

AIGC专题报告:生成式人工智能人人可用的新时代

今天分享的AIGC系列深度研究报告&#xff1a;《AIGC专题报告&#xff1a;生成式人工智能人人可用的新时代》。 &#xff08;报告出品方&#xff1a;埃森哲&#xff09; 报告共计&#xff1a;21页 人工智能发展迎来新拐点 ChatGPT 正在唤醒全球对人工智能&#xff08;AI&…

蛇形矩阵

蛇形矩阵是由1开始的自然数依次排列成的一个矩阵上三角形。 例如&#xff0c;当输入5时&#xff0c;应该输出的三角形为&#xff1a; 1 3 6 10 15 2 5 9 14 4 8 13 7 12 11 输入描述&#xff1a;输入正整数N&#xff08;N不大于100&#xff09; 输出描述&#xff1a;输出一个N…

MySQL七 | 存储引擎

目录 存储引擎 存储引擎特点 存储引擎选择 Innodb与MyISAM区别 存储引擎 默认存储引擎:InnoDB show engines;#展示当前数据库支持的存储引擎 存储引擎特点 特点InnoDBMyISAMMemory存储限制64TB有有事务安全支持--锁机制行锁表锁表锁Btree锁支持支持 支持 Hash索引--支…

在pom.xml中添加maven依赖,但是类里面import导入的时候报错

问题&#xff1a; Error:(27, 8) java: 类TestKuDo是公共的, 应在名为 TestKuDo.java 的文件中声明 Error:(7, 23) java: 程序包org.apache.kudu不存在 Error:(8, 23) java: 程序包org.apache.kudu不存在 Error:(9, 23) java: 程序包org.apache.kudu不存在 Error:(10, 30) jav…

【场景测试用例】上传文件

测试思路&#xff1a; 功能 上传符合需求给的文件格式&#xff0c;大小&#xff0c;宽高等可以正常上传 不同的文件格式最大/最小/中间的文件大小如支持批量上传可以正常上传 边界值如支持删除可以正常删除指定文件&#xff0c;其他文件不受影响如支持预览&#xff0c;可以正常…

【Java探索之旅】我与Java的初相识(一):Java的特性与优点及其发展史

&#x1f3a5; 屿小夏 &#xff1a; 个人主页 &#x1f525;个人专栏 &#xff1a; Java入门到精通 &#x1f304; 莫道桑榆晚&#xff0c;为霞尚满天&#xff01; 文章目录 一. Java语言概述与优势1.1 Java的概述1.2 Java语言的优势 二. Java领域与发展史2.1 Java的使用领域2.…

面试多线程八股文十问十答第二期

面试多线程八股文十问十答第二期 作者&#xff1a;程序员小白条&#xff0c;个人博客 相信看了本文后&#xff0c;对你的面试是有一定帮助的&#xff01; ⭐点赞⭐收藏⭐不迷路&#xff01;⭐ 1.进程和线程的区别 概念不同&#xff1a;进程是操作系统中的一个独立执行单元&a…

LeetCode56. Merge Intervals

文章目录 一、题目二、题解 一、题目 Given an array of intervals where intervals[i] [starti, endi], merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input. Example 1: Input: interva…

目标检测mAP计算以及coco评价标准

这篇是我对哔哩哔哩up主 霹雳吧啦Wz 的视频的文字版学习笔记 感谢他对知识的分享 讲一下目标检测中的一些常见的指标 在我们使用目标检测网络训练时 最后在验证集上会得到一个coco的评价列表 就像我们图中给的这一系列参数列表一样 我们再进一步引入两个概念 第一个叫做precisi…

P1 Qt的认识及环境配置

目录 前言 01 下载Qt Creator windows下载安装包拷贝到Linux Linux直接下载 02 Linux 安装Qt 前言 &#x1f3ac; 个人主页&#xff1a;ChenPi &#x1f43b;推荐专栏1: 《C_ChenPi的博客-CSDN博客》✨✨✨ &#x1f525; 推荐专栏2: 《Linux C应用编程&#xff08;概念类…

地址栏不安全提示

在使用浏览器时访问网站的时候&#xff0c;我们可能会遇到地址栏提示不安全的情况。这种情况通常都是是由于未安装有效SSL证书或者网站SSL证书过期等原因导致的。本文将介绍如何处理地址栏提示不安全的问题&#xff0c;以确保我们的上网安全。 1&#xff0c;缺少SSL证书&#x…

golang游戏服务器 - tgf系列课程01

TGF框架的特点和功能 课程介绍了TGF框架的特点和功能在第一节课程中我们并不会介绍框架的使用。我们希望在这节课程中,能让你了解到tgf是一个什么样的框架 概要 本节课程介绍了TGF框架的特点和功能。TGF是一个开箱即用的服务器框架, 适合中小型团队和独立开发者进行游戏开发。…

基于单片机音乐盒仿真仿真系统设计

**单片机设计介绍&#xff0c;基于单片机音乐盒仿真仿真系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的音乐盒仿真仿真系统是一种基于嵌入式系统技术的设计方案&#xff0c;用于模拟传统的音乐盒功能。它通…

002 self-attention自注意力

目录 一、环境 二、self-attention原理 三、完整代码 一、环境 本文使用环境为&#xff1a; Windows10Python 3.9.17torch 1.13.1cu117torchvision 0.14.1cu117 二、self-attention原理 自注意力&#xff08;Self-Attention&#xff09;操作是基于 Transformer 的机器翻…

【XILINX】记录ISE/Vivado使用过程中遇到的一些warning及解决方案

前言 XILINX/AMD是大家常用的FPGA&#xff0c;但是在使用其开发工具ISE/Vivado时免不了会遇到很多warning&#xff0c;(大家是不是发现程序越大warning越多&#xff1f;)&#xff0c;并且还有很多warning根据消除不了&#xff0c;看着特心烦&#xff1f; 我这里汇总一些我遇到的…

http和https区别

http和https区别 HTTP&#xff08;Hypertext Transfer Protocol&#xff09;和HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff09;是用于在网络上传输数据的两种协议。它们之间的主要区别在于安全性和数据传输方式&#xff1a; 安全性&#xff1a;HTTP是明文传…

华清远见嵌入式学习——QT——作业2

作业要求&#xff1a; 代码运行效果图&#xff1a; 登录失败 和 最小化 和 取消登录 登录成功 和 X号退出 代码&#xff1a; ①&#xff1a;头文件 #ifndef LOGIN_H #define LOGIN_H#include <QMainWindow> #include <QLineEdit> //行编辑器类 #include…

如何在centos8上配置一个ca证书颁发机构并且颁发一个自签名证书【超详细!!!】

在CentOS 8上配置CA证书颁发机构并颁发自签名证书的步骤如下&#xff1a; 1. 安装OpenSSL sudo dnf install openssl 2. 创建CA证书目录 sudo mkdir /etc/pki/CA/ sudo chmod 0700 /etc/pki/CA/ 3. 创建CA证书数据库 sudo touch /etc/pki/CA/index.txt sudo echo 1000 >…