关于数组[ ]的复制与对比(memcpy & memcmp)
·
memcpy 和 memcmp 函数用法详解
1. memcpy 函数
函数原型
void *memcpy(void *dest, const void *src, size_t n);
功能
将 src 指向的内存区域的 n 个字节复制到 dest 指向的内存区域。源和目标内存区域不能重叠,如果重叠应该使用 memmove。
参数
-
dest:目标内存地址指针 -
src:源内存地址指针 -
n:要复制的字节数
使用示例
示例1:复制整型数组
#include <stdio.h>
#include <string.h>
int main(void)
{
int src[5] = {1, 2, 3, 4, 5};
int dest[5];
// 复制整个数组
memcpy(dest, src, sizeof(src));
}
示例2:复制部分数据
#include <stdio.h>
#include <string.h>
int main(void)
{
char src[] = "Hello, World!";
char dest[20];
// 只复制前5个字符(不包括字符串结束符)
memcpy(dest, src, 5);
}
示例3:复制结构体
#include <stdio.h>
#include <string.h>
typedef struct {
int id;
char name[20];
float score;
} Student;
int main(void)
{
Student student1 = {1, "张三", 85.5};
Student student2;
// 复制整个结构体
memcpy(&student2, &student1, sizeof(Student));
}
示例4:从数组中间复制数据
#include <stdio.h>
#include <string.h>
int main(void)
{
int src[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int dest[5];
// 从src的第3个元素开始复制5个元素
memcpy(dest, &src[2], 5 * sizeof(int));
}
示例5:复制到数组中间
#include <stdio.h>
#include <string.h>
int main(void)
{
int data[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int new_data[3] = {10, 11, 12};
// 将new_data复制到data的第4个位置开始
memcpy(&data[3], new_data, sizeof(new_data));
}
2. memcmp 函数
函数原型
int memcmp(const void *s1, const void *s2, size_t n);
功能
比较 s1 和 s2 指向的内存区域的前 n 个字节。
参数
-
s1:第一个内存区域指针 -
s2:第二个内存区域指针 -
n:要比较的字节数
返回值
-
返回 0:两个内存区域的前
n个字节完全相同 -
返回 <0:第一个不同的字节,在
s1中的值小于s2中的值(按无符号字符比较) -
返回 >0:第一个不同的字节,在
s1中的值大于s2中的值(按无符号字符比较)
使用示例
示例1:比较整型数组
#include <stdio.h>
#include <string.h>
int main(void)
{
int arr1[5] = {1, 2, 3, 4, 5};
int arr2[5] = {1, 2, 3, 4, 5};
int arr3[5] = {1, 2, 3, 4, 6};
// 比较arr1和arr2
if(memcmp(arr1, arr2, sizeof(arr1)) == 0) {
printf("arr1 和 arr2 完全相等\n");
} else {
printf("arr1 和 arr2 不相等\n");
}
// 比较arr1和arr3
int result = memcmp(arr1, arr3, sizeof(arr1));
if(result == 0) {
printf("arr1 和 arr3 完全相等\n");
} else if(result < 0) {
printf("arr1 小于 arr3\n"); // 因为5 < 6
} else {
printf("arr1 大于 arr3\n");
}
}
示例2:比较字符串(包括非字符串数据)
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[] = "Hello";
char str2[] = "Hello";
char str3[] = "Hellp"; // 最后字符是'p'而不是'o'
char str4[] = "Hell"; // 少一个字符
// 比较str1和str2的前5个字符
if(memcmp(str1, str2, 5) == 0) {
printf("str1 和 str2 前5个字符相等\n");
}
// 比较str1和str3
int result = memcmp(str1, str3, 5);
if(result < 0) {
printf("str1 小于 str3,因为 'o'(0x6F) < 'p'(0x70)\n");
}
// 比较str1和str4的前4个字符
if(memcmp(str1, str4, 4) == 0) {
printf("str1 和 str4 前4个字符相等\n");
}
return 0;
}
示例3:比较结构体
#include <stdio.h>
#include <string.h>
typedef struct {
int id;
char name[10];
float score;
} Student;
int main(void)
{
Student stu1 = {1, "张三", 85.5};
Student stu2 = {1, "张三", 85.5};
Student stu3 = {1, "张三", 90.0};
// 比较两个结构体
if(memcmp(&stu1, &stu2, sizeof(Student)) == 0) {
printf("stu1 和 stu2 完全相等\n");
}
// 比较stu1和stu3
int result = memcmp(&stu1, &stu3, sizeof(Student));
if(result != 0) {
printf("stu1 和 stu3 不相等\n");
// 注意:浮点数比较可能会因为内存表示不同而显示不相等,即使数值相等
}
return 0;
}
示例4:比较数组的部分数据
#include <stdio.h>
#include <string.h>
int main(void)
{
unsigned char data1[10] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A};
unsigned char data2[10] = {0x01, 0x02, 0x03, 0x04, 0xFF, 0x06, 0x07, 0x08, 0x09, 0x0A};
// 比较前4个字节
if(memcmp(data1, data2, 4) == 0) {
printf("前4个字节相等\n");
}
// 比较前5个字节
int result = memcmp(data1, data2, 5);
if(result < 0) {
printf("第5个字节不同: 0x05 < 0xFF\n");
}
// 比较整个数组
result = memcmp(data1, data2, sizeof(data1));
if(result != 0) {
printf("整个数组不相等\n");
}
}
示例5:与 strcmp 的区别
#include <stdio.h>
#include <string.h>
int main(void)
{
char str1[] = "Hello";
char str2[] = "Hello\0World"; // 后面还有内容
char str3[] = "Hell"; // 少一个字符
// 使用strcmp比较(遇到\0停止)
printf("strcmp(str1, str2) = %d\n", strcmp(str1, str2)); // 0,因为\0前的内容相同
// 使用memcmp比较指定字节数
printf("memcmp(str1, str2, 6) = %d\n", memcmp(str1, str2, 6)); // 可能非0,比较包括\0
// 比较不同长度的字符串
printf("strcmp(str1, str3) = %d\n", strcmp(str1, str3)); // >0,因为"Hello" > "Hell"
// memcmp需要指定长度
printf("memcmp(str1, str3, 4) = %d\n", memcmp(str1, str3, 4)); // 0,前4个字符相同
printf("memcmp(str1, str3, 5) = %d\n", memcmp(str1, str3, 5)); // >0,第5个字符不同
}
3. 注意事项
memcpy 注意事项
// 1. 内存重叠问题
char str[] = "Hello, World!";
// 错误:源和目标有重叠
// memcpy(str + 7, str, 7); // 未定义行为
// 正确:使用memmove处理重叠
memmove(str + 7, str, 7);
// 2. 缓冲区溢出
int dest[5];
int src[10] = {1,2,3,4,5,6,7,8,9,10};
// 错误:目标缓冲区太小
// memcpy(dest, src, sizeof(src)); // 缓冲区溢出!
// 正确:确保目标缓冲区足够大
memcpy(dest, src, sizeof(dest));
// 3. 复制对象包含指针
typedef struct {
char *name;
int age;
} Person;
Person p1 = {malloc(20), 25};
strcpy(p1.name, "John");
Person p2;
// 注意:这只会复制指针,不会复制指针指向的数据
memcpy(&p2, &p1, sizeof(Person));
// p2.name 和 p1.name 指向同一块内存!
memcmp 注意事项
// 1. 浮点数比较问题
float f1 = 1.0f;
float f2 = 1.0f;
// 注意:浮点数在内存中的表示可能不完全相同
// memcmp(&f1, &f2, sizeof(float)) 可能返回非0,即使数值相等
// 2. 结构体填充字节问题
typedef struct {
char c;
int i;
} MyStruct;
MyStruct s1 = {'A', 10};
MyStruct s2 = {'A', 10};
// 结构体可能有填充字节,这些字节的值是不确定的
// memcmp(&s1, &s2, sizeof(MyStruct)) 可能返回非0,即使成员值相同
// 3. 比较带指针的结构体
typedef struct {
char *ptr;
int value;
} Data;
Data d1 = {NULL, 10};
Data d2 = {NULL, 10};
// memcmp(&d1, &d2, sizeof(Data)) 会比较指针值,即使都指向NULL
// 但不同的NULL指针在比较时可能产生非0结果
4. 性能提示
-
memcpy通常比手动循环快:因为编译器会进行优化,甚至使用硬件加速
-
对齐访问:如果数据是按字对齐的,memcpy/memcmp性能更好
-
小数据量:对于非常小的数据(几个字节),手动循环可能更快
-
编译器优化:现代编译器对memcpy/memcmp有很好的优化
更多推荐

所有评论(0)