C/C++易错知识点(2):二级指针、数组指针、函数指针

指针在C语言中非常关键,除开一些常见的指针用法,还有一些可能会比较生疏,但有时却也必不可少,本文章整理了一些易错知识点,希望能有所帮助!

1.二级指针:

2ab567f99dc74a5fb7c598652e9fe23a.png

parr是一个指针数组,其中每个元素存储字符串首字符的地址

d120d1e5c04f4abb89f9e27ac31d35c2.png

parr在这里表示首元素的地址,首元素是"Hello!"的'H'的地址,所以parr表示的是'H'的地址的地址,用char**来存储,如果解引用p就得到'H'的地址,相当于parr[0]。

如果使用p + 1,就会跳过一个char*的大小,在这里是8个字节(64位平台)。要理解p的加法含义,我们需要知道内存中的每一个字节都有一个地址,这个地址相当于内存的标签,它指向我们存储的内存空间,存储该数据需要k个字节,那么这些地址的数值差也是k。

83d0070198314e248fdfc435a742380e.png

以上面的例子讲解:p对应的是首元素地址,相当于一块内存空间的标签,在p这个地址下存储char*的具体值,占了8个字节。p + 1就会找到紧接着第一个char*的下一个char*存储的内存空间的地址。p + 2同理。

0ea1c3841d1048c09ac906b4f6733734.png

139c85e5aa354b77b3e3a2e33c152b3f.png

我们可以通过这两张图看到,地址是内存空间的标签,在内存里存储数据,地址则是负责找到这块空间。理解了这里,那么指针的大部分问题都会解决。

2.一维数组指针:

注意数组指针的本质是指针,它存储的值是数组的首元素地址,象征着它指向的对象是一个数组。但是,很多人会注意到,既然存储的值和单独取首元素地址的指针存储的值相同,那么怎么区分它们?

区分它们的主要方式有以下几点:首先,指针+1跳过的大小不同,数组指针+1会跳过数组的大小,而单独取首元素地址对应的指针+1只会跳过该元素的大小。

8c52e215b4624fd294502abea2e4ab79.png

这里可以轻松算出两者之间相差32,即一个数组的大小。

4a8894914f814dfea961cb2c3adb03ad.png

注意:arr单独表示整个数组,而arr + 0 表示第一个元素地址,两者有本质区别

那么,既然两者存储的值相同,那么它们之间在除强制转换这种方法以外是否有其它转换方法?

我们知道,数组指针是对整个数组取地址,即&arr,假设这个指针表示为int (*parr) [10] = &arr,那么*parr得到的就是*(&arr)即arr,相当于首元素地址,也就是int*,所以首元素的地址也可表示为int* p = *parr。

0e73932029b74d9db407556b8bede88a.png

我们要尝试理解它的本质,不要死记硬背,学会分析会帮助我们更好的运用指针。

下面四种写法均等效:

949540125c69469b86e97d25bb34fe20.png

3.二维数组指针:

二维数组指针是一维数组指针的变形,理解了一维数组的指针,二维数组指针就可以轻松应对了。

首先熟悉一下二维数组的初始化过程:

9b0597c523454b3faf88812f898c28bd.png

其中arr[2][2]中第一个2代表2行,第二个2代表2列。

下面是有关二维数组指针易混的代码,可以尝试解释:

3a28f0ca98a045888e8938b642094d3f.png

对数组的解释具体如下图:

c068952634884c6c8526baeec6c8b07a.png

理解了这里,那么二维数组就基本掌握了,下面看看整型数组指针和整型指针的转换,加深理解:

0c57b28c28cb4c2aa6541613543df0cb.png

说到底,二维数组就是将一维数组作为元素存储在数组中,刚开始会觉得有点绕,不过多看几遍就能很好理解运用了。

注意二维数组传参:

490e53c332fa4f7ea7e8bd0ed5a19ece.png

这里arr传的是首元素(数组)地址,要用数组指针来接收,数组指针传参不能省略元素个数

57af2f1f9eb64a1ebc7c24a8aabd0a07.png

667a356193724d4d8445b19fc9a681da.png

二维数组在函数内取值要注意层级:

a10cd18a5d4f49809fc5f6599a69fc63.png

&arr是对整个arr取地址,是二维数组的指针,第一次解引用得到arr,首元素(数组)的地址,即一维数组指针,第二次解引用是对元素数组解引用,得到首元素(整型)的地址(注意理解)即int*,第三次解引用就能得到值。

4.函数指针:

函数指针一般用的不多,但是我们要清楚它的用法。对于int Fun (int a, int b),其对应的函数指针应表示为int (*pFun) (int a, int b) = Fun,当然也可写作&Fun。使用过程中,可以直接将pFun当作函数名一样使用,如pFun (1, 2)。多个函数指针也可以组成一个数组,成为函数指针数组,如int (*pFunarr[2]) (int a, int b) = { pFun1, pFun2 };它可以用于传递参数相同,且实现的功能有相似度的几种函数的集合,如加减乘除的函数的集合。


#include <stdio.h>

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;
}

int main()
{
	int (*pFun[4]) (int x, int y) = { add, sub, mul, div };

	printf("%d\n%d\n%d\n%d", pFun[0](1, 1), pFun[1](1, 1), pFun[2](2, 3), pFun[3](8, 2));

	return 0;
}

36ce2c7dcc2d4cbcb9dc82b5376469ac.png

注意函数指针和函数指针数组传参:

b3980b27ea2a440e94dc322a41921936.png

 注意因为函数指针创建可以&fun也可直接fun,在解引用时也可选择加*或不加*

556582ccbe8d48edb81e9413dc025be6.png

但是要注意层级不要弄错:

912358fb88614f0b934b8748fad7e08f.png

这里是函数指针的指针,pFun + 1相当于找到了存储减法函数地址的地址,但是只有在减法函数地址这个层级才能使用。

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值