指针数组与数组指针、函数指针

一、指针数组与数组指针

1.1 概念与区别

  • 指针数组的实质是一个数组,这个数组中存储的内容全部是指针变量
  • 数组指针的实质是一个指针,这个指针指向的是一个数组

1.2 一般规律

  1. 找核心: 在定义一个符号的时候,关键在于搞清楚定义的符号是什么
  2. 找结合: 其次看谁和核心最近、谁和核心结合(结合的实质是运算)
  • 如果核心*结合,表示核心指针
  • 如果核心[]结合,表示核心数组
  • 如果核心()结合,表示核心函数

1.3 指针与数组的区分

1.3.1 int *p;

核心是pp*结合,所以p是一个指针

1.3.2 int p[5];

核心是pp[]结合,所以p是一个数组

1.4 指针数组与数组指针的区分

优先级:[]().->的优先级是所有运算符中最高的,均比*

1.4.1 指针数组 int *p[5];

1.4.1.1 分析:
  1. 核心是p
  2. p先和[]运算成一个数组,数组有5个元素
  3. 数组中的元素与*结合,数组中的元素都是指针,指向的元素类型是int类型
1.4.1.2 结论:

int *p[5];是一个指针数组

1.4.1.3 测试代码:
#include <stdio.h>
int main(void)
{
    int a[5];
    int *p[5];
    for (int i = 0; i < 5; i ++)
    {
        *(p + i) = &(*(a + i));
    }
    for (int i = 0; i < 5; i ++)
    {
        printf("&(*(a + %d)) = %p\n", i, &(*(a + i)));
        printf("  *(p + %d)  = %p\n", i, *(p + i));
    }
    return 0;
}
1.4.1.4 测试结果

指针数组测试
我们可以发现a[i]的地址和p[i]的值是一样的。

1.4.2 数组指针 int (*p)[5];

1.4.2.1 分析:
  1. 核心是p
  2. 由于()的存在,p先和*运算成一个指针
  3. 指针指向一个数组,数组有5个元素,数组中存的元素是int类型
1.4.2.2 结论:

int (*p)[5];是一个数组指针

1.4.2.3 测试代码:
#include <stdio.h>
int main(void)
{
    int a[5] = {1, 2, 3, 4, 5};
    int (*p)[5];//定义数组指针
    p = &a;//p指向数组a
    for(int i = 0; i < 5; i++)
    {
        printf(i == 4 ? "%d\n" : "%d ", *(*(p) + i));
    }
    return 0;
}
1.4.2.4 测试结果

数组指针测试
我们可以发现(*p)[i]a[i]的值是一样的。

1.4.3 指针数组 int *(p[5]);

int *p[5];效果是一样的,()并没有起作用

二、函数指针

2.1 函数指针的实质

  • 函数指针的实质还是指针,也就是指针变量,在32位系统中,也是占4个字节。
  • 所有的指针变量类型其实本质都是一样的,函数指针、数组指针、普通指针之间并没有本质区别,只是指针指向的变量不同
  • 函数的实质是一段代码,这一段代码在内存中是连续分布的,对于函数来说最关键的就是函数中的第一句代码的地址,这个地址就是函数地址,在C语言中函数名这个符号来表示。
  • 结合函数的实质,函数指针其实就是一个普通变量,这个普通变量的类型是函数指针变量类型,它的值就是某个函数的地址(也就是它的函数名这个符号在编译器中对应的值)

2.2 函数指针的书写方法

为什么要研究函数指针的书写?

C语言本身是强类型语言(每一个变量都有自己的变量类型),编译器可以帮我们做严格的类型检查。

类型检查测试代码:

#include <stdio.h>
int main(void)
{
    int* p;     //普通指针变量
    int (*a)[5];//数组指针变量
    p = a;
    return 0;
}

编译结果:
不兼容指针类型的分配

我们可以看出编译器报了assigment from incompatible pointer type**(不兼容指针类型的分配)**的警告

2.2.1 函数指针的书写

  • 假设一个函数结构为:函数返回值类型 函数名 (函数参数列表)
  • 那对应的函数指针为:函数返回值类型 (*指针变量名) (函数参数列表)

例如:

函数为:

void func(void)
{
    printf("Test func_pointer!\n");
}

其对应的函数指针是void (*pFunc)(void);
类型是:void (*)(void)

2.2.2 测试代码

#include <stdio.h>

void func1(void);
void func2(void);

int main(void)
{
    void (*pFunc1)(void);//定义函数指针
    void (*pFunc2)(void);//定义函数指针

    pFunc1 = &func1;
    pFunc2 = func2; //这个在下面的结果分析中说明
    pFunc1();
    pFunc2();     //调用函数
    printf("%p\n%p\n",func1,&func1);
    return 0;
}

void func1(void)
{
    printf("Test func1_pointer!\n");
}

void func2(void)
{
    printf("Test func2_pointer!\n");
}

2.2.3 测试结果分析

函数指针测试
我们发现程序通过了正常的编译,运行结果也有点出乎意料。我们在这里可以看出,函数名和数组名其实是不同的。我们需要记住以下两点:

  1. 函数名做右值时,func&func是一样的,都表示函数的首地址,这个我们需要特别注意一下。
  2. 调用的时候不需要再对函数指针进行解引用操作
发布了4 篇原创文章 · 获赞 0 · 访问量 214

猜你喜欢

转载自blog.csdn.net/weixin_43955214/article/details/104072389
今日推荐