IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 从零开始C语言精讲篇8:指针进阶 -> 正文阅读

[C++知识库]从零开始C语言精讲篇8:指针进阶


前言

指针的主题,我们在初级阶段的《指针》章节已经接触过了,我们知道了指针的概念:

  1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。
  2. 指针的大小是固定的4/8个字节(32位平台/64位平台)。
  3. 指针是有类型,指针的类型决定了指针的±整数的步长,指针解引用操作的时候的权限。
  4. 指针的运算。

这个章节,我们继续探讨指针的高级主题。


提示:以下是本篇文章正文内容,下面案例可供参考

一、字符指针

常规使用

#include<stdio.h>
int main()
{
	char ch = 'w';
	char* pc = &ch;
	//用char*类型的pc来接收char类型ch的地址
	//pc指向一个字符变量ch
	return 0;
}

示意图如下:
在这里插入图片描述
特殊使用

#include<stdio.h>
int main()
{
	char* p = "hello bit";//ps:bit后面还默认有一个\0
	//char*类型一共4字节,所以这里并不是把整个hello bit\0放到p指针变量里去
	//真正的意思是:把常量字符串hello bit首字母h的地址赋给了p
	printf("%c\n", *p);//打印h
	printf("%s\n", p);//打印hello bit
	//%s是从提供的地址(这里是首字母h的地址)开始,往后找\0,找到\0打印结束
	return 0;
}

在这里插入图片描述

示意图如下:

在这里插入图片描述

注:"hello bit"这是一个常量字符串,而对于常量,我们是要求不能修改的,我们上述代码中是把h的地址给了P,那么通过*P是可以修改常量字符串内容的,一旦进行修改,系统就会报错。
所以,更加妥善的写法是const char * p = “hello bit”;

趁热打铁,我们来看一道字符指针的面试题:

#include <stdio.h>
int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    char *str3 = "hello bit.";
    char *str4 = "hello bit.";
    if(str1 ==str2)
 printf("str1 and str2 are same\n");
    else
 printf("str1 and str2 are not same\n");
       
    if(str3 ==str4)
 printf("str3 and str4 are same\n");
    else
 printf("str3 and str4 are not same\n");
       
    return 0;
}

在这里插入图片描述
解释1:
数组是独立开辟空间的,str1和str2分别是两个字符数组的数组名,数组名是数组首元素地址,str1和str2分别是两个不同数组首元素的地址,自然是不一样的。

在这里插入图片描述

解释2:
str3和str4都是const修饰的char*指针,这两个指针都指向一个常量字符串

而常量字符串又是不能修改的,也就是它的内容永远是"hello bit",那么我其他的指针也想来指向这个不可修改的"hello bit"时,为了节省内存,就没必要再创建一块额外空间了,还指向原来的那个即可。

所以这里str3和str4指向的是同一个地址
在这里插入图片描述

二、指针数组

指针数组是指针还是数组?
这个问题你就想,好男孩,好男孩的本质是男孩啊
指针数组本质还是数组

举个例子:

int main()
{
	int arr1[5];//整形数组,存放整形的数组就是整形数组
	char arr2[3];//字符数组,存放字符的数组就是字符数组

	//指针数组,存放指针的数组就是指针数组
	int* parr[5];//整形指针数组
	char* pbrr[4];//字符指针数组
	return 0;
}

示意图如下
在这里插入图片描述
应用实例1:

int main()
{
	int a = 123;
	int b = 213;
	int c = 312;
	int* arr[3] = { &a,&b,&c };

	for (int i = 0;i < 3;i++)
	{
		printf("%d\n", *arr[i]);
		//arr[i]是一个元素地址,*arr[i]对该地址解引用,得到地址指向的元素
	}
	return 0;
}

在这里插入图片描述

应用实例2:

#include<stdio.h>
int main()
{
	int arr1[] = { 1,2,3 };
	int arr2[] = { 4,5,6 };
	int arr3[] = { 7,8,9 };
	int* parr[] = { arr1,arr2,arr3 };//数组名是数组首元素地址,这里类型为int*
	for (int i = 0;i < 3;i++)
	{
		printf("%d\n", *parr[i]);
		//parr[i]是一个元素地址,*parr[i]对该地址解引用,得到地址指向的元素
	}
	return 0;
}

