目录
1 —— 字符指针
2 —— 指针数组-数组指针
3 —— 数组传参和指针传参
4 —— 函数指针
5 —— 函数指针数组
6 —— 指向函数指针数组的指针
7 —— 回调函数
前言
1.指针是个变量,用来存放地址,地址是指向一块内存空间。
2.指针的大小是(32位平台)4个字节(64位平台)8个字节。
3.指针拥有类型,指针的类型决定了指针加减大小的长度。
int main()
{
char ch = 'w';//创建一个char类型的ch变量存入字符w
char* pc = &ch;//把ch的地址放到char类型的*pc指针里面去
return 0;
}
int main()
{
char arr[] = "abcdef";//字符数组
char* pc = arr;//arr是数组名指向数组的地址放到指针*pc
printf("%s\n",arr);//结果为abcdef
printf("%s\n",pc);//结果为abcdef
return 0;
}
int main()
{
char* p = "abcdef";//"abcdef"是一个常量字符串赋给*p是把首字符a的地址赋给*p而不是整个字符串
printf("%c\n",*p);//结果为a
printf("%s\n",p);//结果为abcdef是从a的地址开始向后打印字符串
//"abcdef"为常量字符串,内容是不可被更改的
//*p = 'w';为错误导致程序崩溃Segmentation fault(段错误)
return 0;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcdef";//arr1,arr2地址不同指向的空间不同
char* p1 = "abcdef";
char* p2 = "abcdef";//p1,p2地址不同,但指向的空间相同都是"abcdef"改变p1并不影响p2
return 0;
}
int main()
{
int* parr[10];//是存放整形指针的数组,存放10个元素,每个元素是int*类型 - 指针数组
char* pch[10];//存放字符指针的数组,存放10个元素,每个元素是char*类型 - 指针数组
return 0;
}
指针数组的用法:
int main()
{
int a = 10;
int b = 20;
int c = 30;
int* parr[3] = { &a, &b, &c };
for (int i = 0; i<3; i++)
{
printf("%d\n", *(parr[i]));
}
//输入结果为10 20 30
int arr1[] = { 1, 2, 3, 4, 5 };
int arr2[] = { 2, 3, 4, 5, 6 };
int arr3[] = { 3, 4, 5, 6, 7 };
int* parr1[] = { arr1, arr2, arr3 };
for (int i = 0; i<3; i++)
{
for (int j = 0; j<5; j++)
{
printf("%d ", *(parr1[i] + j));
//parr1[i]是下标为i的数组+j是下标增加j//找到下标为i数组的第j个元素
}
printf("\n");//换行
}
//结果为1 2 3 4 5
// 2 3 4 5 6
// 3 4 5 6 7
return 0;
}
数组指针是一个指针,如char ch = 'w'; 而char* ps=&ch;是一个*ps的指针指向了ch的地址,而数组指针同理,是一个指针指向数组的。
int main()
{
int arr[10]={1,2,3,4,5,6,7,8,9,10};//是一个整形数组
int (*parr)[10] = &arr;//(*parr)是一个指针,指向了有[10]个元素的数组的地址每个元素是int
//把arr的地址用*parr指针来接收
return 0;
}
int main()//把一个指针数组存入数组指针
{
int* arr[5] = {0};
int* (*parr)[5] = &arr;//(*parr)是一个指针,指向一个数组有[5]个元素每个元素是int*类型
return 0;
}
注意:int arr[10]; 比如&arr表示数组的地址,不是首元素的地址。
数组的地址+1表示跳过整个数组的大小,所以&arr+1相对于&arr相差40
数组指针的用法:
void Show(int(*p)[5], int x, int y)//用数组指针传参*p是指针指向第一行数组有[5]个元素每个元素是int
{
for (int i = 0; i < x; i++)//打印一行
{
for (int j = 0; j < y; j++)//打印一行的第j的元素
{
printf("%d ", *(*(p + i)+j));//*(*(p+i)+j)难理解的话用p[i][j]效果一样
//*(p+i)是找到这一行+j是第j个元素地址在*号解引用找到第j个元素
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { { 1, 2, 3, 4, 5 }, { 2, 3, 4, 5, 6 }, { 3, 4, 5, 6, 7 } };//二维数组
Show(arr, 3, 5);
//自定义一个函数把二维数组的每行每列打印出来,arr是首元素地址代表第一个元素,就是第一行的地址
//二维数组的首元素地址就是第一行的地址
return 0;
}
void test(int arr[])//没问题
{}
void test(int arr[10])//没问题元素个数写不写都可以
{}
void test(int *arr)//没问题用地址来接受数组的地址写成指针也可以
{}
void test2(int *arr2[20])//没问题arr2和[20]先结合是数组每个元素是int*(元素个数可以省略)
{}
void test2(int* *arr)//没问题
{}
int main()
{
int arr[10];
int* arr2[10];
test(arr);
test2(arr2);
return 0;
}
二维数组传参
void test(int arr[3][5])//传过来一个数组用数组接受!!行[3]可以省略但是列[5]不能省列
{}
void test(int arr[][5])//省略行的写法
{}
void test(int (*arr)[5])//*arr是个指针指向了一个数组有五个元素每个元素是int这是指向一行的元素
{}
int main()
{
int arr[3][5]={0};
test(arr);
return 0;
}
指针传参
void test(int* p)//用指针接收
{}
int main()
{
int a=10;
int *p = &a;
test(p);//ok
test(&a);//ok
return 0;
}
二级指针传参
void test(int** ptr)//二级指针来接收
{}
int main()
{
int a=10;
int *p=&a;
int **ps=&p;
int* arr[10]={0};
test(ps);//ok
test(&p);//ok
test(arr);//ok
return 0;
}
int Add(int x,int y)
{
return x+y;
}
int main()
{
int a=10;
int b=20;
Add(a,b);//&Add和Add都是函数的地址
int(*pa)(int,int)=Add;
//*pa是个指向函数的指针(int,int)是函数的参数类型写成int x int y都可以返回类型是int
(*pa)(a,b);//函数指针的用法*pa是对pa解引用找到指向的函数传参数(a,b)和Add(a,b)结果一样
return 0;
}
无限套娃
(*(void (*)())0)();
//一步一步了解
//void (*)()//(*)是一个函数指针参数()无参返回类型是void ——函数指针
//然后(* () 0)()//0前面是个()里面放着一个函数指针就是把0强制类型转换成一个函数指针把0当成一个函数的地址0就是一个函数的地址
//然后*0就是对0进行解引用操作,使用0指向的这个函数最后一个()是函数的参数(无参)
void (*arr(int,void(*)(int)))(int);
//arr是一个函数名,后面(int,viod(*)(int))是参数一个是int一个是(*)是函数指针参数是(int)返回类型是viod
//然后void (*)(int)参数是int返回类型是void
//所以arr这是一个函数指针指向的函数返回类型是一个函数指针void (*)(int)
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(*p[4])(int, int) = { Add, Sub, Mul, Div };
//p先和[4]结合是个数组,int(*)(int,int)是元素类型每个元素是函数指针
//函数指针数组的用法:
int a = 10;
int b = 20;
for (int i = 0; i < 4; i++)
{
int c = p[i](a, b);//p[i]找到函数指针数组的第i个元素因为函数原来就是个地址不需要解引用然后(a,b)进行传参再用int c来接收返回值
printf("%d\n", c);//打印整数的结果为30 -10 200 0
}
return 0;
}
用函数指针数组写一个简单的计算器:
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("————————————————");
printf("——1.加法————2.减法————");
printf("——3.乘法————4.除法————");
printf("——0.退出———————————");
}
int main()
{
int input = 0;
int a = 0;
int b = 0;
menu();//打印一个计算器的菜单
do
{
printf("请输入:");
scanf("%d", &input);//选择函数
switch (input)//使用函数input为0则结束switch
{
case 1:
printf("请输入两个数进行操作:");
scanf("%d%d", &a, &b);
printf("%d ", Add(a, b));
break;
case 2:
printf("请输入两个数进行操作:");
scanf("%d%d", &a, &b);
printf("%d ", Sub(a, b));
break;
case 3:
printf("请输入两个数进行操作:");
scanf("%d%d", &a, &b);
printf("%d ", Mul(a, b));
break;
case 4:
printf("请输入两个数进行操作:");
scanf("%d%d", &a, &b);
printf("%d ", Div(a, b));
break;
case 0:
printf("退出计算器");
break;
default://默认输入不是switch里面的值为错误
printf("输入错误");
break;
}
} while (input);
return 0;
}
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(*parr[4])(int, int) = { Add, Sub, Mul, Div };//是一个数组-函数指针的数组,指向函数指针数组的指针是要有一个指针能够指向这个数组
int(*(*psarr)[4])(int, int) = &parr;//*psarr是一个指针,指向[4]数组有四个元素每个元素是int(*)(int,int)函数指针
return 0;
}
void Show(char* str)//Show函数的创建用来打印字符串
{
printf("%s\n", str);//将abcdef穿进来用指针str接收%s打印出字符串
}
void test(void (*ps)(char*))//参数是函数指针
{
ps("abcdef");//ps是个函数指针指向Show所以直接调用函数名(参数)即可
}
int main()
{
test(Show);//用test函数调用Show函数,Show是个地址用来找到函数本体
return 0;
}
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("————————————————");
printf("——1.加法————2.减法————");
printf("——3.乘法————4.除法————");
printf("——0.退出———————————");
}
void Calc(int(*ps)(int, int))//函数参数传一个函数指针
{
int x = 0;
int y = 0;
printf("请输入两个数进行操作:");
scanf("%d%d", &x, &y);
printf("%d ", ps(x, y));//调用函数指针指向的函数
}
int main()
{
int input = 0;
menu();//打印一个计算器的菜单
do
{
printf("请输入:");
scanf("%d", &input);//选择函数
switch (input)//使用函数input为0则结束switch
{
case 1:
Calc(Add);//使用回调函数来调用函数可以解决代码冗余的问题——方便多了
break;
case 2:
Calc(Sub);
break;
case 3:
Calc(Mul);
break;
case 4:
Calc(Div);
break;
case 0:
printf("退出计算器");
break;
default://默认输入不是switch里面的值为错误
printf("输入错误");
break;
}
} while (input);
return 0;
}