C语言指针详解(3)

目录

一、字符指针变量

二、数组指针变量 

三、二维数组传参的本质

四、函数指针变量

4.1、函数指针变量的创建

4.2、函数指针变量的使用 

4.3、typedef关键字 

五、函数指针数组

六、函数指针数组的使用


一、字符指针变量

我们知道,在指针类型中,有一种叫字符指针(char*)。它有两种使用方法:

使用方法一:

#include <stdio.h>
int main()
{
	char ch = 'a';
	char* pc = &ch;
	return 0;
}

 这种方法与定义int类型指针无异,先定义一个字符变量,再将该字符变量的地址存入指针中。

使用方法二:

#include <stdio.h>
int main()
{
	const char* pc = "abcdef";
	printf("%s\n", pc);
	return 0;
}

结果如下:

这种方法并不是把字符串放入了字符指针,而是把字符串的首字母的地址放入到了字符指针中。(注意:不要漏掉const)。

二、数组指针变量 

数组指针,就如同字符指针一样,是一种指针变量。它存放的是数组的地址,是一种能够指向数组的指针变量。

数组指针变量的定义及初始化如下:

#include <stdio.h>
int main()
{
	int arr[4] = { 1,2,3,4 };
	int (*p)[4] = &arr;//数组指针的定义及初始化
	return 0;
}

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

三、二维数组传参的本质

之前我们写一个二维数组传参给一个函数的时候,我们可以采用以下写法:

#include <stdio.h>
void func(int arr[3][5], int r, int c) {
	int i = 0;
	int j = 0;
	for (i = 0; i < r; i++) {
		for (j = 0; j < c; j++) {
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	func(arr, 3, 5);
	return 0;
}

其结果如下:

那么除了这种写法,我们是否还会有其他写法呢?答案是有的。首先,我们再深入理解一下二维数组就可以知道:二维数组可以看成是每个元素是一维数组的数组,那么二维数组的首元素就是第一行,是一个一维数组。所以,根据数组名是数组⾸元素的地址这个规则,二维数组的数组名表示的就是第一行的地址,是一维数组的地址。那就意味着⼆维数组传参本质上也是传递了地址,传递的是第一行这个⼀维数组的地址。由此,形参也可以写成指针形式。如下:

#include <stdio.h>
void func(int (*p)[5], int r, int c) {
	int i = 0;
	int j = 0;
	for (i = 0; i < r; i++) {
		for (j = 0; j < c; j++) {
			printf("%d ",*(*(p+i)+j));
		}
		printf("\n");
	}
}
int main()
{
	int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
	func(arr, 3, 5);
	return 0;
}

其结果与上述结果相同:

四、函数指针变量

4.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;
}

 其结果如下:

由此,我们可以看出,函数确实是存在地址的,并且函数名就是函数的地址,也可以使用&函数名来获取函数的地址。既然函数存在地址,那么函数指针变量也就有了用武之地。那么函数指针变量是何写法呢?请看以下代码:

#include <stdio.h>
int Add(int x,int y) {
	return x + y;
}
int main()
{
	int (*pf3)(int x, int y) = Add;//写法1
	int (*pf3)(int, int) = Add;//写法2
	return 0;
}

 由上述代码,我们可以知道,x和y是可以省略的。具体的函数指针类型解析如下:

4.2、函数指针变量的使用 

我们可以通过函数指针调用指针指向的函数:

#include <stdio.h>
int Add(int x,int y) {
	return x + y;
}
int main()
{
	int (*pf3)(int, int) = Add;
	printf("%d\n", pf3(3, 4));
	printf("%d\n", (*pf3)(3, 7));//两种写法均可
	return 0;
}

其结果如下:

4.3、typedef关键字 

typedef是⽤来类型重命名的,可以将复杂的类型简单化。

例1:

typedef unsigned int uint;
//将unsigned int简化为uint

 例2:重命名指针类型

typedef int* ptr_t;
//将int*重命名为ptr_t

例3:重命名数组指针

typedef int(*parr_t)[5]; //新的类型名必须在*的右边
//将int(*)[5]重命名为parr_t 

例4:重命名函数指针

typedef void(*pfun_t)(int);//新的类型名必须在*的右边 
//将void(*)(int)重命名为pfun_t

五、函数指针数组

把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组,那么函数指针数组该如何定义呢?例如:

int (*parr[5])();

 这就是函数指针数组的定义。parr先和 [] 结合,说明parr是数组,数组的内容是什么呢?是 int (*)() 类型的函数指针。

六、函数指针数组的使用

转移表:

#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  2.Sub*****\n");
	printf("****3.Mul  4.Div*****\n");
	printf("****   0.exit   *****\n");
	printf("*********************\n");
}
int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int (*prparr[5])(int, int) = { 0,Add,Sub,Mul,Div };
	do {
		menu();
		printf("请选择:");
		scanf("%d", &input);
		if (input >= 1 && input <= 4) {
			printf("请输入两个整数:");
			scanf("%d %d", &x, &y);
			int ret = prparr[input](x, y);
			printf("%d\n", ret);
		}
		else if (input == 0) {
			printf("退出计算机\n");
		}
		else {
			printf("输入错误,请重新选择\n");
		}
	} while (input);
	return 0;
}

上述是利用函数指针数组存储函数地址来实现计算器功能。

指针完...... 

  • 17
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值