【C语言基础】双指针在qsort函数中的应用

在C语言中使用 qsort 对字符串数组(如 char* 数组)排序时,必须转换为双指针(char**,这是由字符串数组的内存结构和 qsort 的工作原理决定的。以下是详细解释:


一、底层原理分析

1. 字符串数组的内存结构

假设有一个字符串数组:

char* strs[] = {"apple", "banana", "cherry"};

其内存布局如下:

strs[0] → 指向 "apple" 的首地址
strs[1] → 指向 "banana" 的首地址
strs[2] → 指向 "cherry" 的首地址

每个元素 strs[i] 的类型是 char*(字符串指针),因此:

  • 数组名 strs 的类型是 char**(指向指针的指针)
  • qsort 传递给比较函数的是 strs[i] 的地址(即 &strs[i]),其类型为 char**

2. qsort 的比较函数参数

qsort 的比较函数原型为:

int compar(const void *a, const void *b);
  • 参数 ab 是数组元素的指针,即 &strs[i]&strs[j]
  • 对于字符串数组,ab 的类型是 char**(指针的指针)。

二、正确转换步骤

1. 错误写法(直接转 char*
// 错误!会导致比较的是字符串内容,而非指针地址
int compare_strings_wrong(const void *a, const void *b) {const char *str1 = (const char*)a; // ❌ 直接转换const char *str2 = (const char*)b;return strcmp(str1, str2);
}
  • 问题ab 本质是 &strs[i]char** 类型),若直接转为 char*,实际比较的是指针地址值,而非字符串内容。

2. 正确写法(转双指针后解引用)
int compare_strings(const void *a, const void *b) {const char **str1 = (const char **)a; // ✅ 转换为双指针const char **str2 = (const char **)b;return strcmp(*str1, *str2); // 解引用得到实际的字符串指针
}
  • 关键点
    • a/b 转为 char**(因为它们本质是 char** 类型)
    • 解引用(*str1)得到实际的 char*(字符串首地址)
    • 比较字符串内容而非指针地址。

三、类比其他类型

int 数组为例:

int arr[] = {5, 2, 8};
  • 比较函数的参数是 int*(数组元素地址),直接解引用即可:
int compare_ints(const void *a, const void *b) {int num1 = *(const int*)a; // ✅ 直接转 int*int num2 = *(const int*)b;return num1 - num2;
}
  • 字符串数组与之不同,因为数组元素本身是指针(char*),所以需要多一层解引用。

四、常见错误场景

1. 错误结果示例

若错误地直接转换:

const char *str1 = (const char*)a; // a 是 char**,转 char* 后值等于 &strs[i]
const char *str2 = (const char*)b;
  • str1 的值是 &strs[i](即 char** 的地址值)
  • strcmp(str1, str2) 会比较这两个地址值的 ASCII 码,而非字符串内容,导致排序混乱。

2. 内存访问崩溃

若字符串数组元素为 NULL

char* strs[] = {"apple", NULL, "cherry"};
  • 错误转换后,strcmp 会尝试访问 NULL 地址,导致段错误。

五、总结

数据类型qsort 参数类型比较函数转换方式
int[]int*(指向元素的指针)*(const int*)a
char*[]char**(指向指针的指针)*(const char**)a

核心原则qsort 始终传递数组元素的地址,需根据元素类型决定如何转换和解引用。

以下是引用

逐步解释

  1. 定义比较函数

    int compare_strings(const void *a, const void *b) {const char **str1 = (const char **)a;const char **str2 = (const char **)b;return strcmp(*str1, *str2);
    }
    
    • const void *aconst void *bqsort 传递给比较函数的参数。
    • const char **str1const char **str2 是将 const void* 转换为 const char** 后的结果。
    • *str1*str2 分别是 str1str2 指向的字符串。
  2. 调用 qsort

    qsort(strs, len, sizeof(char*), compare_strings);
    
    • strs 是要排序的数组。
    • len 是数组的长度。
    • sizeof(char*) 是每个元素的大小(即每个元素是指针)。
    • compare_strings 是比较函数。
  3. 输出排序后的结果

    for (size_t i = 0; i < len; i++) {printf("%s ", strs[i]);
    }
    printf("\n");
    

为什么需要双指针转换

  • 第一次转换:将 const void* 转换为 const char**,因为 qsort 传递的是指向数组元素的指针。
  • 第二次转换:通过 *str1*str2 获取实际的字符串指针,以便使用 strcmp 函数进行比较。

通过这种方式,我们可以正确地对字符串数组进行排序,而不会出现类型不匹配的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/76987.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

批处理(Batch Processing)的详解、流程及框架/工具的详细对比

以下是批处理&#xff08;Batch Processing&#xff09;的详解、流程及框架/工具的详细对比&#xff1a; 一、批处理核心概念 定义&#xff1a; 批处理是离线处理大量数据或任务的自动化流程&#xff0c;特点是无人值守、高吞吐量、资源密集型&#xff0c;常用于数据清洗、报表…

基于FreeRTOS和LVGL的多功能低功耗智能手表(APP篇)

目录 一、简介 二、软件框架 2.1 MDK工程架构 2.2 CubeMX框架 2.3 板载驱动BSP 1、LCD驱动 2、各个I2C传感器驱动 3、硬件看门狗驱动 4、按键驱动 5、KT6328蓝牙驱动 2.4 管理函数 2.4.1 StrCalculate.c 计算器管理函数 2.4.2 硬件访问机制-HWDataAccess 2.4.3 …

【初阶数据结构】——算法复杂度

一、前言 1、数据结构是什么&#xff1f; 数据结构(Data Structure)是计算机存储、组织数据的⽅式&#xff0c;指相互之间存在⼀种或多种特定关系的数 据元素的集合。没有⼀种单⼀的数据结构对所有⽤途都有⽤&#xff0c;所以我们要学各式各样的数据结构&#xff0c; 如&…

记录 | Pycharm中如何调用Anaconda的虚拟环境

目录 前言一、步骤Step1 查看anaconda 环境名Step2 Python项目编译器更改 更新时间 前言 参考文章&#xff1a; 参考视频&#xff1a;如何在pycharm中使用Anaconda创建的python环境 自己的感想 这里使用的Pycharm 2024专业版的。我所使用的Pycharm专业版位置&#xff1a;【仅用…

linux如何用关键字搜索日志

在 Linux 系统中搜索日志是日常运维的重要工作&#xff0c;以下是几种常用的关键字搜索日志方法&#xff1a; 1. 基础 grep 搜索 bash 复制 # 基本搜索&#xff08;区分大小写&#xff09; grep "keyword" /var/log/syslog# 忽略大小写搜索 grep -i "error&…

K-均值聚类机器学习算法的优缺点

K-均值聚类是一种常用的无监督学习算法&#xff0c;用于将具有相似特征的数据点聚集到一起。以下是K-均值聚类算法的步骤及其优缺点&#xff1a; K-均值聚类算法步骤&#xff1a; 初始化&#xff1a;随机选择K个点作为初始的聚类中心。分配数据点&#xff1a;将每个数据点分配…

AI驱动SEO关键词实战策略

内容概要 AI驱动的SEO关键词优化体系通过技术融合实现了策略升级。该框架以语义理解模型为基础&#xff0c;结合实时流量监测与行业数据库&#xff0c;构建了包含关键词挖掘、竞争评估、内容适配三大核心模块的闭环系统。通过自然语言处理&#xff08;NLP&#xff09;技术解析…

Golang|在线排查协程泄漏

根据我们的代码&#xff0c;前5毫秒内&#xff0c;每隔1毫秒就会来一个请求&#xff0c;5毫秒之后由于前面的协程执行完&#xff0c;后面又会来新的协程&#xff0c;所以协程数目会保持稳定但是代码一运行&#xff0c;协程数量一直增长&#xff0c;发生了协程泄漏 我们可以list…

Java项目之基于ssm的QQ村旅游网站的设计(源码+文档)

项目简介 QQ村旅游网站实现了以下功能&#xff1a; 管理员权限操作的功能包括管理景点路线&#xff0c;板块信息&#xff0c;留言板信息&#xff0c;旅游景点信息&#xff0c;酒店信息&#xff0c;对景点留言&#xff0c;景点路线留言以及酒店留言信息等进行回复&#xff0c;…

高级语言调用C接口(四)结构体(2)-Python

这个专栏好久没有更新了&#xff0c;主要是坑开的有点大&#xff0c;也不知道怎么填&#xff0c;涉及到的开发语言比较多&#xff0c;写起来比较累&#xff0c;需要看的人其实并不多&#xff0c;只能说&#xff0c;慢慢填吧&#xff0c;中间肯定还会插很多别的东西&#xff0c;…

JAVA 主流微服务常用框架及简介

Java微服务架构的优势在于其轻量级、高效资源利用&#xff0c;支持快速开发与灵活部署&#xff0c;拥有强大的生态系统与跨平台兼容性&#xff0c;能够实现高性能与稳定性&#xff0c;并允许独立扩展与技术栈多样性。然而&#xff0c;其劣势也不容忽视&#xff0c;包括架构复杂…

儿童后期至青少年早期脑网络隔离增强的发育机制研究

目录 1 研究背景 2 研究方法 2.1 纵向数据集 2.2 图像预处理 2.3 个体化区域放射组学相似网络构建 2.4 分离度&#xff08;模块化&#xff09;度量 2.5 分离度指数发育变化的建模 2.6 分离指数与认知表现的相关性分析 2.7 成像转录组分析 3 研究结果 3.1 三个尺度上…

redis 内存中放哪些数据?

在 Java 开发中,Redis 作为高性能内存数据库,通常用于存储高频访问、低延迟要求、短期有效或需要原子操作的数据。以下是 Redis 内存中常见的数据类型及对应的使用场景,适合面试回答: 1. 缓存数据(高频访问,降低数据库压力) 用户会话(Session):存储用户登录状态、临时…

Spring AOP 学习笔记 之 Advice详解

学习材料&#xff1a;https://docs.spring.io/spring-framework/reference/core/aop/ataspectj/advice.html 1. 什么是 Advice&#xff08;通知&#xff09; 定义&#xff1a;Advice 是 AOP 的核心概念之一&#xff0c;表示在特定的连接点&#xff08;Join Point&#xff09;上…

数智读书笔记系列029 《代数大脑:揭秘智能背后的逻辑》

《代数大脑:揭秘智能背后的逻辑》书籍简介 作者简介 加里F. 马库斯(Gary F. Marcus)是纽约大学心理学荣休教授、人工智能企业家,曾创立Geometric Intelligence(后被Uber收购)和Robust.AI公司。他在神经科学、语言学和人工智能领域发表了大量论文,并著有《重启AI》等多部…

如何看电脑的具体配置?

李升伟 整理 要查看电脑的具体配置&#xff0c;可以通过系统工具、命令行工具或第三方软件实现&#xff0c;以下是具体方法&#xff1a; 一、系统自带工具查看&#xff08;无需安装软件&#xff09; Windows系统&#xff1a; 系统设置&#xff1a; 右键点击桌面“此电脑”…

开源TTS项目GPT-SoVITS,支持跨语言合成、支持多语言~

简介 GPT-SoVITS 是一个开源的文本转语音&#xff08;TTS&#xff09;项目&#xff0c;旨在通过少量语音数据实现高质量的语音合成。其核心理念是将基于变换器的模型&#xff08;如 GPT&#xff09;与语音合成技术&#xff08;如 SoVITS&#xff0c;可能指“唱歌语音合成”&am…

D1084低功耗LDO稳压器:技术解析与应用设计

引言 在现代电子设计中&#xff0c;低功耗和高效率是至关重要的。D1084是一款5A低功耗低压差线性稳压器&#xff08;LDO&#xff09;&#xff0c;以其出色的负载调节能力和快速瞬态响应&#xff0c;成为低电压微处理器应用的理想选择。本文将深入解析D1084的技术特性和应用设计…

Log4j详解:Java日志系统全指南

文章目录 1. 日志系统简介1.1 什么是日志1.2 为什么使用日志框架1.3 Java中的常见日志框架 2. Log4j概述2.1 Log4j简介2.2 Log4j的版本历史2.3 Log4j与Log4j 2的主要区别 3. Log4j架构与核心组件3.1 Logger&#xff08;日志记录器&#xff09;3.2 日志级别&#xff08;Level&am…

【信息系统项目管理师】高分论文:论信息系统项目的整合管理(银行数据仓库项目)

更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 正文一、制定项目章程二、制定项目管理计划三、指导和管理项目的实施四、管理项目知识五、监控项目工作六、实施整体变更控制七、结束项目或阶段正文 2023年6月,我以项目经理的身份,参加了 xx银行xx省分行数…