指针进阶(详解)
创始人
2024-05-08 11:33:23
0

指针进阶

  • 一.字符指针
  • 二.指针数组
    • 1.一次打印多个字符串
    • 2.模拟二维数组
  • 三.数组指针
    • 1.定义
    • 2.应用
  • 四.函数指针
  • 五.函数指针数组
  • 六.指向函数指针数组的指针
  • 七.回调函数

在这里插入图片描述

在开始这篇之前,前面有两篇指针初阶,如果需要的话可以去看看哟!指针初阶1,指针初阶2

一.字符指针

在这里插入图片描述

对于一个字符串,那么指针又该如何指向呢?

在这里插入图片描述

毫无疑问p里存的是地址,那它存了abcdefg的所有地址吗?当然不是,因为它根本存不下(一个指针在32为机器下只有4个字节,如果不太明白可以看看指针初阶)。实际上,它存的是首字符a的地址。字符串在内存里是连续存放的,所以只需要找到首元素地址就可以啦。ps:这和数组很像,事实上处理字符串时也可以按照下标来处理。

在这里插入图片描述

追加一个小知识:字符串可以直接使用%s打印是因为它有\0作为结束标志。但如果全部是整数的话,没有结束标志就只能通过下标挨个打印。

一道面试题

在这里插入图片描述

在这里插入图片描述

首先,str1和str2是两个数组,需要开辟两个空间,而数组名代表首元素地址,空间不同首元素地址自然不同,故str1!=str2。但是str3和str4是指针变量,里面存的都是h的地址并且hello,bite是一个常量字符串永远不能被改变。所以此时编译器就会认为既然都一样且没法被改变,那么就只会开辟一个空间,str3和str4都指向同一空间,故str3==str4。(可以理解为编译器的一种规定)

二.指针数组

存放整形的数组->整形数组,存放字符的数组->字符数组,存放指针的数组->指针数组。

1.一次打印多个字符串

在这里插入图片描述

在这里插入图片描述

我们如何打印呢?很简单,因为数组内每个元素存的都是各个字符串首元素地址,所以我们只需要依靠首元素地址就能打印出所有字符串。

在这里插入图片描述
在这里插入图片描述

2.模拟二维数组

在这里插入图片描述

它的打印需要使用两个for嵌套,因为它不能像字符串那样打印一串,这里其实也就是用一维数组模拟二维数组(但不同的是二维数组每一行每一列都是连续存放的,而这里每一行不一定连续)

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

三.数组指针

1.定义

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

追加个小知识:【】的优先级高于*所以别忘了加括号哦。

ps:如果pa先与*结合就说明是个指针,如果先于【】结合就说明是个数组。

pps:这里的&arr是整个数组的地址,也就是如果+1的话是跳过整个数组。注意与数组名区分开。

2.应用

1.强行使用

在这里插入图片描述

这样写实际上很别扭,当然实际上一般也没人会怎么写。所以它的真正作用体现在二维数组里。

2.正常使用

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

一些练习

在这里插入图片描述

四.函数指针

指向函数的指针。

一段代码

首先,函数名=&函数,故函数名就是函数地址(如果需要验证的话,写一个函数再用%p输出就可以了,这里就不再累述了)

在这里插入图片描述

分析这个指针的构成,首先是一个指针故pf应该先与*结合,其次指向一个函数,后面就应该接上(参数),最后该函数是int类型,故再前面写上int。将这3个部分串起来就是如上指针。

接下来使用pf指针调用Add函数。

在这里插入图片描述

在这里插入图片描述

首先对pf进行解引用,解引用后就是原函数。也就是*pf=Add,接下来是传参(参数1,参数2),这样就完成了调用功能。实际上,在调用时前面的星号是没有作用的,因为如我们平常调用函数Add(2,3),pf里存的本身就是Add,所以不需要解引用。

在这里插入图片描述

代码一

在这里插入图片描述

这道题的关键就是把0当成地址来看。

在这里插入图片描述

该代码是一次函数调用,调用0地址处的函数

ps:以上代码出自c语言缺陷与陷阱

代码二

在这里插入图片描述

依然从名字signal入手。

在这里插入图片描述

1.该代码是一次函数的声明。
2.声明的函数名字是signal
3.参数有两个,第一个是int类型,第二个是函数指针类型
4.signal函数的返回值是一个函数指针

五.函数指针数组

数组是一个存放相同类型数据的存储空间,那我们已经学习了指针数组,比如:int arr[10];数组的每个元素是int。那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢?

在这里插入图片描述

使用:简单的计算器

int add(int a, int b){return a + b;
}
int sub(int a, int b){return a - b;
}
int mul(int a, int b){return a * b;
}
int div(int a, int b){return a / b;
}
int main()
{int x, y;int input = 1;int ret = 0;do{printf("*************************\n");printf("*** 1:加法      2:减法***\n");printf("*** 3:乘法      4:除法*** \n");printf("**********0.退出*********\n");printf("*************************\n");printf("请选择:");scanf("%d", &input);switch (input){case 1:printf("输入操作数:");scanf("%d %d", &x, &y);ret = add(x, y);printf("ret = %d\n", ret);break;case 2:printf("输入操作数:");scanf("%d %d", &x, &y);ret = sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("输入操作数:");scanf("%d %d", &x, &y);ret = mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("输入操作数:");scanf("%d %d", &x, &y);ret = div(x, y);printf("ret = %d\n", ret);break;case 0:printf("退出程序\n");break;default:printf("选择错误\n");break;}} while (input);return 0;
}

这个代码很简单就不多说了。实际上我们可以看到这个代码很冗长繁琐,如果在之后我们需要给计算器添加新的功能的话,毫无疑问case会加长,我们能不能有一种方法避免这种写法呢?

int add(int a, int b){return a + b;
}
int sub(int a, int b){return a - b;
}
int mul(int a, int b){return a * b;
}
int div(int a, int b){return a / b;
}
int main()
{int x, y;int input = 1;int ret = 0;int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //使用数组去除冗长的调用while (input){printf("*************************\n");printf("*** 1:加法      2:减法***\n");printf("*** 3:乘法      4:除法*** \n");printf("**********0.退出*********\n");printf("*************************\n");printf("请选择:");scanf("%d", &input);if (0 == input){printf("退出程序。\n");break;}if ((input <= 4 && input >= 1)){printf("输入操作数:");scanf("%d %d", &x, &y);ret = (*p[input])(x, y);}elseprintf("输入有误\n");printf("ret = %d\n", ret);}return 0;
} 

使用函数指针数组的前提是所有的函数类型都相同,都是两个参,参数类型都是int,返回值都是int。

六.指向函数指针数组的指针

其实本质上就是一个数组指针,只不过这个数组的类型是一个函数指针类型数组。

在这里插入图片描述

要分辨类型,需要先看与哪个操作符结合。

一些练习

在这里插入图片描述

七.回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个 函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

应用例子qsort函数,由于篇幅比较大,将其放到了下一篇博客里qsort函数

在这里插入图片描述

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...