指针进阶详解(下)

简介: 指针进阶详解(下)

前言

指针进阶详解(上)中,我们已经介绍了部分指针进阶相关知识,接下来我们将继续介绍指针进阶相关知识。

1. 函数指针

我们知道数组指针,是一个指向数组的指针。同理,函数指针是一个指向函数的指针。

既然是函数指针,就需要取出函数的地址。那函数的地址如何得到呢?

首先我们先看以下代码:

void test()
{
  printf("hehe\n");
}

int main()
{
  printf("%p\n", test);
  printf("%p\n", &test);
  return 0;
}

运行结果:

输出的两个地址就是test()函数的地址。那函数的地址如何保存起来呢?

下面再来看看这段代码:

void test()
{
  printf("hehe\n");
}

//下面pfun1和pfun2那个有能力存放test函数的地址呢?
void (*pfun1)();
void* pfun2();

首先,能存储地址,要求pfun1或pfun2是指针,那哪个可以?答案是:

pfun1可以存放。pfun1先和*结合,说明pfun1是一个指针;在和()结合,说明指针指向的是一个函数;最后和int结合,说明函数的返回类型是int。即,fun1指向一个返回int类型数据的函数。

1.1 两端有趣代码

//代码一
(*(void (*)())0)()
//解读:首先假设有一个数子:OX23FC11。如果仅是这个数字,我们可以认为他是一个地址,也可以是一个16进制数字
//同理,这里0也可以理解为一个地址,只是值比较特殊为0
//1.将0强制类型转换为void(*)()
//2.调用0处的函数

//代码二
void (*signal(int, void (*)(int)))(int);
//signal函数的一个声明
//1.signal函数有两个参数,第一个参数是int类型;第二个参数为int无返回值的函数指针类型
//2.signal函数的返回值是也是void(*)(int)函数指针类型,该函数指针指向的函数有一个int类型的参数,返回类型是void

代码二太复杂,如何简化呢?

typedef void(*pfun_t)(int)
pfun_t signal (int, pfun_t)

2. 函数指针数组

数组是一个存放相同类型数据的存储空间,我们已经介绍过指针数组,比如:

int *arr[10];
//数组的每个元素是int*

那要把函数的地址存放到一个数组中,那这个数组就叫函数指针数组。

那函数指针数组如何定义?

int (*parr1[10])();
//parr1先和[]结合,说明parr1是一个数组;数组的每个元素是int (*)()函数指针类型。

2.1 函数指针数组的用途之一:转移表

使用函数指针数组实现简单计算器:

#include <stdio.h>

int add(int a, int b)
{
  return a + b;
}
int sub(int a, int b)
{
  return a - b;
}
int mul(int a, int b)
{
  return a * b;
}
int div(int a, int b)
{
  return a / b;
}

int main()
{
  int input = 0;
  int (*p[5])(int x, int y) = { NULL, add, sub, mul, div };//转移表
  do
  {
    int x = 0; 
    int y = 0;
    int ret = 0;
    printf("XXXXXXXXXXXXXXXXXXXXXX\n");
    printf("XXXX 1.add  2.sub XXXX\n");
    printf("XXXX 3,mul  4.div XXXX\n");
    printf("XXXX 0.exit      XXXXX\n");
    printf("XXXXXXXXXXXXXXXXXXXXXX\n");

    printf("请选择:>\n");
    scanf("%d", &input);
    if (input >= 1 && input <= 4)
    {
      printf("输入操作数:");
      scanf("%d %d", &x, &y);
      ret = p[input](x, y);
      printf("%d\n", ret);
    }
    else
    {
      printf("输入错误,重新输入\n");
    }
  } while (input);
  return 0;
}

3. 指向函数指针数组的指针

指向函数指针数组的指针是一个指针,指针指向一个数组,数组的元素是数组指针。

如何定义?

void test(const char* str)
{
  printf("%s\n", str);
}
int main()
{
  //函数指针pfun
  void (*pfun)(char*) = test;
  //函数指针的数组pfunArr
  void (*pfunArr[5])(char*) = test;
  //指向函数指针的数组pfunArr的指针ppfunArr
  void (*(*pfunArr)[5])(char*) = test;
  return 0;
}
  • 不建议初学者直接上手写最终结果,而是根据上面过程一步步修改添加得到。

4. 回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是有函数的实现方直接调用,而是在特定的事件或条件发生时有另一方调用,用于对该事件或条件进行响应。

回调函数的应用

#include <stdio.h>
#include <stdlib.h>
//库函数中有一个函数qsort()是用来排序的
int cmp(const void* p1, const void* p2)
{
  //升序
  return *(int*)p1 - *(int*)p2;
  //降序
  //return *(int*)p2 - *(int*)p1;
}

int main()
{
  int arr[] = { 12,43,87,34,56,3,5,1,86 };
  int sz = sizeof(arr) / sizeof(arr[0]);
  qsort(arr, sz, sizeof(arr[0]), cmp);//通过指针调用cmp函数,所以cmp()函数为回调函数
  for (int i = 0; i < sz; i++)
  {
    printf("%d ", arr[i]);
  }
  return 0;
}

冒泡排序模拟实现qsort()函数

5. 结尾

本篇博客到此就结束了。创作不易,如果对你有帮助记得三连哦!感谢您的支持!!

指针进阶详解(上)

指针和数组笔试题解析


相关文章
|
6月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
6月前
|
机器学习/深度学习 搜索推荐 算法
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
|
6月前
|
C语言
指针进阶(回调函数)(C语言)
指针进阶(回调函数)(C语言)
|
6月前
|
存储 C语言 C++
指针进阶(函数指针)(C语言)
指针进阶(函数指针)(C语言)
|
6月前
|
编译器 C语言
指针进阶(数组指针 )(C语言)
指针进阶(数组指针 )(C语言)
|
6月前
|
搜索推荐
指针进阶(2)
指针进阶(2)
52 4
|
6月前
指针进阶(3)
指针进阶(3)
45 1
|
6月前
|
C++
指针进阶(1)
指针进阶(1)
47 1
|
6月前
|
存储 安全 编译器
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
51 2
|
7月前
|
C语言
C语言进阶:进阶指针(下)
C语言进阶:进阶指针(下)
51 2