``` /*********** memcmp的模拟实现 ***********/ int my_memcmp(const void* ptr1, const void* ptr2, size_t num) { assert(ptr1 && ptr2); while (*(char*)ptr1 == *(char*)ptr2) { ptr1 = *(char*)ptr1 + 1; ptr2 = *(char*)ptr2 + 1; } if (*(char*)ptr1 > *(char*)ptr2) { return 1; } else { return -1; } return 0; } int main() { int arr1[] = { 1,2,3,4,5 }; int arr2[] = { 1,2,3,4,0x12233301 }; int r = my_memcmp(arr1, arr2, 17); printf("%d", r); return 0; }```我想要模仿memcmp的功能上面我写的代码有哪些问题?

时间: 2025-03-16 07:04:09 浏览: 9

好的,我现在需要帮用户分析他们写的memcmp模拟实现代码中的问题。首先,我得仔细阅读用户提供的代码,理解他们的思路,然后逐行检查可能存在的错误。

首先看my_memcmp函数的实现。用户的目标是逐字节比较两个内存区域的内容,直到找到不同的字节或者比较完num个字节。看起来他们用了while循环来遍历每个字节,当两个字节相等时继续循环。循环结束后,比较当前字节的大小,返回1或-1,否则返回0。

不过,我发现有几个问题。首先,在循环条件中,用户没有检查已经比较了多少个字节。也就是说,即使还没有比较完num个字节,只要遇到相同的字节就会继续循环,这可能导致越界访问。正确的做法应该是在循环条件中加入对剩余字节数的检查,比如使用一个计数器,或者在每次循环后递减num,直到num变为0。

然后看循环体内部的指针移动。用户将ptr1和ptr2强制转换为char指针,然后解引用,接着将指针加1。但是这里有一个错误:ptr1 = (char)ptr1 + 1; 这行代码实际上是将ptr1指向的值(转换为char)加1后的结果赋值给ptr1,这显然是不对的。正确的做法应该是先将指针转换为char类型,然后进行指针算术运算,比如:ptr1 = (char*)ptr1 + 1; 同样适用于ptr2。这一步的错误会导致指针移动不正确,可能访问到错误的内存地址,导致程序崩溃或错误的结果。

接下来,循环结束后,用户直接比较当前字节的大小,但这里忽略了一个情况:如果在num个字节全部比较完成后,所有字节都相等,那么应该返回0。而当前的代码在循环结束后,只有当遇到不同的字节才会进行比较,否则循环结束后直接返回0。但这里的问题在于,如果在循环中已经比较完所有num个字节,而所有字节都相等,那么应该返回0,但当前代码可能在循环结束后继续执行后面的判断,导致错误。例如,当所有字节都相等时,循环会因为ptr1和ptr2的值相等而继续,直到遇到不相等的情况或者指针越界。这显然不符合memcmp的行为,因为memcmp会在比较完所有num个字节后返回0,即使之后的字节不同也不影响。

另外,用户的循环条件只检查当前字节是否相等,而没有检查是否已经比较了num个字节。这可能导致比较的字节数超过num指定的数量,进而导致越界访问。正确的做法应该是在循环中每比较一个字节就减少num,并在num减到0时退出循环,返回0。

还有,当所有字节都相等且num减到0时,函数应该直接返回0,而不是继续后面的比较。用户的代码中,循环结束后直接进行大小比较,而没有考虑num已经处理完的情况,这会导致错误的返回值。

此外,在main函数中,用户比较了17个字节。由于arr1和arr2是int数组,每个int占4字节(假设32位系统),所以每个数组元素占4字节。arr1有5个元素,占20字节,arr2同理。比较17字节的话,会覆盖前4个int(16字节)加上第5个int的第1个字节。用户可能在测试时预期不同的结果,但由于代码中的指针移动错误,结果可能不符合预期。

