一篇文章了解指针变量

字符指针变量

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

它的使用情况如下:

#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&…

在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…

【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…

目标检测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…

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

**单片机设计介绍&#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 的机器翻…

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

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

Java Spring + SpringMVC + MyBatis(SSM)期末作业项目

本系统是一个图书管理系统&#xff0c;比较适合当作期末作业主要技术栈如下&#xff1a; - 数据库&#xff1a;MySQL - 开发工具&#xff1a;IDEA - 数据连接池&#xff1a;Druid - Web容器&#xff1a;Apache Tomcat - 项目管理工具&#xff1a;Maven - 版本控制工具&#xf…

探索人工智能领域——每日20个名词详解【day12】

目录 前言 正文 总结 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filotimo__✍️原创&#xff0c;首发于CSDN&#x1f4da;。 &#x1f4e3;如需转载&#xff0c;请事先与我联系以…

进程、线程、线程池状态

线程几种状态和状态转换 进程主要写明三种基本状态&#xff1a; 线程池的几种状态&#xff1a;

STM32的BKP与RTC简介

芯片的供电引脚 引脚表橙色的是芯片的供电引脚&#xff0c;其中VSS/VDD是芯片内部数字部分的供电&#xff0c;VSSA/VDDA是芯片内部模拟部分的供电&#xff0c;这4组以VDD开头的供电都是系统的主电源&#xff0c;正常使用时&#xff0c;全部都要接3.3V的电源上&#xff0c;VBAT是…

Leetcode2477. 到达首都的最少油耗

Every day a Leetcode 题目来源&#xff1a;2477. 到达首都的最少油耗 解法1&#xff1a;贪心 深度优先搜索 题目等价于给出了一棵以节点 0 为根结点的树&#xff0c;并且初始树上的每一个节点上都有一个人&#xff0c;现在所有人都需要通过「车子」向结点 0 移动。 对于…

从阻抗匹配看拥塞控制

先来理解阻抗匹配&#xff0c;但我不按传统方式解释&#xff0c;因为传统方案你要先理解如何定义阻抗&#xff0c;然后再学习什么是输入阻抗和输出阻抗&#xff0c;最后再看如何让它们匹配&#xff0c;而让它们匹配的目标仅仅是信号不反射&#xff0c;以最大能效被负载接收。 …

Amazon CodeWhisperer 开箱初体验

文章作者&#xff1a;Coder9527 科技的进步日新月异&#xff0c;正当人工智能发展如火如荼的时候&#xff0c;各大厂商在“解放”码农的道路上不断创造出各种 Coding 利器&#xff0c;今天在下就带大家开箱体验一个 Coding 利器&#xff1a; Amazon CodeWhisperer。 亚马逊云科…

99基于matlab的小波分解和小波能量熵函数

基于matlab的小波分解和小波能量熵函数&#xff0c;通过GUI界面导入西储大学轴承故障数据&#xff0c;以可视化的图对结果进行展现。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 99小波分解和小波能量熵函数 (xiaohongshu.com)https://www.xiaohongshu.co…