目录
一、字符指针变量
我们知道,在指针类型中,有一种叫字符指针(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;
}
上述是利用函数指针数组存储函数地址来实现计算器功能。
指针完......