还有一个问题是,当两个内存块的内容完全相同,但num为0时,memcmp应该返回0,但用户的代码在这种情况下可能不会正确处理,因为循环可能不会执行,但后续的比较逻辑可能会错误地返回1或-1,不过在这种情况下num可能为0,循环不会执行,直接返回0,这部分可能需要再确认。

总结一下,用户代码中的主要问题包括:

  1. 指针递增错误:错误地解引用后加1,导致指针移动不正确。
  2. 缺少对比较字节数的控制:循环没有检查已经比较了多少字节,可能导致越界或比较不足。
  3. 处理所有字节相等的情况不正确:在比较完所有字节后未正确返回0。
  4. 返回值逻辑问题:当所有字节都相等时,循环结束后错误地进行比较,而实际上应该返回0。

接下来需要将这些分析整理成用户能够理解的步骤,指出每个问题,并提供修正后的代码示例。同时,需要确保使用正确的中文表达,结构清晰,帮助用户逐步理解问题所在。你的my_memcmp实现存在以下几个关键问题,我通过对比标准库的memcmp行为进行逐步分析:


一、指针递增错误(最严重问题)

问题代码

ptr1 = *(char*)ptr1 + 1;  // 错误解引用导致野指针
ptr2 = *(char*)ptr2 + 1;

问题分析

  • 这里先将ptr1强转成char*指针后解引用,取到的是当前指针指向的char类型数据值
  • 对数据值+1后赋值给指针,会导致指针指向完全错误的地址(例如当数据值为0x01时,指针会被赋值为0x02)

正确写法

ptr1 = (char*)ptr1 + 1;  // 正确指针运算
ptr2 = (char*)ptr2 + 1;

二、缺少比较次数控制(功能错误)

问题代码

while (*(char*)ptr1 == *(char*)ptr2)  // 缺少num控制

问题分析

  • 标准库的memcmp会比较前num个字节,而你的代码会一直比较到出现差异为止
  • 当两个内存块前num个字节完全相同时,你的代码会因为循环结束后的判断而错误返回1或-1

正确逻辑

while (num-- > 0) {
    if (*(unsigned char*)ptr1 != *(unsigned char*)ptr2) {
        // 比较差异
    }
    ptr1 = (char*)ptr1 + 1;
    ptr2 = (char*)ptr2 + 1;
}
return 0;  // 全部比较完未发现差异

三、符号处理不当(易错点)

问题代码

if (*(char*)ptr1 > *(char*)ptr2) return 1;
else return -1;

问题分析

  • char类型范围是-128~127,当字节值为0xFF时会被当作-1
  • 正确做法应使用unsigned char比较,确保按二进制值比较

正确写法

unsigned char c1 = *(unsigned char*)ptr1;
unsigned char c2 = *(unsigned char*)ptr2;
return (c1 > c2) ? 1 : -1;

四、最终修正代码

int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{
    assert(ptr1 && ptr2);
    const unsigned char* p1 = ptr1;
    const unsigned char* p2 = ptr2;

    while (num-- > 0) {
        if (*p1 != *p2) {
            return (*p1 > *p2) ? 1 : -1;
        }
        p1++;
        p2++;
    }
    return 0;
}

五、测试用例分析

你的测试代码

int arr1[] = {1,2,3,4,5};
int arr2[] = {1,2,3,4,0x12233301};
int r = my_memcmp(arr1, arr2, 17);

注意事项

  1. int类型通常占4字节,比较17字节相当于比较:
    • 前4个int(16字节)
    • 第5个int的第一个字节
  2. 当使用修正后的代码时:
    • 前16字节相同(1,2,3,4的二进制表示)
    • 第17字节比较5的二进制第1字节 vs 0x01

正确输出:由于0x01小于0x05,应该返回1


通过以上修正,你的函数可以正确实现标准库memcmp的以下特性:

  1. 按字节比较内存内容
  2. 严格比较num个字节
  3. 返回值的符号反映差异字节的大小关系
向AI提问 loading 发送消息图标

相关推荐

最新推荐

recommend-type

2023-04-06-项目笔记 - 第四百四十六阶段 - 4.4.2.444全局变量的作用域-444 -2025.03.23

