第十一讲:指针(3)
- 1.字符指针变量
- 1.1存储一个字符
- 1.2存储一个字符串
- 1.3一个有趣的面试题
- 2.数组指针变量
- 2.1什么是数组指针变量
- 2.2数组指针变量的初始化
- 3.二维数组传参的本质
- 4.函数指针变量
- 4.1介绍函数指针变量
- 4.2 两段有趣的代码
- 4.2.1代码1
- 4.2.2代码2
- 4.3typedef关键字
- 5.函数指针数组
- 6.转移表
- 6.1一般写法
- 6.2函数指针数组写法
1.字符指针变量
1.1存储一个字符
我们当然可以使用指针来存放一个字符变量,使用方法如下:
1.2存储一个字符串
那么如果我们用指针存放字符串会发生什么呢?
结论:
1.指针存放字符串时存放的时一个字符串首元素的地址
2.直接使用指针存放字符串时,这个字符串被称为常量字符串,此时字符串的值不能被改变
int main()
{
char* pa = "abcdef"; //此时abcdef就是一个常量字符串
//pa中存储的是首元素a的地址,证明如下:
printf("%c\n", *pa); //此时打印出的是a
//*pa = 'c'; 如果想要改变pa的值,程序会崩溃,但是并不会报错
//所以我们不如将上面的代码表示如下
const char* pb = "abcd";
//*pb = 0; 此时如果再想改变pb的值,程序就会报错
return 0;
}
1.3一个有趣的面试题
这个面试题的结果为:
原因如下:
str3和str4指向的是同一个常量字符串,常量字符串会存储再内存中的常量区,它的地址是确定的,而使用str1和str2初始化数组时,就会开辟不同的内存块
2.数组指针变量
2.1什么是数组指针变量
类比于
整形指针变量(int * pa),存放的时整形变量的地址,能够指向整形数据
浮点型指针变量(float * pb),存放的是浮点型变量的地址,指向浮点型数据
那么数组指针变量应该是:
存放的是数组的地址,能够指向数组的指针变量
指针变量的表示方法如下:
pa先和*进行结合,说明pa是一个指针变量,指向的是一个大小为5的数组。所以pa是一个指针,指向一个数组,称为数组指针
2.2数组指针变量的初始化
如果要存放个数组的地址,就得存放在数组指针变量中
数组指针解析:
3.二维数组传参的本质
结论:
二维数组传参,传入的是二维数组中首个一维数组的地址
我们用代码和图像来进一步理解二维数组传参的本质:
//二维数组传参的本质 (打印二维数组的每一个元素)
Print(int(*pa) [3], int r, int c) //二维数组传参的本质是传入了首个一维数组的地址,而首个一维数组的类型是int [3],
{ //所以接受的指针类型是int (*)[3]的类型
for (int i = 0; i < r; i++)
{
for (int j = 0; j < c; j++)
{
printf("%d ", (*(pa + i))[j]); //这里的(*(pa + i))[j]相当于*(*(pa+i)+j)相当于pa[i][j]
}
printf("\n");
}
}
int main()
{
int arr[2][3] = { {1,2,3}, {2,3,4} };
Print(arr, 2, 3);
return 0;
}
当然,二维数组进行传参时,也可以用二维数组来接受:
Print(int arr[2][3], int r, int c)
4.函数指针变量
4.1介绍函数指针变量
类比于数组指针变量(用来存放数组的地址),函数指针变量是用来存放函数的地址的,对于函数的地址的理解:
我们可以看出来,函数名其实就是函数的地址,Add == &Add,为了将函数的地址存下来,就要使用函数指针变量,使用方法如下:
//函数指针的使用
int Add(int x, int y)
{
return x + y;
}
int main()
{
int a = 2;
int b = 3;
//(int x, int y)中x和y写不写都可以
int (*Pa)(int, int) = Add; //将Add函数的地址存储在函数指针变量中,Add和&Add等价
printf("%d\n", Pa(a, b)); //在使用时,pa(a,b)和(*pa)(a,b)等价
return 0;
}
函数指针类型解析:
4.2 两段有趣的代码
4.2.1代码1
(*(void (*)())0)();
对于上述代码的解释如下:
4.2.2代码2
void (*signal(int , void(*)(int)))(int);
4.3typedef关键字
typedef是用来类型重命名的,可以将复杂的类型简单化,具体使用方法如下:
//typedef关键字
typedef unsigned int uint; //1.使用关键字定义普通类型的名称
typedef int* pa; //2.使用关键字定义指针类型的名称
typedef int(*ppa)[4]; //3.使用关键字定义数组指针的名称
typedef int(*pppa)(int, int); //4.使用关键字定义函数指针变量名称
int Add(int x, int y)
{
return x + y;
}
int main()
{
uint a = 3; //关键字的使用
printf("%d\n", a);
pa p_a = &a;
*p_a = 4;
printf("%d\n", a);
int arr[4] = { 1,2,3,4 };
ppa p_arr = &arr;
for (int i = 0; i < 4; i++)
{
printf("%d ", *((*p_arr) + i));
}
printf("\n");
pppa p_add = Add;
int ret = p_add(2, 3);
printf("%d", ret);
return 0;
}
那么此时我们就可以简化代码2,将其转换成:
void (*signal(int , void(*)(int)))(int);
typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);
5.函数指针数组
函数指针数组是存放函数指针的数组,那么函数指针数组如何使用呢?
//函数指针数组的使用
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pa[3])(int, int) = { Add };
int ret = pa[0](2, 3);
printf("%d", ret);
return 0;
}
6.转移表
函数指针的用途:转移表
举例:计算器的一般实现
6.1一般写法
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 = 1;
int ret = 0;
do
{
printf("*************************\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf(" 0:exit \n");
printf("*************************\n");
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = add(x, y);
printf("ret = %d\n", ret);
break;
case 2:
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = sub(x, y);
printf("ret = %d\n", ret);
break;
case 3:
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = mul(x, y);
printf("ret = %d\n", ret);
break;
case 4:
printf("输⼊操作数:");
scanf("%d %d", &x, &y);
ret = div(x, y);
printf("ret = %d\n", ret);
break;
case 0:
printf("退出程序\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}
显然,这个方法比较啰嗦,不好用
6.2函数指针数组写法
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 = 1;
int ret = 0;
int (*pa[5])(int, int) = { 0, add, sub, mul, div };
do
{
printf("*************************\n");
printf(" 1:add 2:sub \n");
printf(" 3:mul 4:div \n");
printf(" 0:exit \n");
printf("*************************\n");
printf("请选择:");
scanf("%d", &input);
if (input >= 1 && input <= 5)
{
printf("请输入两个操作数:");
scanf("%d %d", &x, &y);
int ret = pa[input](x, y);
printf("%d\n", ret);
}
else if (input == 0)
{
printf("退出程序!");
break;
}
else
printf("输入的值非法,重新输入:");
} while (input);
return 0;
}