【c语言进阶】如此清晰的指针讲解让你再也不怕学不会指针了,硬核指针讲解。

🎇前言🎇

在学习c语言中,很多人都觉得指针是一个难点。而同时指针在c语言中又是非常重要的工具,如果不能熟练的掌握指针,c语言的学习是不完整的,本篇文章总结了大家在深入学习指针时所需要掌握的知识。

 

目录

🎇前言🎇

💎指针初阶内容回顾💎

 💎字符指针💎

✨数组指针和指针数组✨

数组指针

指针数组

区分数组指针和指针数组

✨数组传参与指针传参✨

数组的传参

指针的传参

 ✨函数指针✨

⚖函数指针数组✨

✨回调函数的概念✨



💎指针初阶内容回顾💎

1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
2. 指针的大小是固定的4/8个字节(32位平台/64位平台)。
3. 指针是有类型,指针的类型决定了指针的+-整数的步长,指针解引用操作的时候的权限。
4. 指针的运算


 💎字符指针💎

字符指针是一种常见的指针,一般用 char* 来表示:

下面来介绍字符指针的两种常见的使用方法:

 一:用来存放字符变量的地址

 二:存放常量字符串的地址

 请大家思考一个问题此时指针变量p中存放的是什么?是这个常量字符串?还是这个常量字符串的地址?还是这个常量字符串首元素的地址?

很多人第一次见这种字符指针使用方式时,都会下意识的误认p指针存放的是这个常量字符串,但这种想法显然不成立,因为指针的作用是储存地址的,而把常量字符串赋值给指针,指针其实拿到的是这个常量字符串首元素的地址。

由上面的讲述,现在我来考虑这样一个经典的问题:

 

运行结果是这样的:

 

这到底是为什么呢?

原因是:我们用这个常量字符串去开辟两个数组时,实际上开辟了两块不同的内存空间,而这个常量字符串本身是存储在内存中的静态区,因此我们拿出它的地址赋值给两个指针时,拿到的是同一块内存空间。


✨数组指针和指针数组✨

现在我们来介绍并区分一组概念:数组指针和指针数组

数组指针

首先大家思考一个问题:数组指针是数组还是指针呢?

答案是:数组指针是指针,是指向数组的指针。

下面来学习数组指针的定义初始化与使用。

 从结果上可以清晰的看出来,两个地址差值是40,刚好是整个数组的空间大小。

在这里出现了一个新朋友 &arr ,下面我们来解释一下 &arr 和arr到底有什么区别。

&数组名和数组名的区别

1:&数组名:这里的数组名代表的是整个数组,所以这句代码的意思是取出整个数组的地址。

2:数组名一般被认为是首元素的地址

补充:数组名什么情况下表示整个数组,什么情况下表示首元素的地址

1:数组名代表整个数组:只有&数组名和sizeof(数组名)即数组名单独放在sizeof的内部。

2:除了上面两种情况,其它所有情况都数组名表示首元素的地址。


指针数组

在大家前面的学习中想必已经了解过整型数组,字符数组,浮点型数组等多种数组。

我们把元素类型是指针的数组称为指针数组。

下面举例介绍指针数组的使用


区分数组指针和指针数组

请大家分辨以下三个变量的类型

1:int *parr1[10];
2:int (*parr2)[10];
3:int (*parr3[10])[5];

给出答案:1:parr1首先与[]结合,说明它是个数组,数组有10个元素每个元素是一个一级整型指针。指针数组

2:parr2首先与*号结合,说明它是一个指针,该指针指向一个有10个元素且每个元素均为整型的数组。数组指针

3:parr3先和[]结合,说明它是一个有10个元素的数组,其中每个元素都是指向一个有5个元素且每个元素均为整型的数组。存放数组指针的数组


✨数组传参与指针传参✨

大家可能有想过为什么c语言要存在指针?现在给出其中重要的一个原因。

在函数传参的时候,如果采用传值调用,则需要对实参进行拷贝,如果在实参所占空间很大时,这时对实参进行一次拷贝,就会浪费大量的栈区空间。而若我们进行传址调用,只需要把实参的地址传递上去,并不需要对实参进行拷贝,而且地址只占用(4/8)个字节的空间,节省了空间。

一般结构体传参的时候,用传址调用更好。


数组的传参

在这里我以二维数组传参作为例子

注意:二维数组的数组名在表示首元素的地址时,代表的是第一行的地址,也就是说二维数组的每一个元素是它的每一行

指针的传参

在这里我们以一级指针传参为例

1:一级指针的传值调用:对于指针的传值调用是用同级的指针接收,例如一级指针传参用一级指针接收,二级指针传参用二级指针接收。

2:一级指针的传址调用:对于指针的传址调用是用下一级的指针接收的,例如一级指针传参用二级指针接收。

 在这里就不得不讨论传值调用和传址调用的区别了。

详细内容请看这篇文章:函数


 ✨函数指针✨

从字面意思大家就可以知道函数指针其实是一种指针,是指向函数的指针。

函数指针储存的是函数的地址:请大家分析下面这个例子

从中大家可以清晰的看出来,函数也是有地址的,且以上两种方式都可以打印出函数的地址。

我们知道函数的地址存放在函数指针中,那么函数指针具体是怎样使用的呢?


⚖函数指针数组✨

相信经过前面的学习,大家应该能分辨清楚函数指针数组是什么意思了。

函数指针数组顾名思义就是一个数组,它的每一个元素都是一个函数指针。

函数指针数组的用途是:转移表

现在我们可以利用函数指针数组实现一个简易的计算器:

在这里我只给出代码:

//模拟实现计算器
int add(int x, int y)
{
	return x + y;
}
int sub(int x, int y)
{
	return x - y;
}
int mul(int x, int y)
{
	return x * y;
}
int div(int x, int y)
{
	return x / y;
}
void menu()
{
	printf("********************\n");
	printf("***1:add****2:sub***\n");
	printf("***3:mul****4:div***\n");
	printf("********0:exit******\n");
	printf("********************\n");

}
int main()
{
	int x = 0;
	int y = 0;
	int input = 1;
	int ret = 0;
	int(*pc[5])(int, int) = { 0,add,sub,mul,div };

	while (input)
	{
		menu();
		printf("请输入你要计算的两个操作数>:");
		scanf("%d %d", &x, &y);
		printf("请输入你的选择:>");
		scanf("%d", &input);
		if (input >= 1 && input <= 4)
		{
			int ret = (*pc[input])(x, y);
			printf("ret=%d\n", ret);
		}
		else if(input==0)
		{
			printf("退出计算器\n");
		}
		else
		{
			printf("输入错误\n");
		}
	}
	return 0;
}

✨回调函数的概念✨

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

回调函数顾名思义就是把函数作为参数传递给函数,在函数参数部分用函数指针来接收,在函数内部通过函数指针来调用函数时,我们将这个函数称为回调函数。

回调函数的应用十分广,只要涉及到将函数作为参数传递就可以使用回调函数。

下面留一个思考题:对于库函数qsort而言,我们在使用它的时候需要传递一个比较函数作为比较器,请大家写用于整型比较的比较器,用于字符比较的比较器,用于结构体中某个成员的比较器等等,你想比较什么就写什么比较器。

大家能不能自己编写一个函数模拟实现qsort呢?

答案会在下期揭晓。


以上代码,还可做优化在此仅作参考,若有更好的算法,还望能够私信告知,多谢各位。

由于本人水平十分有限,若有错误请即使告知!如果有帮助别忘了,万分感谢。

点赞👍         收藏✨    关注✌

 

 

 

 

 

 

  • 38
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 18
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值