C语言易错知识点:二级指针、数组指针、函数指针

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

1.二级指针:

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

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

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

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

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

2.一维数组指针:

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

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

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

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

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

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

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

下面四种写法均等效:

3.二维数组指针:

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

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

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

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

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

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

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

注意二维数组传参:

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

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

&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 };它可以用于传递参数相同,且实现的功能有相似度的几种函数的集合,如加减乘除的函数的集合。

cpp 复制代码
#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;
}

至于这种数组的大小,就看函数参数的大小和数组的元素个数就能算了:

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

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

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

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

相关推荐
darkchink16 分钟前
[LevelDB]Block系统内幕解析-元数据块(Meta Block)&元数据索引块(MetaIndex Block)&索引块(Index Block)
android·java·服务器·c语言·数据库·c++·分布式
Rinai_R29 分钟前
xv6-labs-2024 lab2
c语言·操作系统·学习笔记·计算机基础·实验
xiecoding.cn43 分钟前
Sublime Text使用教程(用Sublime Text编写C语言程序)
c语言·c++·青少年编程·编辑器·sublime text
Wythzhfrey1 小时前
51单片机Day03---让一个LED灯闪烁
c语言·单片机·嵌入式硬件·c#·51单片机
houliabc2 小时前
C语言个人笔记
c语言·数据结构·笔记·算法
双叶8362 小时前
(51单片机)串口通讯(串口通讯教程)(串口接收发送教程)
c语言·开发语言·c++·单片机·嵌入式硬件·microsoft·51单片机
阿巴~阿巴~3 小时前
蓝桥杯 C/C++ 组历届真题合集速刷(一)
c语言·c++·算法·蓝桥杯
knightkkzboy4 小时前
《C语言中的“魔法盒子”:自定义函数的奇妙之旅》
c语言·开发语言·函数
Dovis(誓平步青云)5 小时前
【数据结构】排序算法(下篇·终结)·解析数据难点
c语言·数据结构·学习·算法·排序算法·学习方法·推荐算法
北冥有鱼被烹15 小时前
【工具】如何将一个脚本作为C语言的一个文件被include到新的C文件中然后执行?(C语言 array的方式)
c语言