在这里插入图片描述
在这里插入图片描述

如果想得到三个数组的所有元素

#include <stdio.h>

int main()
{
	int arr1[] = { 1,2,3 };
	int arr2[] = { 4,5,6 };
	int arr3[] = { 7,8,9 };
	int* parr[] = { arr1,arr2,arr3 };//数组名是数组首元素地址,这里类型为int*
	for (int i = 0;i < 3;i++)
	{
		for(int j=0;j<3;j++)
		{
			printf("%d ", parr[i][j]);
			//举个例子:
			//parr[0]是arr1,
			//parr[0][1]就是arr1[1],即2
		}
		printf("\n");
	}
	return 0;
}

在这里插入图片描述
ps:还有一个老生常谈的话题:
arr[i]=*(arr+i),因为arr是数组名(一个地址)嘛,
arr+i就是这个地址往后i个单位,也就是arr[i]的地址,
对(arr+i)解引用,就可以得到arr[i]

应用实例3:

#include<stdio.h>
int main()
{
	const char* arr[5] = { "abc","defg","hijkl","mn","opqish" };
	//ps:每个常量字符串后面都默认有一个\0,比如“abc”其实存储的是abc\0
	int i = 0;
	for (i = 0;i < 5;i++)
	{
		printf("%s\n", arr[i]);//arr[i]是每个字符串首元素地址
	}
	return 0;
}

在这里插入图片描述

三、数组指针

3.1 数组指针定义

数组指针是数组还是指针?

还是那个判别方法:好男孩,性质是好,本质是男孩
所以,数组指针本质上是个指针

int *p1[10];//指针数组
int (*p2)[10];//数组指针

解释:p2先和 * 结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。
所以p2是一个指针,指向一个数组,叫数组指针。

这里要注意:[]的优先级要高于 * 号的,所以必须加上()来保证p先和*结合。

示例:

#include<stdio.h>
int main()
{
	int a = 10;
	int* pa = &a;//整形地址放整形指针中

	char c = 'w';
	char* pc = &c;//字符地址放字符指针中

	int arr[10] = { 0 };
	int* p = arr;//p是数组arr首元素的地址

	int(*parr)[10] = &arr;//数组地址放在数组指针中
	//简单判断类型的方法就是把变量名去掉,剩下的就是类型名
	//比如int a,把a去掉,剩下int就是a的类型
	//parr类型是int(*)[],
	return 0;
}

3.2 &数组名vs数组名

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	//arr     是首元素地址
	//&arr[0] 是首元素地址
	//&arr    是整个数组地址

	printf("%p\n", arr);//arr类型是int*
	printf("%p\n", &arr[0]);//&arr[0]类型是int*
	printf("%p\n", &arr);//&arr类型是int(*)[10]

	printf("=====我是分割线====\n");

	printf("%p\n", arr+1);
	printf("%p\n", &arr[0]+1);
	printf("%p\n", &arr+1);
	return 0;
}

在这里插入图片描述
综上,我们可以了解到,数组首元素地址和整个数组地址的区别:
他们在进行±操作时,跳过的单位是不同的,
前者是跳过一个数组元素大小,后者则是跳过整个数组的大小。

数组名不是数组首元素地址的两种特殊情况:

#include<stdio.h>
int main()
{
	//情况1
	//sizeof(数组名),这里数组名表示整个数组
	int arr[10] = { 0 };
	printf("%d\n", sizeof(arr));//打印40

	//情况2
	//&数组名,这里数组名表示整个数组,&arr取出的是整个数组的地址

	return 0;
}

3.3 数组指针的使用

引子:

