【C语言】进阶指针Four

186 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情

🚩write in front🚩

🔎大家好,我是泽奀,希望你看完后。能对你有所帮助,不足请指正,共同学习交流🔎
🏅2021年度博客之星物联网与嵌入式开发TOP5~2021博客之星Top100~阿里云专家^星级博主~掘金⇿InfoQ创作者~周榜34»总榜1712🏅
🆔本文由 謓泽 原创 CSDN首发🙉如需转载还请通知⚠
📝个人主页-掘金 (juejin.cn)💬
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​
📣系列专栏-[C系列] 从0到1 - 泽奀的专栏 - 掘金 (juejin.cn)🎓
✉️我们并非登上我们所选择的舞台,演出并非我们所选择的剧本📩

 💥 一级指针传参 

用一级指针接收数组名(首元素地址),写个函数把一级指针变量传递过去。打印出 arr 数组名当中的内容。函数当中传参是一级指针,所以也被称之为一级指针的传参。那么在实参当中我们就可以拿指针变量去接收传参当中的一级指针。 

💥重点核心: 一级指针传参就用一级指针来进行接收!

示例,如下代码所示 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void print(int* p2, int sz)
{
	int i;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p2+i));
	}
}
int main(void)
{
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* p1 = arr;
	print(p1, sz);
	return 0;
}

*编译运行结果: *1 2 3 4 5 6 7 8 9 10

💥注意:当一个函数的参数部分为一级指针的时候,函数接收的参数依旧是一级指针!


💥 二级指针传参  

取出 &a 的地址,存放到指针变量 pa,pa 此时此刻就是一级指针变量。对于一级指针变量来说,取出 pa 的地址就要用个二级指针来进行存放 ppa。这个时候我们把二级指针传参到自定义函数当中,这样我们就把二级指针给进行传参。形参当中那么就需要用到二级指针来接收。

💥注意:二级指针是专门存放一级指针变量的地址的。

示例,如下代码所示 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void print(int** ppa)
{
	*ppa = 20;
}
int main(void)
{
	int a = 0;
	int *p = &a;
	int **ppa = &p;
	print(ppa);
	printf("a = %d", p);
	printf("a = %d", a);//a是不会改变的
	return 0;
}

编译运行结果:p = 20

从上述结果可以得知,我们通过二级指针改变了原本整形指针 p 的结果。


🔥 指针的类型 

从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。

1、 int p; 指针的类型是 int

2、 char p; 指针的类型是 char

3、 int p; 指针的类型是 int

4、 int (p)[2]; **指针的类型是 int()[2]**

5、 int (p)[4]; 指针的类型是 int()[4]


🔥 指针所指向的类型

当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。

从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。

1、 int*ptr; 指针所指向的类型是 int

2、 char*ptr; 指针所指向的的类型是 char

3、 intptr;** 指针所指向的的类型是 int*

4、 *int(ptr)[3]; 指针所指向的的类型是 int()[3]

5、 int(ptr)[4]; 指针所指向的的类型是 int()[4]*

在指针的算术运算中,指针所指向的类型有很大的作用。 


🌀 函数指针 

数组指针:是指向数组的指针。

函数指针:是指向函数的指针,存放函数地址的指针。

那么 & 地址函数名,取出的就是函数的地址。

从这里我们就联想到了 数组名 != &数组名,那么函数也是这样的吗?

答案:不是!函数名 == &函数名(完全等价)

示例,如下代码所示 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int add(int x,int y)
{
	return x + y;
}
int main(void)
{
	int a = 10;
	int b = 20;
	add(a,b);
	printf("&函数名 - %p\n",&add);
	printf(" 函数名 - %p\n",add);
	return 0;
}

编译运行结果如下 👇 

​编辑​

由此,证明了 ****函数名 == &函数名(完全等价)

那么指针所指向的类型就是函数返回值当中的类型。

当然,函数的地址也是可以取&出来,赋值给函数指针变量。

格式: *函数返回值(指针变量)(函数参数类型)

💥注意:这个函数指针变量是因为我们存放的地址是函数!

接着上面代码,示例,如下代码所示 👇

int (*ptr)(int,int) = &add;

这里的 ptr 就是函数指针变量。 

那么这里 ptr 相当于存放函数的地址,如果我对 ptr 进行解引用的话就相当于找到了函数的地址。而找到这个函数我们需要把 *(ptr) 用小括号给括起来。调用的时候进行传参,所以需要在后面给上()

示例,如下代码所示 👇

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int add(int x,int y)
{
	return x + y;
}
int main(void)
{
	int (*ptr)(int, int) = &add;
	int ret = (*ptr)(3, 5);
	printf("ret = %d\n", ret); 
	return 0;
}

编译运行结果👉 ret  =  8

从上述代码中可以说明调用时✔的,木的问题。这个地方用的就是函数指针,用了一个函数指针去调用它所指向的函数。

int (*ptr)(int, int) = add;

当然,你这样子也是和上面是等价的。 

int ret = ptr(3, 5);

以及这样子也都是没有问题的,运行结果都是一样的。