C语言----指针(G3)1. 字符指针2. 指针数组3.数组指针4. 数组传参和指针传参5. 函数指针6. 函数指针数组7. 指向函数指针数组的指针8. 回调函数

C语言----指针(G3)1. 字符指针2. 指针数组3.数组指针4. 数组传参和指针传参5. 函数指针6. 函数指针数组7. 指向函数指针数组的指针8. 回调函数,第1张

回顾一下上节课

函数指针:


void test()
{
	printf("haha\n");
}

int main()
{

	printf("%p\n", test);
	printf("%p\n", &test);

	void(*pf)() = &test;//这个就是函数指针
	//void(*pf)() = test;//这样写也可以。

函数名就是地址。

test(); (*pf)();//通过pf调用test函数。

pf();//也可以这样写 这个*其实没有意义的。

//函数名就是地址 用地址写也可以。

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("*********************\n");
	printf("****1.Add  2.Sub ****\n");
	printf("****3.Mul  4.Div ****\n");
	printf("****0.exit       ****\n");
	printf("*********************\n");
	printf("*********************\n");
	printf("请输入序号\n");

}

int main()
{
	//在函数指针变量名后面加一个[]就是函数指针数组。

int(*pf[5])(int, int) = {0,Add,Sub,Mul,Div };//这个就是一个函数指针数组。

//返回值 参数类型 0就是空指针,也可以写NULL int n; do { menu(); //判断输入的合法性; while (scanf("%d", &n) != EOF) { if ((n > 4) && (n<0)) { printf("输入错误,请重新输入!!\n"); } if ((n <= 4) && (n >= 0)) { break; } } if (n == 0) { printf("退出计算器!\n"); break; } int x, y; printf("请输入运算的两个值:"); scanf("%d %d", &x, &y); int red = pf[n](x, y); printf("运算结果为:%d\n", red); } while (n); return 0; }



7. 指向函数指针数组的指针

就是一个指针 指向函数指针数组的指针

定义:


int main()
{
	int arr1[10] = { 1,2,3,4,5,6 };
	int(*p1)[10] = &arr1; //p是一个数组指针。

int* arr2[5]; //这个是指针数组 int* (*p2)[5] = &arr2; //类比 int (*pf)(int, int) = &Add; //这个是一个函数指针。

int (*pfarr[4])(int, int) = { Add,Sub,Mul,Div }; //函数名和&函数名都是函数的地址 都一样。

//这个是函数指针数组。

//现在我们要写一个 函数指针数组的指针。

//每个元素是函数指针。

// 类型为int (*)(int, int) //指针数组就是 类型 加 (*数组名)[n] int(*(*p3)[4])(int, int) = &pfarr; //p3是一个指针,指向函数指针数组的指针。

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(*p)(int, int) = Add;
	//p是函数指针变量
	int (*pfarr[4])(int, int) = { Add, Sub, Mul,Div };
	//pfarr是函数指针数组名

	int (*(*p3)[4])(int, int) = &pfarr;
	//p3指向函数指针数组的指针。

printf("%d",(*p3)[0](3, 4));//7 return 0; }



8. 回调函数

回调函数就是一个通过函数指针调用的函数。

如果你把函数的指针(地址)作为参数传递给另一个 函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

回调函数不是由该函数 的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进 行响应。

简单说就是:把A函数的指针,作为参数传递给B函数,在B函数内,通过A函数的指针来调用A函数时,我们就说这是一个回调函数。

简单的例子:


void test()
{
	printf("haha");

}

void print_haha(void(*p)())
{
	if (1)
	{
		p();
	}
}

int main()
{
	void (*pf)() = test;
	print_haha(pf);


	//结果为haha

	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("请输入选择:\n");
	printf("**********************************\n");
	printf("**********1.Add      2.Sub  ******\n");
	printf("**********3.Mul      4.Div  ******\n");
	printf("**********0.exit            ******\n");
	printf("**********************************\n");
	printf("**********************************\n");
}


//这个代码就是大大缩减了代码的冗余
void mmm(int (*p)(int, int))//这里用函数指针类型进行接收。

{ printf("请输入两个数字:\n"); int x, y; scanf("%d%d", &x, &y); printf("%d\n", p(x, y)); } //这里用到了回调函数 //在B函数通过地址来调用A函数 int main() { int input = 0; do { menu(); scanf("%d", &input); switch (input) { case 0: printf("退出计算器!!\n"); break; case 1: mmm(Add); break; case 2: mmm(Sub); break; case 3: mmm(Mul); break; case 4: mmm(Div); break; default: printf("输入错误!!!\n"); } } while (input); return 0; }

案例:

qsort函数:

qsort是一个库函数 ,基于快速排序算法实现的一个排序的函数。

这个qsort函数对任意类型的数据都可以进行排序。

功能很强大。

我们写的排序并不是任意数据都可以排序 ,只能排一类数据。

//
//	//qsort库函数有四个参数。

// void qsort(void* base, //待排序数据的起始位置,也就数组的首元素地址 // // size_t num,//数组的元素个数 // // size_t width, //一个元素的字节大小。

// // int(* com)(const void* elem1, const void* elem2)); com是比较函数, elem1和elem2是待比较的两个元素的地址。

#include #include //这里e1和e2是void*的指针,是一个无确切类型的指针,不能直接进行解引用的 //void* 是用来接收任意类型的指针的。

不能直接解引用和加减。

//可以先用()强制类型转换成某一类型的指针就可以使用了。

//而且被const修饰 int cmp(const void* e1, const void* e2) { 第一种方法。

//if (*(int*)e1 > *(int*)e2) //{ // return 1; //} //else if (*(int*)e1 == *(int*)e2) //{ // return 0; //} //else //{ // return -1; //} // //第二种方法 return (*(int*)e1 - *(int*)e2); //如果e1大于e2返回一个正数。

//如果e1大于e2返回一个正数。

//如果e1等于e2返回一个0。

} int main() { int arr[10] = { 9,8,7,6,5,4,3,2,1,0 }; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr, 10, sizeof(arr[0]), cmp); //打印结果 for (int i = 0; i < sz; i++) { printf("%d", arr[i]); } //结果为0123456789 return 0; }

运用qsort排序字符串。

//使用qsort排序结构体
struct stu
{
	char name;//名字
	int age;//年龄
	float score;//成绩
};

//按照年龄来排的
int cmp_stu_age(const void* e1, const void* e2)//这里的e1和e2是指向结构体的指针。

{ return (((struct stu*)e1)->age - ((struct stu*)e2)->age); } //按照名字来排的 int cmp_stu_name(const void* e1, const void* e2)//这里的e1和e2是指向结构体的指针。

{ return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name); } int main() { struct stu arr[3] = {{"liu",21,99.8} , {"guan",19,100.0}, {"zhang", 20,99.9} }; qsort(arr, 3, sizeof(arr[0]), cmp_stu_age); //这里就实现了按年龄从小到大排序 //可以通过监视窗口自己观看。

return 0; }

