C语言 qsort 函数用法详解与模拟实现

云舒
云舒
发布时间:2026-10-15| 4人浏览过
原创

本文详解C语言标准库函数qsort的用法,涵盖整型、字符串、浮点数及结构体的排序技巧。通过自定义比较函数解决通用排序问题,并提供基于冒泡思想的通用排序模拟实现,帮助深入理解指针操作与泛型编程原理。

一、qsort 函数简介与参数解析

qsort是C语言标准库提供的通用排序函数,底层通常采用快速排序算法。它位于头文件 stdlib.h中,能够对任意类型的数组进行排序。

函数原型如下:

void qsort(void *base, size_t num, size_t size,
           int (*compar)(const void *, const void *));

第1步:理解参数含义

  • void *base:指向待排序数组的第一个元素的地址(起始位置)。
  • size_t num:数组中元素的总个数。
  • size_t size:每个元素占用的字节数。
  • int (*compar)(const void *, const void *):比较函数的指针。该函数用于定义两个元素的比较规则,其返回值决定排序顺序:
返回值条件
> 0第一个参数大于第二个参数
< 0第一个参数小于第二个参数
= 0两个参数相等

注意:由于传入的比较函数接收的是 const void * 类型指针,无法直接解引用或运算,必须强制转换为具体数据类型的指针。

二、qsort 函数的常见应用场景

1. 整型数组排序

对整数数组进行升序排序。核心在于编写一个针对整型的比较函数。

#include <stdio.h>
#include <stdlib.h>

int cmp_int(const void* e1, const void* e2) {
    // 将 void* 强转为 int* 并解引用获取值
    return *((int*)e1) - *((int*)e2);
}

int main() {
    int arr[] = { 7,8,9,4,5,6,1,2,3,10 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    
    // base传数组名(首元素地址),num为元素个数,size为单个元素字节数
    qsort(arr, sz, sizeof(int), cmp_int);
    
    for (int i = 0; i < sz; i++) {
        printf("%d ", arr[i]); // 输出:1 2 3 4 5 6 7 8 9 10
    }
    return 0;
}

2. 字符串(字符数组)排序

对字符数组按ASCII码升序排序。需注意计算长度时应使用 strlen,因为 sizeof 会包含结尾的空字符 '\0'。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int cmp_char(const void* e1, const void* e2) {
    return strcmp((char*)e1, (char*)e2);
}

int main() {
    char arr[] = "badecf";
    int sz = strlen(arr); // 不包含 '\0'
    
    qsort(arr, sz, sizeof(char), cmp_char);
    printf("%s\n", arr); // 输出:abcdef
    return 0;
}

3. 字符串指针数组按长度排序

当数组元素是指针(如 char*)时,比较函数需先解引用指针得到字符串地址,再计算长度进行比较。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int cmp_strlen(const void* e1, const void* e2) {
    // e1/e2 是 char** 类型,解引用后得到 char* 地址
    return strlen(*(char**)e1) - strlen(*(char**)e2);
}

int main() {
    char* arr[] = { "abc", "abcd", "abcdef" };
    int sz = 3;
    
    qsort(arr, sz, sizeof(char*), cmp_strlen);
    
    for (int i = 0; i < sz; i++) {
        printf("%s\n", arr[i]); // 按长度从短到长输出
    }
    return 0;
}

4. 浮点型数组排序

浮点数比较不能直接相减后转 int,因为精度丢失会导致错误结果。应判断差值是否大于/小于0。

#include <stdio.h>
#include <stdlib.h>

int cmp_float(const void* e1, const void* e2) {
    float val1 = *(float*)e1;
    float val2 = *(float*)e2;
    if (val1 > val2) return 1;
    else if (val1 < val2) return -1;
    else return 0;
}

int main() {
    float arr[] = { 12.01f, 12.03f, 12.09f };
    int sz = sizeof(arr) / sizeof(arr[0]);
    
    qsort(arr, sz, sizeof(float), cmp_float);
    
    for (int i = 0; i < sz; i++) {
        printf("%f  ", arr[i]);
    }
    return 0;
}

5. 结构体类型排序

可根据结构体成员的不同类型分别编写比较函数,例如按年龄(整型)或姓名(字符串)排序。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct stu {
    char name[20];
    int age;
};

// 按年龄排序
int cmp_age(const void* e1, const void* e2) {
    return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}

// 按姓名排序
int cmp_name(const void* e1, const void* e2) {
    return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);
}

int main() {
    struct stu s[] = { {"zhangsan",21},{"lisi",20},{"wangwu",52} };
    int sz = sizeof(s) / sizeof(s[0]);
    
    // 选择按年龄排序
    qsort(s, sz, sizeof(struct stu), cmp_age);
    
    for (int i = 0; i < sz; i++) {
        printf("%s %d\n", s[i].name, s[i].age);
    }
    return 0;
}

三、用冒泡排序模拟实现通用排序功能

为了深入理解 qsort 的泛型原理,我们可以利用内存字节交换的方式,结合冒泡排序算法实现一个通用的排序函数 qsort_bubble。

1. 核心思路

  • 字节交换:由于处理的是 void*,无法直接按数据类型交换。需要逐字节(byte by byte)交换,次数由元素宽度 width 决定。
  • 地址偏移:在遍历数组时,通过 (char*)base + index * width 定位当前和相邻元素的起始地址。
  • 比较逻辑复用:比较函数保持不变,只需传入对应的地址即可。

2. 代码实现

#include <stdio.h>
#include <string.h>

struct stu {
    char name[20];
    int age;
};

int cmp_age(const void* e1, const void* e2) {
    return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}

// 逐字节交换函数
void Swap(char* buf1, char* buf2, int width) {
    for (int i = 0; i < width; i++) {
        char tmp = *buf1;
        *buf1 = *buf2;
        *buf2 = tmp;
        buf1++;
        buf2++;
    }
}

// 通用冒泡排序实现
void qsort_bubble(void* base, int sz, int width, int(*cmp)(const void*, const void*)) {
    for (int i = 0; i < sz - 1; i++) {
        for (int j = 0; j < sz - 1 - i; j++) {
            // 计算相邻两个元素的地址
            char* elem1 = (char*)base + j * width;
            char* elem2 = (char*)base + (j + 1) * width;
            
            // 调用比较函数
            if (cmp(elem1, elem2) > 0) {
                Swap(elem1, elem2, width);
            }
        }
    }
}

int main() {
    struct stu s[] = { {"zhangsan",21},{"lisi",20},{"wangwu",52} };
    int sz = sizeof(s) / sizeof(s[0]);
    
    // 打印排序前
    for (int i = 0; i < sz; i++) {
        printf("%s %d\n", s[i].name, s[i].age);
    }
    
    // 调用自定义通用排序
    qsort_bubble(s, sz, sizeof(struct stu), cmp_age);
    
    printf("\n--- Sorted ---\n");
    // 打印排序后
    for (int i = 0; i < sz; i++) {
        printf("%s %d\n", s[i].name, s[i].age);
    }
    return 0;
}

以上就是C语言中qsort函数用法及用冒泡排序实现的详细内容,更多关于C语言 qsort泛型排序的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。