2023-04-06-项目笔记-第四百四十六阶段-课前小分享_小分享1.坚持提交gitee 小分享2.作业中提交代码 小分享3.写代码注意代码风格 4.3.1变量的使用 4.4变量的作用域与生命周期 4.4.1局部变量的作用域 4.4.2全局变量的作用域 4.4.2.1全局变量的作用域_1 4.4.2.444局变量的作用域_444- 2025-03-23
recommend-type

第三章 Matlab基本语法练习题.docx

第三章 Matlab基本语法练习题.docx
recommend-type

医学图像分割数据集:4种显微镜下的细胞目标图像语义分割数据集(约1000张数据和标签)

医学图像分割数据集:4种显微镜下的细胞目标图像语义分割数据集(约1000张数据和标签) 【5类别的分割】:背景:0 上皮细胞:1 淋巴细胞:2 中性粒细胞:3 巨噬细胞:4(具体参考classes文件 ) 数据集介绍:【已经划分好】 训练集:images图片目录+masks模板目录,737张左右图片和对应的mask图片 验证集:images图片目录+masks模板目录,315张左右图片和对应的mask图片 除此之外,包含一个图像分割的可视化脚本,随机提取一张图片,将其原始图片、GT图像、GT在原图蒙板的图像展示,并保存在当前目录下 医学图像分割网络介绍:https://blog.csdn.net/qq_44886601/category_12102735.html 更多图像分割网络unet、swinUnet、trasnUnet改进,参考改进专栏:https://blog.csdn.net/qq_44886601/category_12803200.html
recommend-type

LA1C-PHP+CSV_1个通用条件工资成绩等通用查询系统网页自适应版(Utf-8)_2024最终版.zip

LA1C-PHP+CSV_1个通用条件工资成绩等通用查询系统网页自适应版(Utf-8)_2024最终版
recommend-type

基于SpringBoot的酒店管理系统(源码+数据库+万字文档+开题报告+ppt)315

酒店管理系统,系统包含两种角色:管理员、用户,系统分为前台和后台两大模块,主要功能如下。 前台: - 首页:展示酒店的一些基本信息和轮播图。 - 酒店简介:展示酒店的基本介绍、位置等信息。 - 酒店客房:用户可以查看酒店的客房类型、价格、设施等信息,并进行客房预定。 - 酒店公告:展示酒店的公告信息,包括优惠活动、服务通知等。 - 个人中心:管理个人信息,包括修改个人信息、查看订单记录等。 后台: - 管理员: - 个人中心:管理个人信息,包括修改个人信息、查看订单记录等。 - 员工管理:管理酒店的员工信息,包括添加、编辑、删除员工等操作。 - 用户管理:管理酒店的用户信息,包括添加、编辑、删除用户等操作。 - 客房类型管理:管理酒店的客房类型信息,包括添加、编辑、删除客房类型等操作。 - 酒店简介管理:管理酒店的简介信息,包括编辑、更新酒店简介等操作。 - 酒店客房管理:管理酒店的客房信息,包括添加、编辑、删除客房等操作。 - 客房预定管理:管理客房的预定信息,包括查看、确认、取消预定等操作。 - 入住安排管理:管理
recommend-type

深入解析网络原理RFC文档全集