#include<stdio.h>
int main()
{
	int* arr[10] = { 0 };
	//这里arr是一个指针数组
	//怎么判断?联想int  brr[10],这里brr是一个数组,里面存放10个int类型的元素
	//那么相应的, int* arr[10],这里arr是一个数组,里面存放10个int*类型的元素


	int* (*p)[10] = &arr;
	//arr是一个指针数组,&arr获得了指针数组的地址
	//如果想把这个地址赋给变量p
	//那么p的类型一定是一个指针,所以我们先用(*p),让p变成一个指针
	//而p这个指针指向的是一个大小为10的指针数组啊,所以外面套一层int* [10]
	//最终p的类型就是int* (*p)[10]

	int** p1 = arr;
	//arr是指针数组,
	//这里直接用arr表示数组首元素地址,也就是指针的地址,所以我们用int**
	
	return 0;
}

示例1:

#include <stdio.h>
void print(int(*parr)[10],int sz)
{
	int i = 0;
	for (i = 0;i < sz;i++)
	{
		printf("%d ", parr[0][i]);
		//把arr[10]看成一个二维数组,也就是1行10列的二维数组
		//那么*(parr+0)也就是arr
		//*(parr+0)==parr[0]
		//arr[i]==parr[0][i]

        //所以上面parr[0][i]写成(*(parr+0))[i]或者(*parr)[i]也是可以的
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	print(&arr,sz);
	return 0;
}

解释如下:
在这里插入图片描述

在这里插入图片描述

示例2:

void print(int(*p)[5],int r,int c)//r为行数,c为列数
{
	int i = 0;
	for (i = 0;i < r;i++)
	{
		int j = 0;
		for (j = 0;j < c;j++)
		{
			printf("%d ", (*(p + i))[j]);
			//也可写printf("%d ", *(*(p + i) + j));
			//也可写printf("%d ", p[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };
	//二维数组行可省略,列不可省略
	print(arr, 3, 5);
	//二维数组的数组名作为参数,传的是第一行一维数组的地址,也就是arr[0][5]的地址
	return 0;
}

解释如下:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

学了指针数组和数组指针我们来一起回顾并看看下面代码的意思:

//注:[]优先级比*高
int arr[5];//整型数组
int *parr1[10];//指针数组
int (*parr2)[10];//数组指针
int (*parr3[10])[5];

对于parr3,它首先是和[10]结合,我们就可以确定它本质是一个10元素的数组
然后把int ( * parr3[10] )[5]中的parr3[10]去掉就可以得到int ( * )[5],
也就是数组元素为数组指针,这种指针指向数组有5个元素,每个元素为int型

示意图如下:
在这里插入图片描述

四、数组参数、指针参数

在写代码的时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?

4.1一维数组传参

void test(int arr[])//数组传参,数组接收,没有任何问题
{}

void test(int arr[10])//10个大小的接收10个大小的数组,也没有问题
{}
//其实这里arr[]里面放100,1000都没问题,只不过看起来有点别扭,
//主流写法还是int arr[]来接收

void test(int *arr)
{}
//我们之前说过,数组名作为参数表示数组首元素地址,所以这里int*接收没问题

void test2(int *arr[20])
{}
//这个参数和int* arr[]是一个效果,因为是整形指针数组作为参数,
//那么我们用同样的整形指针数组来接收也没有问题

void test2(int **arr)
{}
//整形指针数组首元素是整形指针,而数组名又表示首元素地址,
//也就是整形指针的指针,这样写也没问题

int main()
{
	int arr[10] = { 0 };
	int *arr2[20] = { 0 };
	test(arr);
	test2(arr2);
	return 0;
}

4.2二维数组传参

热知识:二维数组首元素指的是该二维数组的第一行

void test(int arr[3][5])
{}
//3*5的数组传参过去,3*5的数组来接收,没有任何问题

void test(int arr[][5])
{}
//这种写法和一维数组[]里面放不放数字一样,
//但是二维数组,函数形参的设计只能省略行,不能省略列
//举个例子,我现在有15个元素,我知道是3列,可以算出来,行就是15/3=5个
//但是如果知道是3行,妈的,你一行可以放15个,也可以一行只放1个,谁知道你要放多少列?


void test(int(*arr)[5])
{}
//数组名作为参数,传的是首元素地址。
//对于二维数组来说,数组首元素是第一行的地址,
//我们这里是3*5的整形数组,那么它的第一行就是1*5的整形数组
//我们用整形数组指针来接收


int main()
{
	int arr[3][5] = { 0 };
	test(arr);
}

4.3一级指针传参

#include <stdio.h>
void print(int *p, int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9 };
	int *p = arr;
	int sz = sizeof(arr) / sizeof(arr[0]);
	//一级指针p,传给函数
	print(p, sz);
	return 0;
}

在这里插入图片描述

4.4二级指针传参

#include <stdio.h>
void test(int** ptr)
{
	printf("num = %d\n", **ptr);
}
int main()
{
	int n = 10;
	int*p = &n;
	int **pp = &p;//pp为二级指针
	test(pp);
	test(&p);//如果接收方是二级指针,我们传一级指针地址也可以
	return 0;
}

在这里插入图片描述

五、函数指针

5.1引子

示例:我们常常接触的指针大多有如下几类:
整形指针-存放整形地址,指向整形
字符指针-存放字符地址,指向字符
数组指针-存放数组地址(注意不是数组首元素地址),指向数组

由以上三个例子,我们能总结指针的共同点:存放某个类型变量的地址,指向那个类型的变量,但是在讲函数指针首先有一个问题:函数也有地址吗?我们用一段简单的代码来验证一下即可。

#include<stdio.h>
int Add(int x,int y)
{
   return x+y;
}
int main()
{
   printf("%p\n",&Add);
   return 0;
}

屏幕上打印出地址:
在这里插入图片描述

所以答案是有的,函数也存在地址,也就衍生出了今天的知识点-函数指针。

5.2使用步骤

5.2.1取函数地址

我们知道&数组名,取出的是数组的地址。单独一个数组名,取出的是数组首元素的地址。但是对于函数来说:函数名==&函数名

我们代码验证一下(示例):

#include<stdio.h>
int Add(int x,int y)
{
   return x+y;
}
int main()
{
   printf("%p\n",&Add);
   printf("%p\n",Add);
   return 0;
}

在这里插入图片描述
显然,打印出来的地址是一样的,但是这个时候也会有同学跳出来说:“那数组名和&数组名打印出来的地址还一样呢,但意义明显不一样啊”。但是你想想,函数也没有首元素等其他玩意啊,它就是它本身啊,它也不会出现什么函数首元素啊。

所以再次声明:
在函数指针这一块 函数名==&函数名,它的意义和值,都是一样的

5.2.2创建函数指针

我们知道,数组指针用来存放数组地址,整形指针用来存放整形地址。。。函数指针也不例外,它用来存放函数地址,我们现在定义一个p来存放Add地址,那它的类型怎么创建?我们来看一下具体步骤:

1.p是一个指针对吧,给它一个*是不是必须的 p变成了 * p。为了确保 * 和 p结合(如果没有括号,*或者p有可能会与其他的一些符号结合,具体参见符号优先级)那我在 * p外面加一个括号便于观看也没有问题吧,也就是(*p)

2.那函数总得有参数啊,比如这里是Add(int x,int y)。参数x和y的类型是int
你指针指向的函数是不是要找一下它的参数。所以(*p)(int,int)

3.那函数还有一个性质啊,有没有返回值,要是有的话,类型呢? 这里以Add为例,它是返回int型,所以我们指针也返回int 型 即int(*p)(int,int)

到这里Add函数指针的类型就创建完成啦即为*int(p)(int ,int)

需要注意的是:不同函数的参数类型和返回值类型是不一样的,到时候需要根据不同函数对类型进行转换,这里只是以Add函数为例,其他函数以此类推

ps:一个快速判别类型的方法——去掉变量的名字,剩下的就是类型
代码如下(示例):

	int a = 10;//去掉a 类型int
	int arr[10] = { 0 };//去掉arr 类型int [10]
	int(*parr)[10] = &arr;//去掉parr 类型int(*)[10],数组指针,指向一个10int型元素的数组
	int(*pf)(int, int) = &Add;//去掉pf 类型int(*)(int,int)

5.2.3通过函数指针调用函数的两种方法

法一:
我们平时在调用函数的时候,一般就是函数名( ,)然后把参数传进括号即可,那我们现在有函数指针了呀,指针怎么使用?

p不是指向了函数Add嘛,我们用*解引用指针,得到的是地址里的东西,

也就是说 *p==Add,用 * p(,)来传参也可以实现Add函数的调用。
代码如下:

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int ret = Add(2, 3);
	printf("%d\n", ret);//ret=5
	int(*p)(int, int) = &Add;//p是一个指向函数Add的指针
	ret = (*p)(3, 3);//ret=6
	//p指向Add,对p解引用就是Add
	//简言之:*p=Add
	//我们并不总是可以拿到变量,有时是拿到变量的地址
	//对应函数指针同样的道理,有时不直接给你函数,给你函数地址,就这样调用
	printf("%d\n", ret);
}

在这里插入图片描述

法二:
我们在二.1取函数地址那一块介绍了,在函数指针这一块,函数名==&函数名, 也就是说创建函数指针的时候可以这样写:int(*p)(int, int) = Add,Add是赋给了p啊,你也可以认为:p就是Add。

你可以这样理解,法一是int(*p)(int, int) = &Add,是把Add的地址给p,所以用p来调用函数要解引用一下,但是法二p就是Add,那不用解引用了,直接调用。代码如下:

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int main()
{
	//我们由前面的知识知道:函数add取地址时,add=&add
	int(*p)(int, int) = Add;//把Add赋给p,这里p即可看做Add
	//与法一不同的是,法一将&Add赋给p,p是Add的地址,
	//所以要解引用,这里p就可以看做是Add本身,可以不解引用
	int ret = p(3, 6);
	printf("%d", ret);
}//如果是为了方便理解,一般是用第一种方法,
//如果是为了操作方便,可以用第二种方法

在这里插入图片描述

5.3函数指针进阶

大家来看这样一个代码

( * (void(*)() ) 0)()

乍一看非常复杂,我们来细化一下

1 . ( * (void( * )() ) 0)() 我们抽出加粗部分
这是我们熟悉的老朋友:void( * )(),这不就是一个函数指针嘛,该函数无参,返回类型void

2 . (void( * )() ) 0是什么?我们联想一下(int)3.14,不就是对3.14强制类型转换嘛,将3.14这个浮点型强制转换成整形。这里同样的道理,是将整形0强制转换成类型为void( * )()的一个函数指针

3 .现在有了(void( * )() ) 0,我们在这个东西前面加一个 *,这个是什么意思,我们知道(void( * )() ) 0已经被转换成一个指针(指针即地址)了,地址前面加一个 *表示解引用,取出地址里的东西,也就是找到了那个函数

4 . (void( * )() ) 0表示那个函数那再在后面加一个()即是对函数的调用,也就是( * (void(*)() ) 0)()

六、函数指针数组

6.1引子

示例:以下这个代码,我们可以很清楚的看出,arr是一个整形指针数组,数组里的每个元素均为整形指针

int *arr[10];

那我们就会有接下来的两个问题:
整形指针能放入到一个数组内,
那么参数、返回类型相同的*函数指针能否也可以放入一个数组内?
如果可以,我们应该如何创建那个数组呢?

6.2使用步骤

6.2.1创建函数指针数组

先上代码(示例):

#include<stdio.h>
int Add(int x, int y)
{
	return x + y;
}
int Sub(int x, int y)
{
	return x - y;
}
int main()
{
	int(*p1)(int, int) = Add;//Add和Sub的函数指针类型为int(*)(int,int)
	int(*p2)(int, int) = Sub;
	int(*parr[2])(int,int)={Add,Sub};
}

由以上代码,我们不难看出,函数Add和函数Sub除了名字和功能不同,它们的参数和返回类型均相同,我们可以写出它们共同的函数指针类型(详情见上一期的C语言快速入门):int(*)(int,int) ,也就是说,只要我们由Add和Sub两个函数的地址,我们都可以放到int( * )(int,int)这个类型中去

那么Add和Sub这两个函数指针数组类型怎么创建?我们举两个简单的例子:

int a;//将变量名a删去就是类型 int也就是整形
int arr[10];//将变量名arr删去就是类型 int [10]也就是整形数组

整形和整形数组类型的差别也就是多了一个[ ]这样的东西

这里找函数指针数组类型的创建法也是同样的道理,
我们仍以Add函数为例,已知了Add函数指针类型为int( * )(int,int),我们在 * 后跟一个[ ]即可

也就是如下代码,初始化和别的数组初始化没有什么区别,
我们正常把函数Add和Sub放入(函数名==&函数名,详情见上一期函数指针)

int(*parr[2])(int,int)={Add,Sub};//这里初始化放入的是函数的地址
//parr就是一个函数指针数组

6.2.2函数指针数组的实际使用案例

比如我们这里写一个加减乘除的简易计算器
代码如下(示例):
Add Sub Mul Div分别代表加减乘除

#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;
}
void menu()
{
	printf("*************\n");
	printf("***1.Add  ***\n");
	printf("***2.Sub  ***\n");
	printf("***3.Mul  ***\n");
	printf("***4.Div  ***\n");
	printf("***0.exit ***\n");
}
int main()
{
	int input = 0;
	do
	{
		int x = 0;
		int y = 0;
		int z = 0;
		menu();
		printf("请选择:");
		scanf("%d", &input);
		int(*parr[5])(int, int) = { 0,Add,Sub,Mul,Div };
		//这里为什么要加0,是为了让数组中Add到Div下标分别是1到4,对应计算器菜单中的选项
		if (input == 0)
		{
			printf("退出计算器\n");
		}
		else if (input >= 1 && input <= 4)
		{
			printf("请输入2个操作数\n");
			scanf("%d %d", &x, &y);
			z=parr[input](x,y);
			//parr是存放函数指针的数组,有了下标也就有了某个函数指针(也就是函数地址)
			//我们在函数指针那一块讲解过:调用函数的时候可以直接用函数地址调用
			printf("计算结果为%d\n", z);
		}
		else
		{
			printf("输入错误,请重新输入\n");
		}
	} while (input);
	return 0;
}

