第十一讲:指针(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;}elseprintf("输入的值非法,重新输入:");} while (input);return 0;
}