网络原理RFC文档详解的知识点可以分为以下几部分: ### 1. 网络协议基础 网络协议是计算机网络中进行数据交换而建立的规则、标准或约定。在网络原理的学习中,协议是非常重要的部分。RFC文档(Request For Comments,请求评论)是由互联网工程任务组(IETF)发布的一系列备忘录,记录了各种互联网协议的设计、行为、研究和创新。了解RFC文档可以帮助我们更深入地理解网络原理,比如IP、TCP、UDP等常见协议的工作机制。 ### 2. RFC文档的结构和内容 RFC文档通常包括标题、状态(标准、草案等)、日期、作者、摘要、目录、正文和参考文献等部分。文档详细解释了协议的各个方面,包括协议的设计目标、数据格式、状态机、操作过程、安全性考虑等。对于网络工程师和开发者而言,RFC文档是学习和开发网络应用的重要参考资料。 ### 3. 网络协议族和RFC 网络协议按照功能和层次可以分为不同的协议族,例如TCP/IP协议族。RFC文档涵盖了这一协议族中几乎所有的协议,包括但不限于以下内容: #### 3.1 网络层协议 - **IP协议(RFC 791)**:定义了互联网中数据包的格式和路由方式。 - **ICMP协议(RFC 792)**:用于在IP主机、路由器之间传递控制消息。 - **ARP协议(RFC 826)**:地址解析协议,将网络层地址解析成链路层地址。 #### 3.2 传输层协议 - **TCP协议(RFC 793)**:传输控制协议,提供面向连接的、可靠的数据传输服务。 - **UDP协议(RFC 768)**:用户数据报协议,提供无连接的、不可靠的传输服务。 #### 3.3 应用层协议 - **HTTP协议(RFC 2616等)**:超文本传输协议,用于万维网数据传输。 - **FTP协议(RFC 959)**:文件传输协议,用于文件的上传和下载。 - **SMTP协议(RFC 5321)**:简单邮件传输协议,用于邮件发送。 - **DNS协议(RFC 1035)**:域名系统,用于将域名转换成IP地址。 ### 4. RFC文档的应用和实践 网络工程师、开发人员、系统管理员和其他IT专业人员通常需要阅读RFC文档来了解特定技术的具体实现细节。例如,设计一个网络服务时,需要参考相关协议的标准RFC来确保服务的兼容性和可靠性。在遇到网络问题时,RFC文档也可以提供权威的故障排除信息。 ### 5. 如何获取和理解RFC文档 RFC文档是公开的,并且可以从互联网工程任务组(IETF)的官方网站免费获取。对于非专业人员来说,直接阅读RFC文档可能会有一定难度,因为它们通常包含大量的技术术语和细节描述。为了更好地理解和应用RFC文档,可以通过网络课程、专业书籍和实践操作相结合的方式来学习。 ### 6. RFC文档对网络研究的影响 RFC文档是网络技术研究的基础,它们不仅提供了网络协议的详细规范,而且还有助于新的网络技术和应用的发现。学术研究者和工程师通过分析和改进现有的RFC标准,能够推动网络技术的进步。 通过以上对网络原理RFC文档的详细介绍,我们可以看出,RFC文档不仅为网络行业提供了一个开放、共享和权威的知识库,而且它也是网络技术不断进步和发展的基石。掌握RFC文档的知识,对于从事网络相关工作的专业人士来说,无疑是一种重要的技能和财富。
recommend-type

【PLC流水灯设计全面攻略】:从理论到实践,专家带你实现零故障控制系统

# 摘要 本文系统介绍了PLC(可编程逻辑控制器)流水灯的设计、硬件接线技术、编程实现及深入应用。首先,概述了流水灯设计的理论基础和PLC硬件的基本组成、工作原理以及硬件选型与配置。接着,重点探讨了PLC编程基础、控制逻辑的设计、编程语言的选择与使用,以及流水灯控制程序的编写与调试。此外,文章还分析了特殊流水灯效果的实现、流水灯在自动化生产线的应用案例,以及故障诊断与维护。最后,针对当前技术趋势和挑战,展望了PLC流水灯设计的创新方向,包括智能控制系统的融合与面向未来的系统设计展望。 # 关键字 PLC;流水灯设计;硬件接线;编程实现;故障诊断;自动化生产线 参考资源链接:[基于PLC的流
recommend-type

针对你range 代码生成效果图

