前言:
上一期我们讲到了数组与指针的爱恨情仇,没看过的新朋友可以点击链接看一下,这一期我们将继续展开“它们”之间的故事,这个“它们”又是些谁呢,接下来就由我来为大家一一揭晓!
一、指针变量
指针变量大家应该都不陌生,如果初学的朋友们可以点击🔗深入探寻指针奥秘中有详细讲解,但是今天我们要为大家着重介绍几个指针变量。
1.1 字符指针变量(char*)
其实这是一个相对比较常见的指针类型,我们来看一段代码。
int main()
{
const char* pstr = "hello world";
printf("%s\n", pstr);
return 0;
}
请问字符串有放在pstr指针变量中吗? 这里很容易被错误认知为将字符串放入了字符指针pstr中了,其实本质是将字符串的首字符的地址放到了pstr中。
1.2数组指针变量
我们在深入探寻指针奥秘中有提到指针数组是一种数组,数组中存放的是地址(指针)。那数组指针变量是指针变量?还是数组?
当然是指针啦!
- 整型指针:int*pint;存放的是整型变量的地址,能指向整型数据的指针。
- 浮点型指针:float*pint;存放的是浮点型变量的地址,能指向浮点型数据的指针。
- 数组指针:就应该是存放数组的地址,能够指向数组的指针变量。
int *p1[10];
int (*p2)[10];
思考一下上面p1,p2分别是什么呢?
p先和*结合,说明p是一个指针变量,然后指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针(p2),[]的优先级高于*号,所以必须叫上()来保证p先和*结合。
我们来看一下数组指针的初始化,需要注意的是&arr是传的整个数组的地址。
int main()
{
int arr[10] = { 0 };
int(*p)[10] = &arr;
return 0;
}
1.2.1二维数组传参的本质
我们先来看一段二维数组给函数传参的代码:
void test(int a[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 ", a[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} };
test(arr, 3, 5);
return 0;
}
这里实参是二维数组,形参也写成二维数组,我们现在来讲一讲别的写法。根据我们对数组的了解,二维数组可以看作是每个元素是一维数组的数组,那么二维数组的首元素就是第一行,是个一维数组。那么根据这个规则,二维数组的数组名表示的就是第一行的地址,是一维数组的地址,那么二维数组传参本质上传递了地址,传递的是第一行这个一维数组的地址,既然如此我们的形参就可以写成指针形式。
void test(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} };
test(arr, 3, 5);
return 0;
}
就是这样,二维数组传参,形参部分可以写成数组也可以写成指针。
1.3函数指针变量
什么是函数指针变量呢?其实就是用来存放函数地址的,未来通过地址能够调用函数的。
void test()
{
printf("hello");
}
int main()
{
printf("test: %p\n", test);
printf("&test: %p\n", &test);
return 0;
}
我们来看看函数的地址会是怎么样的呢?
我们可以看到结果,其实函数地址和数组很像,函数名就是函数的地址。 我们来使用一下函数指针变量。
int Add(int x, int y)
{
return x + y;
}
int main()
{
int(*pf3)(int, int) = Add;
printf("%d\n", (*pf3)(2, 3));
printf("%d\n", pf3(3, 5));
return 0;
}
看看结果。
1.4函数指针数组
我们已经学习了指针数组,那要把函数的地址存在一个数组中,那这个数组就叫函数指针数组,那函数指针数组如何定义呢?
int (*parr1[3])();
int* parr2[3]();
int (*)()parr3[3];
这里面正确的定义只有第一行,parr1先和[]结合,说明parr1是数组,数组的内容是int (*)()类型的函数指针。
二、typedef关键字
我们来看看这个特殊的关键字,typedef是用来类型重命名的,可以将复杂的类型简单化。
typedef unsigned int uint;
//将unsigned int 重命名为 uint
比如上面这个代码的例子,如果可以用更简短的名字来代替。
如果是指针类型,能否重命名呢?
typedef int* ptr_t;
但是数组指针和函数指针稍微有些区别:
//数组指针类型
typedef int(*parr_t)[5];
//函数指针类型
typedef void(*pfun_t)(int);
值得注意的是新的类型名必须在*的右边
三、函数指针数组项目实现
我们通过本节所学,用函数指针数组来实现一个简单的转移表!
#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 x, y;
int input;
int temp;
int (*p[5])(int a, int b) = { 0,add,sub,mul,div };
printf("-------------菜单-------------\n");
printf("-------1.加法 2.减法-------\n");
printf("-------3.乘法 4.除法-------\n");
printf("------- 0.退出计算器 -------\n");
scanf("%d", &input);
if (input >= 1 && input <= 4)
{
printf("请输入您要进行运算的两位数字:\n");
scanf("%d %d", &x, &y);
temp = ((*p[input])(x,y));
printf("结果为:%d", temp);
}
else if (input == 0)
{
printf("退出");
}
else
{
printf("输入有误");
}
return 0;
}
本期内容匆匆结束啦,如果对您有帮助的话给博主点个赞吧。