指针(五)后半
1、 qsort 函数
1.1、qsort 函数排列结构体
在这里,我们创建结构体类型的数组,用于 qsort 函数的传参。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>struct Stu//创建结构体变量
{char name[30];int age;
};struct Stu arr[] = { { "zhangsan", 18 }, { "lisi", 20 }, { "wangwu", 38 } };void Print(struct Stu* p, int sz)//打印函数
{for (int i = 0; i < sz; i++){printf("%s: %d\n", p->name, p->age);p++;}
}cmp_str_by_age(const void* p1, const void* p2)//排年龄函数
{return (((struct Stu*)p1)->age - ((struct Stu*)p2)->age);
}test1()//按年龄大小
{int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_str_by_age);Print(arr, sz);
}cmp_str_by_name(const void* p1, const void* p2)//排姓名函数
{return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}test2()//按姓名
{int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_str_by_name);Print(arr, sz);
}int main()
{test1();printf("-------------------------\n");test2();return 0;
}
这里讲两点:
1、结构成员访问操作符: ->
使用方法为:结构体指针 -> 成员变量。上面代码中, ((struct Stu*)p1)->age 也可以换为 *(struct Stu*)p1.age 。
2、 strcmp 函数
使用方法为,向函数中传入两个字符串类型的数据,比较对应位置字符的 ASCII 码值的大小。以顺序为例,若前一个字符串对应位置字符的 ASCII 码值应大于后一个,返回大于0的值;相等返回0,小于返回小于0的值。
1.2、 qsort 函数的模拟实现
既然要实现 qsort 函数,那么向其中传入的参数,也应该是:首元素地址、元素个数、元素大小、比较函数。
#include<stdio.h>int int_cmp(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}void Bubble_qsort(void* base, int count, int size, int (*cmp)(void*, void*))}void test1()
{int arr[] = { 4,5,2,7,9,12,34,101 };int count = sizeof(arr) / sizeof(arr[0]);Bubble_qsort(arr, count, sizeof(arr[0]), int_cmp);
}int main()
{test1();//实现整型值的排序return 0;
}
将这个函数的名字取为 Bubble_qsort ,是因为我们将用冒泡排列的方式来模拟实现 qsort 函数。
所以,我们要交代趟数,也要交代每趟交换数据的次数。
而交换操作中,我们可以将每两个数(的地址)传入 int_cmp 函数中,观察返回的值。若返回正数值,则再创建一个交换函数。
但是, void* 类型的指针不能进行任何操作。也许会用强制类型转换,转换成什么? int* ?但这可是在模拟 qsort 函数,这个函数原来是可以排列任意类型的数据的。
所以,我们不妨将 void* 类型,强制转换成 char* 类型 。
#include<stdio.h>int int_cmp(const void* p1, const void* p2)
{return *(int*)p1 - *(int*)p2;
}void Swap(char* buf1, char* buf2)
{}void Bubble_qsort(void* base, int count, int size, int (*cmp)(void*, void*))
{for (int i = 0; i < count - 1; i++){for (int j = 0; j < count - i - 1; j++){if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0){Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}void test1()
{int arr[] = { 4,5,2,7,9,12,34,101 };int count = sizeof(arr) / sizeof(arr[0]);Bubble_qsort(arr, count, sizeof(arr[0]), int_cmp);
}int main()
{test1();//实现整型值的排序return 0;
}
而在交换函数中,既然地址已被强制转换成 char* ,那么我们就不能一次性交换干净,而是一点一点交换。交换的次数,自然是元素的大小。
#include<stdio.h>void Print(int arr[], int count)//打印函数
{for (int i = 0; i < count; i++){printf("%d ", arr[i]);}printf("\n");
}int int_cmp(const void* p1, const void* p2)//比较函数
{return *(int*)p1 - *(int*)p2;
}void Swap(char* buf1, char* buf2, int size)//交换函数
{for (int i = 0; i < size; i++){char tmp = *(buf1 + i);*(buf1 + i) = *(buf2 + i);*(buf2 + i) = tmp;}
}void Bubble_qsort(void* base, int count, int size, int (*cmp)(void*, void*))
{ //模拟 qsort 的函数for (int i = 0; i < count - 1; i++){for (int j = 0; j < count - i - 1; j++){if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0){Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}void test1()
{int arr[] = { 4,5,2,7,9,12,34,101 };int count = sizeof(arr) / sizeof(arr[0]);Print(arr, count);Bubble_qsort(arr, count, sizeof(arr[0]), int_cmp);Print(arr, count);
}int main()
{test1();//实现整型值的排序return 0;
}
这样一来,这个函数连结构体都能排列。但是要加一点比较函数代码:
#include<stdio.h>struct Stu//创建结构体
{char name[30];int age;
};void Print(int arr[], int count)//打印函数
{for (int i = 0; i < count; i++){printf("%d ", arr[i]);}printf("\n");
}void Print1(struct Stu* p, int sz)//打印结构体
{for (int i = 0; i < sz; i++){printf("%s: %d\n", p->name, p->age);p++;}
}int int_cmp(const void* p1, const void* p2)//比较函数
{return *(int*)p1 - *(int*)p2;
}int cmp_str_by_name(const void* p1, const void* p2)//比较字符串
{if (strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name) > 0)return 1;else if (strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name) < 0)return -1;elsereturn 0;
}void Swap(char* buf1, char* buf2, int size)//交换函数
{for (int i = 0; i < size; i++){char tmp = *(buf1 + i);*(buf1 + i) = *(buf2 + i);*(buf2 + i) = tmp;}
}void Bubble_qsort(void* base, int count, int size, int (*cmp)(void*, void*))
{ //模拟 qsort 的函数for (int i = 0; i < count - 1; i++){for (int j = 0; j < count - i - 1; j++){if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0){Swap((char*)base + j * size, (char*)base + (j + 1) * size, size);}}}
}void test1()
{int arr[] = { 4,5,2,7,9,12,34,101 };int count = sizeof(arr) / sizeof(arr[0]);Print(arr, count);Bubble_qsort(arr, count, sizeof(arr[0]), int_cmp);Print(arr, count);
}void test2()
{struct Stu arr[] = { { "zhangsan", 18 }, { "lisi", 20 }, { "wangwu", 38 } };int count = sizeof(arr) / sizeof(arr[0]);Print1(arr, count);printf("-------------------------\n");Bubble_qsort(arr, count, sizeof(arr[0]), cmp_str_by_name);Print1(arr, count);
}int main()
{//test1();//实现整型值的排序test2();//实现结构体的排列return 0;
}