在Python中,`range()` 函数用于生成一系列数字,常与其他循环结构一起使用来完成迭代操作。虽然 `range()` 本身并不直接生成“效果图”,但我们可以将它和数据可视化库(如 Matplotlib 或 Seaborn)结合起来,创建基于范围值的数据分布图表。 下面是一个简单的例子,展示如何通过 Python 的 `matplotlib.pyplot` 模块配合 `range()` 来绘制一条直线并标记点的位置: ```python import matplotlib.pyplot as plt # 使用 range() 创建 x 轴数值序列 x_values = list(
recommend-type

自定义圆角ListView布局及点击效果解析

标题“CornerListviewDemo”指的是一个Demo程序,这个Demo展示了一种对ListView组件进行定制的实现,旨在根据ListView中项的多少以及布局,动态改变列表项的角的形状。这个Demo的开发和实现涉及到Android开发中的UI定制、布局文件编写以及可能的Java或Kotlin编程。 在描述中提到的行为是,ListView在不同数据量下展现不同的视觉效果。具体来说,当ListView只有一个列表项时,它会表现为四个角都是圆角的卡片式布局。当有两条列表项时,第一条列表项的上边角会是圆角,而第二条列表项的下边角会是圆角。最后,当列表中有多条记录时,除了第一条和最后一条列表项的首尾是圆角,中间的列表项将不再具有圆角,呈现出常规的矩形形状。这种设计可以为用户提供清晰的视觉层次感,使得界面看起来更为美观。 从标签“圆角 Listview 自定义 点击效果 布局”中,可以提取出以下关键知识点: 1. 圆角效果的实现:在Android中实现圆角效果,通常可以通过XML中的shape资源来定义。例如,可以在drawble资源文件中定义一个矩形形状,并通过设置其corners属性来赋予圆角。开发者还可以通过编程方式在代码中动态地绘制圆角,例如使用canvas类的drawRoundRect方法。 2. ListView的自定义:ListView是Android中用于展示滚动列表的基本组件。开发者可以通过自定义Adapter来改变ListView的每项布局。在本Demo中,需要根据列表项的数量来改变ListView中每个项的圆角属性,这通常意味着需要在Adapter的getView()方法中实现逻辑,来根据条件判断并设置相应的布局属性。 3. 点击效果:ListView中的每个列表项除了展示数据外,还可以响应用户的点击事件。在Android中,为ListView设置点击效果,通常需要为ListView设置一个OnItemClickListener。点击效果可以通过设置背景资源(比如按压状态的背景)或者通过定义动画资源来实现。 4. 布局的理解和使用:在Android开发中,布局文件负责定义界面的结构。XML布局文件通过使用各种布局容器(如LinearLayout, RelativeLayout, ConstraintLayout等)来组织界面元素。自定义ListView的布局可能需要对布局结构有深入的了解,以便根据需要调整布局的属性,实现期望的视觉效果。 结合压缩包子文件名称列表中的“CornerListviewDemo”,不难推断出该文件包含了上述Demo程序的源代码或者是相关的项目文件。在该文件中,开发者可以通过查看源代码来学习和理解如何实现自定义的ListView,特别是涉及到圆角、布局定制以及点击响应等方面。 总体来说,该Demo项目对于Android开发人员来说是一个很好的学习资源,可以从中学习如何进行UI组件的定制、布局优化以及交互效果的增强。对于希望通过代码优化提升用户体验的开发者而言,该项目具有一定的参考价值。
recommend-type

【图像处理新境界】:形态学滤波与tc itk的结合使用指南

# 摘要 本文系统阐述了形态学滤波技术的理论基础、应用实践以及ITK库和tcITK框架的概述与优化。首先介绍了形态学滤波的基本操作及其高级技术,接着详细说明了如何在ITK库中集成和应用形态学滤波器,并讨论了在图像处理中的具体案例。文章还介绍了tcITK框架,它为ITK提供了扩展和性能优化,以及在特
手机看
程序员都在用的中文IT技术交流社区

程序员都在用的中文IT技术交流社区

专业的中文 IT 技术社区,与千万技术人共成长

专业的中文 IT 技术社区,与千万技术人共成长

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

关注【CSDN】视频号,行业资讯、技术分享精彩不断,直播好礼送不停!

客服 返回
顶部