模拟实现qsort函数:

qsort函数有四个参数

1,数组的首地址

2,数组的大小

3,数组每个元素的字节大小

4,判断函数的地址

//模拟qsort函数
struct stu
{
	char name[10];
	int age;
	float scort;
};
//交换任意两个数据的函数实现
//这里不知道是什么类型的数据,但是我们传参的时候把元素所占的字节大小也传了过来
//这样就保证了,我们可以一个字节一个字节的进行交换。

void reverse(char* left, char* right,int width) { //单个字符交换。

for (int i = 0; i < width; i++) { char mid = *left; *left = *right; *right = mid; right++; left++; } } //注意这里的void*是为了保证能接收任何类型的函数 my_qsort(void* base, int sz, int width, int (*cmp)(void*, void*)) //注意int(*)(void*)(void*)函数指针类型 { //接收那个自定义的判断函数。

for (int i = 0; i < sz-1; i++)//这个是排序的趟数 { //每一趟具体情况 for (int j = 0; j < sz - 1 - i; j++) { //cmp函数是自己用qsort函数是写的判断函数要在这里使用 //默认返回大于0的数交换,默认升序 //并不知道base指向的类型,所以不能直接加j,要乘以宽度。

//它的两个参数,是两个元素的首地字节地址,但是void*不能直接加减。

//要先进行强制类型转换。

if (cmp((char*)base + j * width, (char*)base + (j + 1) * width)>0) //这个函数是qsort函数的第四个参数指向的函数 { //任意类型的交换函数,这里要用到每个元素的字节大小。

reverse((char*)base + j * width, (char*)base + (j + 1) * width,width); } } } } int cmp(const void* e1, const void* e2) { return *(int*)e1 - *(int*)e2; } int main() { int arr[4] = { 4,6,2,9 }; int sz = sizeof(arr) / sizeof(arr[0]); //第一个数组开头的地址, //第二个数组的元素个数 //每个元素的字节大小 //在自定义的判断函数,返回大于0他就交换。

my_qsort(arr, sz, sizeof(arr[0]), cmp); //默认升序。

for (int i = 0; i < sz; i++) { printf("%d", arr[i]); } return 0; }

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/langs/675129.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-04-19
下一篇2022-04-19

发表评论

登录后才能评论

评论列表(0条)

    保存