使用示例:
在这里插入图片描述

该段代码有以下一些注意点
1.在写函数指针数组时,因为下标的缘故,菜单中的选项和实际存放的函数指针是不匹配的,我们可以在Add前加一个0(该0本身是无意义的)将下标依次加1个

2.parr是存放函数指针的数组,有了下标也就有了某个函数指针(也就是函数地址)我们在函数指针那一块讲解过:&Add=Add,调用函数的时候可以直接用函数地址调用(详情见上一期C语言快速入门)

这里用函数指针数组写的好处是什么?
在日常的工作中,我们如果要写一个需要用到很多函数的程序,而这个程序将来也极其有可能增加新的或删减旧的函数。传统的更改方式,一旦不小心,可能会损伤到其他正常的代码,导致满盘皆输。如果用函数指针数组,我们只需要对函数指针数组大小变换一下,再将新的或旧的在函数指针数组初始化中修改一下即可,而在函数调用方面也不需进行更改,非常非常非常的方便。

七、指向函数指针数组的指针

这里开始就出现无限套娃了,其实方法都是一样的。
这里我们只展示如何定义,函数指针数组的指针也就是函数指针数组取地址

int add(int x, int y)
{
	return x + y;
}
int (*pf)(int, int) = add;//pf是函数指针

int (*pfArr[5])(int, int);//pfArr是一个函数指针的数组

int(*(*ppfArr)[5])(int, int) = &pfArr;//ppfArr是一个指向函数指针数组的指针

八、回调函数

回调函数就是一个通过函数指针调用的函数。

如果你把函数的指针(地址)作为参数传递给另一个函数,
当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

九、指针和数组笔试题详解

题库整理1

题库整理2

题库整理3


总结

本文着重介绍了指针数组、数组指针、函数指针、函数指针数组等知识点。指针作为C语言学习的大头,需要读者们认真细致的学习,而一些指针/或者数组的套娃定义也是其中的难点,建议读者们在学习完本文后,认真练习本文中第九节的笔试题,借此提升自己对指针的理解。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-08 20:22:11  更:2022-10-08 20:23:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 4:37:24-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码