回调函数
回调函数就是一个通过函数指针调用的函数
如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数
时,被调用的函数就是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条
件发生时由另外的一方调用的,用于对该事件或条件进行响应
举个例子:
//使⽤回调函数改造前 #include <stdio.h> 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("******************) printf(" 1:add,2:sub\n) printf(" 3:mul,4:div\n) printf("******************) 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", r 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; }
//使⽤回到函数改造后 #include <stdio.h> 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; } void calc(int(*pf)(int, int)) { int ret = 0; int x, y; printf("输⼊操作数:"); scanf("%d %d", &x, &y); ret = pf(x, y); printf("ret = %d\n", ret); } int main() { int input = 1; do { printf("******************) printf(" 1:add,2:sub\n) printf(" 3:mul,4:div\n) printf("******************) printf("请选择:"); scanf("%d", &input); switch (input) { case 1: calc(add); break; case 2: calc(sub); break; case 3: calc(mul); break; case 4: calc(div); break; case 0: printf("退出程序\n"); break; default: printf("选择错误\n"); break; } } while (input); return 0; }
qsort使用举例
#include <stdio.h> //qosrt函数的使⽤者得实现⼀个⽐较函数 int int_cmp(const void * p1, const void * p2) /*void*p为任意类型的指针, 因为创造这个函数的人不知道使用者会传入什么类型的指针, 因此用viod类型的指针就可以解决这个问题*/ { return (*( int *)p1 - *(int *) p2); /*返回值是用两个指针变量进行相减,其中int*为强制类型转换,将p1和p2强制转换为整形类型的指针,再通过解引用判断大小*/ } int main() { int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 }; int i = 0; qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp); /*qsort函数需要数组的首元素地址,还有多少个元素,一个数组元素有多少字节,比较大小的函数*/ /*因为需要比较两元素的大小,然后进行排序,所以需要一个比较大小的元素*/ for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++) { printf( "%d ", arr[i]); } printf("\n"); return 0; }
qsort函数的模拟实现
使用回调函数,模拟实现qsort(采用冒泡的方式)
#include <stdio.h> //比较大小的函数 int int_cmp(const void* p1, const void* p2) { return (*(int*)p1 - *(int*)p2); } //交换的函数 void _swap(void* p1, void* p2, int size) { int i = 0; for (i = 0; i < size; i++) { char tmp = *((char*)p1 + i); *((char*)p1 + i) = *((char*)p2 + i); *((char*)p2 + i) = tmp; //*((char*)p1 + i)就是数组的元素一点i个字节,因为是强制类型转换为char*类型的指针,又由于char*类型的指针大小为一个字节,所以移动i个字节就是移动i个数组元素 } } //模拟实现的qsort函数 void bubble(void* base, int count, int size, int(*cmp)(void*, void*)) { int i = 0; int j = 0; for (i = 0; i < count - 1; i++) { for (j = 0; j < count - i - 1; j++) { if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0) //判断指针大小是否大于0,如果大于0就会交换 { _swap((char*)base + j * size, (char*)base + (j + 1) * size, size); } } } } int main() { int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 }; //char *arr[] = {"aaaa","dddd","cccc","bbbb"}; int i = 0; bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp); for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++) { printf("%d ", arr[i]); } printf("\n"); return 0; }
sizeof和strlen的对比
sizeof
在学习操作符的时候,我们学习了 sizeof , sizeof 计算变量所占内存内存空间大小的,单位是字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。
sizeof 只关注占用内存空间的大小,不在乎内存中存放什么数据比如:
#inculde <stdio.h> int main() { int a = 10; printf("%d\n", sizeof(a)); printf("%d\n", sizeof a); printf("%d\n", sizeof(int)); return 0; }
strlen
strlen 是C语言库函数,功能是求字符串长度。函数原型如下:
size_t strlen ( const char * str ); 这里随便说一下size_t是无符号整形类型
统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。
strlen 函数会一直向后找 \0 字符,直到找到为止,所以可能存在越界查找(找不到\0)
#include <stdio.h> int main() { char arr1[3] = {'a', 'b', 'c'}; char arr2[] = "abc"; printf("%d\n", strlen(arr1)); /*strlen(arr1)就是越界查找的典型例子 因为数组里都是字符,并没找到\0 因此就会越界查找,甚至找不到*/ printf("%d\n", strlen(arr2)); /*每个字符串末尾都有\0, 因此strlen的大小就是abc中有多少个字符*/ printf("%d\n", sizeof(arr1)); printf("%d\n", sizeof(arr1)); return 0; }
sizeof和strlen的对比
sizeof
- sizeof是操作符
- sizeof计算操作数所占内
存的大小,单位是字节 - 不关注内存中存放什么数
据
strlen
- strlen是库函数,使用需要包含头头件 string.h
- srtlen是求字符串长度的,统计的是 \0 之前字符的隔个数
- 关注内存中是否有 \0 ,如果没有 \0 ,就会持续往后找,可能
会越界
一道关于sizeof的题
#include<stdop.h> int main() { short s=10; in**加粗样式**t i=2; int n=sizeof(s=i+4); printf("%d\n",s); printf("%d\n",n); return 0; }
s作为短整型是占用两个字节,而i是整形则占4个字节,在int n=sizeof(s=i+4)中,很多人会认为i+4会赋值给s,但是我们要注意二者的类型是不同的,一个是短整型,另一个是整形,因此会发生截断,由于s始终为短整形,因此sizeof(s)就是s的内存大小,就是2
对于n为什么是等于10,其实sizeof的操作数如果是一个表达式,那么表达式是不会参与计算的,因为我们已经知道了s是短整型,那么是没有必要再去计算的,所以s赋的值仍然是10.
表达式有两种属性
1:类型属性
2:值属性
所以我们以后只需要判断sizeof中的表达式类型就可以知道大小