相关指针的理解

本文详细探讨了指针的各种形式,包括指针数组、数组指针、函数指针以及函数指针数组。通过实例解析了它们的定义、类型以及使用方法,帮助读者理解指针的本质和在不同场景中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

指针从来都是一个难以消化的知识,你需要透过表象看到其本质,才会让你加深对指针的认识。
指针,顾名思义,这是一个存储某个变量地址的变量。该地址指向某个变量,就像指针一样,所以这个变量叫做指针。
接下来让我们看看下面这些包含指针的家伙到底是些什么东西。

指针数组

我们只看这个名字,会发现其本质是一个数组,而指针看起来更像是一个“形容词”。
那么什么是指针数组呢?
举个例子,我们创建一个数组arr[],里面可以放整形元素例如{1,2,3,4,5};也可以放一些字符{‘x’,’i’,’x’,’i’};那么有一堆指针,我们想把它们存起来,能不能放到数组里面呢?答案是可以的。而这个存放指针的数组就叫做指针数组。
指针数组的类型如下:
类型 *数组名[ ];
int *arr[10];
char *api[20];

数组指针

就像指针数组那样,我们先按照其名字分析一下它的本质是什么。”数组”像是一个形容词形容”指针”,那么数组指针的本质就是指针啦。数组指针指的就是存放某个数组地址的指针。对其解引用可以得到这个数组。(注意:这个指针存放的是整个数组的地址,而非数组首元素的地址!!!)
数组指针的类型如下:

类型 (*指针名)[ ] = &arr;(&arr就是传说中的某个数组的地址了)

int (*parr)[10] = &arr1;
char (*parr)[20] = &arr2;

怎么理解int (*parr)[10]这个式子呢?

( )优先级最高,因此*parr先结合,这表示parr是一个指针。接下来是下标引用,所以parr指向的是一个数组。这个声明表达式中没有更多的操作符,所以数组的每个元素都是整形。
知道了数组指针的本质,让我们继续深究一下它到底是怎么用的。
int arr[3][5] = {0};
int (*parr)[5] = arr;

提个问题:指针parr到底指向哪里?

我们来分析一下。数组名单独放置可以表示该数组首元素的地址,那么对于二维数组arr[3][5],arr所表示的地址其实是arr[0]的地址。在二维数组arr里,我们可以把arr[0]当做一个数组名对待,这个数组中有五个元素。因此:
int (*parr)[5] = &arr[0];
也就是说parr指向二维数组arr第一行的地址

了解完指针数组和数组指针之后,让我们来解决这样一个问题:

int (*parr[10])[5];
这个东西它到底是一个数组还是一个指针呢?
别着急,这个看似复杂的声明只要我们一步步分析,总会找到正确的结果的。首先从优先级来看,()中的下标引用[]优先级最高,它和parr先结合,那么首先确定这个复杂的声明本质是一个数组parr[10]。我们去掉parr[10]后发现这个声明变成int (*)[5];这代表指向大小为5个整形元素的数组的指针。那么这些指针怎么存放呢?还记得parr[10]吗,没错,就存放在数组parr里面。
因此这个声明的含义是声明能存放是个指针的指针数组parr,其中每个指针可以指向一个大小为5个整形元素的数组。

函数指针

我们知道一个整形数它有地址,一个字符它有地址,甚至数组也有它自己的地址。那么我们平常使用的函数其实也有自己的地址。
函数指针类型如下:

返回类型 (*指针名)(函数参数类型);

int Add(int a,int b){
return  a+b;
}
int (*pfun)(int ,int) = Add;
printf("%d\n",pfun(1,2));
这其中使用了通过函数指针调用函数,对于函数Add();可以直接调用pfun();

函数指针数组

函数指针数组就是存放返回类型和参数类型一致的若干函数指针的数组。返回类型和参数一致这个条件很关键!
关于函数指针数组的定义:
int (*pfunArr[4])(int ,int);

其中pfunArr[4]表示数组,去掉pfunArr[4]后…

int (*)(int ,int);

这是一个函数指针类型,这就说明数组pfunArr[4]中包含元素种类就是函数指针了。

那么接下来我们写一段代码看看到底是怎么定义函数指针数组的。
int Add(int x,int y)
{
    return x+y;
}
int Sub(int x,int y)
{
    return x-y;
}
int (*pfunArr[2])(int ,int) = {
Add,
Sub};//方法一

typedef int (*pfun_t)(int ,int);
pfun_t pfunArr = {
Add,
Sub};//方法二

方法一用类似于数组定义方式直接定义,简单粗暴。
方法二采用typedef作为辅助,首先用typedef声明了一个函数指针数组类型pfun_t,在用此类型定义一个函数指针数组变量pfunArr并将其初始化。

使用方法如下:
#include<stdio.h>
int main()
{
    int x = 0;
    int y = 0;
    int ret = 0;
    printf("1 for Add, 2 for Sub");
    printf("input your choice:/n");
    scanf("%d",&x);
    printf("input your numbers");
    scanf("%d%d",%x ,&y);
    switch(input)
    {
    case 1:
        ret = pfunArr[1](x, y);
    case 2:
        ret = pfunArr[2](x ,y);
    }
    return 0;
}

如上,如果要调用函数指针数组中的内容时,只需要
数组名[函数指针对应下标](对应类型参数)即可。

指向函数指针数组的指针

这名字够绕口的…其实这就是一个指针,它指向我们上面所提到的函数指针数组。
指向函数指针数组的指针的定义:
int (*arr[5])(int ,int) = {NULL,Add,Sub,Mul,Div};//这定义了一个大小为5的函数指针数组。
int (*(*p)[5])(int ,int) = &arr;//指针p就是指向函数指针数组arr的指针。

怎么理解这个定义方式呢?
首先*和p先结合,表明p是一个指针。去掉*p后,剩下了

int ( *[5])(int ,int);

我们发现这就是一个函数指针数组类型。所以这个定义方式我们就可以理解啦。

调用方式如下:
int ret = (*p)[1](1,2);

*p解引用后得到数组arr相当于数组名,那么arr [1] (1,2)调用了函数Add并且传入参数1,2。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值