//////————————8.回调函数

////回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个

////函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数

////的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进

////行响应。


////qosrt函数的使用者得实现一个比较函数

////qsort是比较函数,可以排序任意类型的数据

////qsort是库函数,需要引用对应头文件#include <stdlib.h>或者#include <search.h>

//// void qsort——————————————————————————参数详解

//// void qsort(void* base,size_t num,size_t width,int(* cmp)(const void* e1,const void* e2))

//// void* base//我们要排序的数据的起始位置(arr:首元素地址)

//// size_t num//待排序的数据元素的个数

//// size_t width//待排序的数据元素的大小(占几个字节)

//// int(* cmp)(const void* e1,const void* e2)//函数指针

////  

////如果我们实现一个排序算法,排序不同数据的话(结构体,整型...),其比较方式不同,

//// 因此我们把比较函数的功能(比较的模块)提取出来,放在“int(* cmp)(const void* e1,const void* e2)”的“cmp”,

//// cmp函数就是一个比较函数的地址,我们可以把一个比较函数的地址传给cmp,cmp就是一个函数指针,

//// 此时e1指向了我们要比较的第一个元素,e2指向了我们要比较的第二个元素。

//// e1和e2是我们要比较的两个元素的地址,此时cmp就会主动去调用它指向的比较函数,

//// 然后把e1,e2指向的两个元素进行比较,此时,不管我们排序什么类型的数据,我们都根据提供的比较函数进行比较并排序。

////qsort(arr,sz,sizeof(arr[0]),)

//#include <stdio.h>

//#include <stdlib.h>

//int int_cmp(const void* e1, const void* e2)//比较两个整型元素,e1.e2分别指向一个整数

//{

//    //void*的指针不能直接进行解引用操作//例如e1,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为int*(整型指针)//return中e1-e2为升序、e2-e1为降序

//}

//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);

//    //此处我们并没有调用int_cmp函数,int_cmp函数的“实现方”是程序员,也就是“我”,

//    //而调用函数的是qsort,qsort在其内部某个特定的条件下调用了int_cmp所指向的函数

//    for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)

//    {

//        printf("%d ", arr[i]);

//    }

//    printf("\n");

//    return 0;

//}

//////————void*的指针不能直接进行解引用操作

////例如:

//#include<stdio.h>

//int main()

//{

//    int a = 10;

//    //char* pa = &a;//不可以,会报错"int *" 类型的值不能用于初始化 "char *" 类型的实体

//    void* pv = &a;//void*是无具体类型的指针,可以接受任意类型的地址,

//    //但是不能解引用操作和+或-整数的操作,因为进行解引用操作时,到底访问多少字节,

//    // 需要知道确切的类型,才清楚+或-一个整数时,跳过几个字节但是void*无类型

//    return 0;

//}

////为什么使用void*的指针?

////答:当我们不清楚传过来的是什么类型的地址时,我们要去接收此地址只能使用void*(包容性)

//// 使用回调函数,模拟实现qsort(采用冒泡的方式)。

////注意:这里第一次使用 void* 的指针,讲解 void* 的作用。

//////——————————————————————————结构体排序

//#include <stdio.h>

//#include <string.h>

//#include <stdlib.h>

//struct Stu

//{

// char name[5];

// int age;

//};

//int cmp_Stu_byname(const void* e1, const void* e2)//通过比较名字(字符串比较大小必须要用strcmp函数比较,不可以用+-)

//{

// return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);////strcmp返回的值有>0、==0、<0

//}// //比较方法:kk和hh比较,先是第一个相互比,k>h,所以kk大

////通过比较年龄(直接进行比较,可以用+-)

//int cmp_Stu_byage(const void* e1, const void* e2)

//{

// return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;

//}

//void test1()//————名字比较

//{

// //测试使用qsort来排序结构数据

// struct Stu s[] = { {"kk",15}, {"hh",16} ,{"ss",17}};

// int sz = sizeof(s) / sizeof(s[0]);

// qsort(s, sz, sizeof(s[0]), cmp_Stu_byname);

// printf("%s\n", s);

//}

//void test2()

//{

// //测试使用qsort来排序结构数据

// struct Stu s[] = { {"kk",15}, {"hh",16} ,{"ss",17} };

// int sz = sizeof(s) / sizeof(s[0]);

// qsort(s, sz, sizeof(s[0]), cmp_Stu_byage);

// printf("%s\n", s);

//}

//int main()

//{

// test1();

// test2();

// return 0;

//}

////////————————————————————————————自创函数冒泡排序

////qsort函数内部是基于快速排序的思想来实现的

//#include <stdio.h>

//int int_cmp(char* p1, char* p2)

//{

//    return (*(int*)p1 - *(int*)p2);

//}

//void Swap(char* p1, char* p2, int width)

//{

//    int i = 0;

//    for (i = 0; i < width; i++)

//    {

//        /*char tmp = *((char*)p1 + i);

//        *((char*)p1 + i) = *((char*)p2 + i);

//        *((char*)p2 + i) = tmp;*///等同于

//        char tmp = *p1;

//        *p1 = *p2;

//        *p2 = tmp;

//        p1++;

//        p2++;

//    }

//}

//void bubble(void* base, int sz, int width, int(*cmp)(char*, char*))

//{

//    int i = 0;//趟数

//    for (i = 0; i < sz - 1; i++)

//    {

//        int flag=1;//假设数组已经排好顺序

//        //一趟冒泡排序的过程

//    int j = 0;

//        for (j = 0; j < sz - i - 1; j++)

//        {

//            //由于计算之前一切都是未知的,所以我们传参时的每一项都要进行同等条件下最精细的等价转换

//            if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)

//            //此处的两个参数是待比较两个元素的地址

//             //此处的强制类型转换用char*而不是int*是因为我们不清楚其真实类型,而int*+1跳过四个字节过于大,

//             //所以我们采用char*,每次只调过一个字节,更为稳妥

//            {

//                //交换

//                Swap((char*)base + j *width, (char*)base + (j + 1) * width, width);//交换时,需交代一下元素的宽度width

//                //width:待排序的数据元素的大小(占几个字节)

//                flag = 0;

//            }

//        }

//        if (flag == 1)

//        {

//            break;

//        }

//    }

//}

//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的计算,以及类型匹配

//#include<stdio.h>

//#include<string.h>

//int main()

//{

// char a = 10;

// const char arr[] = {1,2,3,4,5};

// printf("%d\n",strlen(&a));

// printf("%d\n", strlen(arr));

// printf("%d\n", sizeof(a));

// printf("%d\n", sizeof(arr));

// return 0;

//}

//