指针在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 };它可以用于传递参数相同,且实现的功能有相似度的几种函数的集合,如加减乘除的函数的集合。
#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相当于找到了存储减法函数地址的地址,但是只有在减法函数地址这个层级才能使用。