目录
一、字符指针变量
在指针类型中,,有一种指针是字符指针
例:
char a = 'h';
char* p = &a;
同时,字符指针还有另一种用法
例:
const char* p = "hello world";
printf("%s", p);
代码运行结果:
看起来是把整个字符串存放在字符指针里,其实是把首字符 ' h ' 的地址存放在该字符指针里。
而且,与字符数组不同,这样的字符串是无法修改的,所以保存这样的字符串不需要申请额外的的内存空间,即只要这样保存的常量字符串,只要常量字符串相同,存放的地址是相同的
例:
const char* p1 = "hello world";
const char* p2 = "hello world";
printf("%p\n", p1);
printf("%p\n", p2);
代码运行结果:
二、数组指针变量
与指针数组不同,指针数组是存放指针的数组,而数组指针是指向数组的指针
例:
int a[10] = {0,1,2,3,4,5,6,7,8,9};
int (*p)[10] = &a;
| | |
| | p指向数组的元素个数
| p是数组指针变量名
p指向数组的元素类型
三、二维数组传参
因为数组名表示数组首元素地址,所以二维数组传参即把二维数组首个一维数组的地址传过去。
那么就同一维数组相同,二维数组传参也可以把形参写成指针形式
例:
#include<stdio.h>
void arr_printf_1(int (*p)[3],int x,int y)
{
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
printf("%d ", *(*(p + i) + j));
}
printf("\n");
}
}
void arr_printf_2(int arr[][3], int x, int y)
{
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int a[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
arr_printf_1(a,3,3);
printf("\n\n");
arr_printf_2(a,3,3);
return 0;
}
代码运行结果:
四、函数指针变量
既然有数组指针,那么也是有函数指针的,也就是函数也有地址
拿上面的代码为例:
#include<stdio.h>
void arr_printf_1(int (*p)[3],int x,int y)
{
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
printf("%d ", *(*(p + i) + j));
}
printf("\n");
}
}
int main()
{
int a[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
printf("&arr_printf_1: %p\n", &arr_printf_1);
return 0;
}
代码运行结果:
同时,就比如数组名是地址,函数名也是地址
例
printf("&arr_printf_1: %p\n",&arr_printf_1);
printf("arr_printf_1: %p\n", arr_printf_1);
代码运行结果:
函数指针:
void (*arr_p)(int (*p)[3],int x ,int y);
//或
void (*p)(int (*),int ,int );
| | ~~~~~~~~~~~~~~~~~~
| | |
| | 指向函数的参数类型和个数的交代
| 函数指针变量名
指向函数的返回类型
五、函数指针变量的使用
继续拿上面的代码为例:
//函数指针的初始化
void (*arr_p_1)(int(*p)[3], int x, int y) = arr_printf_1;
//或
void (*arr_p_2)(int(*)[3], int, int) = arr_printf_1;
函数指针的调用
arr_p_1(a, 3, 3);
printf("\n");
//或
(*arr_p_1)(a, 3, 3);
printf("\n");
arr_p_2(a, 3, 3);
printf("\n");
//或
(*arr_p_2)(a, 3, 3);
代码运行结果:
六、typedef关键字
typedef是⽤来类型重命名的,可以将复杂的类型,简单化。
1、将 " unsigned int " 重命名
typedef unsigned int ui;
那么定义 " unsigned int " 变量时就可以
ui a = 0;
2、指针类型重命名
typedef int* p_t;
使用:
p_t p = &a;
3、数组指针和函数指针重命名
与上面重命名有些不同
继续拿上面的代码为例:
//数组指针,新的类型名必须在*的右边
typedef int (*arr_p)[3];
//函数指针,新的类型名必须在*的右边
typedef void (*fc_p)(arr_p,int,int);
使用:
#include<stdio.h>
//数组指针,新的类型名必须在*的右边
typedef int(*arr_p)[3];
//函数指针,新的类型名必须在*的右边
typedef void (*fc_p)(arr_p, int, int);//
void arr_printf(arr_p p,int x,int y)
{
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
printf("%d ", *(*(p + i) + j));
}
printf("\n");
}
}
int main()
{
int a[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
fc_p arr_p = arr_printf;
arr_p(a, 3, 3);
printf("\n");
return 0;
}
代码运行结果:
七、函数指针数组
也就是把指针数组和函数指针结合一下
1、定义:
int (*arr_p[10])()
2、用途
转移表,例:计算器的⼀般实现
#include<stdio.h>
void menu()
{
printf("==============================\n");
printf("------------1.加--------------\n");
printf("------------2.减--------------\n");
printf("------------3.乘--------------\n");
printf("------------4.除--------------\n");
printf("------------0.退出------------\n");
printf("==============================\n");
}
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;
}
int main()
{
int choose = 0;
int (*calculator[5])(int, int) = { 0,add,sub,mul,div };
do
{
int x = 0, y = 0;
menu();
printf("请选择:");
scanf("%d", &choose);
if (choose)
{
printf("请输入:");
scanf("%d %d", &x, &y);
int ans = calculator[choose](x, y);
printf("%d\n", ans);
}
} while (choose);
return 0;
}