``` /*********** 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的功能上面我写的代码有哪些问题?
首先看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,导致指针移动不正确。
- 缺少对比较字节数的控制:循环没有检查已经比较了多少字节,可能导致越界或比较不足。
- 处理所有字节相等的情况不正确:在比较完所有字节后未正确返回0。
- 返回值逻辑问题:当所有字节都相等时,循环结束后错误地进行比较,而实际上应该返回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);
注意事项:
int
类型通常占4字节,比较17字节相当于比较:- 前4个int(16字节)
- 第5个int的第一个字节
- 当使用修正后的代码时:
- 前16字节相同(1,2,3,4的二进制表示)
- 第17字节比较
5
的二进制第1字节 vs0x01
正确输出:由于0x01
小于0x05
,应该返回1
通过以上修正,你的函数可以正确实现标准库memcmp
的以下特性:
- 按字节比较内存内容
- 严格比较
num
个字节 - 返回值的符号反映差异字节的大小关系
相关推荐

















