上期我们讲过了数组指针传参,在一维数组传参和二维数组传参,今天我们来看看其他的进阶指针。
1.指针数组
概念:本质上是数组,数组中存放的是指针。
int* pa;
int* pb;
int* pc;
int* arr[] = { pa,pb,pc };
这里定义了三个指针,将三个指针存放到了数组里,那么这个数组就是指针数组。
2.函数指针
概念:指向函数的指针。
#include<stdio.h>
int main()
{//函数指针:函数的地址放到指针变量中
int (*pf)(int, int) = &Add; //int (*pf)(int,int) = Add
int temp = (*pf)(2, 3); //int temp = (pf)(2,3)
printf("%d\n", temp);
return 0;
}
#include<stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
//int arr[5] = { 0 };
//&数组名 - 取出的数组的地址
//int(*p)[5] = &arr; //数组指针
//&函数名和函数名 - 取出的就是函数的地址
printf("%p\n", &Add);
printf("%p\n", Add);
int(*pf)(int , int ) = &Add;
int ret = (*pf)(3, 5); //可以加解引用
int rat = pf(3, 6); //不加解引用效果和加了一样
printf("%d\n", ret);
printf("%d\n", rat);
return 0;
}
通过上述代码我们可以看到,我们先写一个加法函数Add,把Add这个函数放到函数指针里,函数指针的类型就是 类型(*名字)(类型,类型) 这里的加法是整数加减,指针就是int(*pf)(int,int),然后将已经写好的函数指针由一个变量接收,最后通过这个变量输出。
//可以换一种简单的代码了解一下
#include<stdio.h>
int Add(int x, int y)
//先创建一个加法函数
{
return x + y;
}
void calc(int(*pf)(int, int))
//最后用*pf来接收(int,int)类型的函数
{
int a = 10;
int b = 20;
int ret = pf(a, b);
//直接使用
printf("%d\n", ret);
}
int main()
{
calc(Add);
//然后把这个函数的地址传给calc函数
return 0;
}
这个函数就是改过的函数;现在对函数指针有一些理解,我们可以用函数指针写一个简易的计算器。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
//函数指针的用途
//函数指针写一个模拟简易计算器
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 mune()
{
printf("*******************************\n");
printf("****** 1.add 2.sub ******\n");
printf("****** 3.mul 4.div ******\n");
printf("****** 0.exit ******\n");
printf("*******************************\n");
}
void cola(int(*py)(int, int))
{
int x = 0;
int y = 0;
printf("please two numbers:>");
scanf("%d %d", &x, &y);
int ret = (*py)(x, y);
printf("%d\n", ret);
}
int main()
{
int input = 0;
do
{
mune();
printf("please a number:>");
scanf("%d", &input);
switch(input)
{
case 1:
cola(add);
break;
case 2:
cola(sub);
break;
case 3:
cola(mul);
break;
case 4:
cola(div);
break;
case 0:
printf("退出计算器\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}
3.函数指针数组
概念:函数指针数组是一个数组,他的每一个函数指针。 函数指针是指向函数的指针变量,可以用来调用相应的函数,函数指针数组的作用是可以根据需要动态地选择并调用不同二掉函数。
由于上面的计算器不够简便,继续改造一下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
void touwen()
{
printf("*****************************\n");
printf("***** 1.ADD 2.SUB ******\n");
printf("***** 3.MUL 4.DIV ******\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()
{
touwen();
int input = 0;
int ret = 0;
//指针数组函数
//转移表
int(*pfarr[5])(int, int) = { 0,Add,Sub,Mul,Div };
do
{
printf("please choose: ");
scanf("%d", &input);
if (input == 0)
{
printf("退出计算器\n");
}
else if (input >= 1 && input <= 4)
{
int a = 0;
int b = 0;
printf("please input two numbers: ");
scanf("%d %d", &a, &b);
ret = (*pfarr[input])(a, b);
printf("%d\n", ret);
}
else
{
printf("choose error");
}
} while (input);
return 0;
通过对函数指针的了解,在函数指针上改变,类型(*类型)(类型,类型),改成函数指针数组,(类型)(*类型[])(类型,类型);
4.回调函数
回调函数是一种特殊的函数,它作为参数传递给另一个函数,并在被调用函数执行完毕后被调用。回调函数通常用于事件处理、异步编程和处理各种操作系统和框架的API。
基本概念:
1.回调:指被传入到另一个函数的函数。
2.异步编程:指在代码执行时不会阻塞程序运行的方式。
3.事件驱动:指程序的执行是由外部事件触发而不是顺序执行的方式。
(1)普通冒泡排序
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//普通冒泡排序
void sort(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz - 1; i++)
{
int flag = 1;
int j = 0;
for (j = 0; j < sz - 1 - i; j++)
{
if (arr[j] < arr[j + 1])
{
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
flag = 0;
}
}
if (flag == 1)
{
break;
}
}
}
void print1(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[] = {9,8,7,6,5,4,3,2,1,0};
int sz = sizeof(arr) / sizeof(arr[0]);
//普通冒泡排序
//sort(arr, sz);
print1(arr, sz);
return 0;
}
(2)库函数冒泡排序
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*)) 对数组进行排序 |
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//qsort库函数
bubble_cmp(const void* e1, const void* e2)
{
return (*(int*)e2 - *(int*)e1);
}
void print1(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[] = {9,8,7,6,5,4,3,2,1,0};
int sz = sizeof(arr) / sizeof(arr[0]);
//c数据库qsort函数
//qsort(arr, sz, sizeof(arr[0]), bubble_cmp);
print1(arr, sz);
return 0;
}
(3)自定义库函数实现排序链表
void bubble_qsort(void* best,size_t sz,size_t width,(*cmp)(const void* e1,const void* e2));
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//自定义qsort函数
bubble_cmp(const void* e1, const void* e2)
{
return (*(int*)e2 - *(int*)e1);
}
void Swap(char* best1, char* best2, int width)
{
int i = 0;
for (i = 0; i < width; i++)
{
char temp = *best1;
*best1 = *best2;
*best2 = temp;
best1++;
best2++;
}
}
void bubble_qsort(void* Best, int sz, int width, int(*cmp)(const void* e1, const void* e2))
{
int i = 0;
//趟数
for (i = 0; i < sz - 1; i++)
{
int flag = 1; //假设冒泡排序排好序
int j = 0; //一趟冒泡排序的过程
for (j = 0; j < sz - 1 - i; j++)
{
//cmp的参数是用来比较两个参数的地址
if (cmp((char*)Best + j * width, (char*)Best + (j + 1) * width) > 0)
{
//交换
Swap((char*)Best + j * width, (char*)Best + (j + 1) * width,width);
flag = 0;
}
}
if (flag == 1)
{
break;
}
}
}
void print1(int arr[], int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[] = {9,8,7,6,5,4,3,2,1,0};
int sz = sizeof(arr) / sizeof(arr[0]);
//自定义qsort链接函数
bubble_qsort(arr, sz, sizeof(arr[0]), bubble_cmp);
print1(arr, sz);
return 0;
}