C memmove 函数
最后修改:2025 年 4 月 8 日
内存操作在 C 编程中是基础性的,而 memmove
是一个用于在内存位置之间安全复制数据的函数。本教程将深入介绍 memmove
,包括其语法、用法以及相对于 memcpy
的优势。我们将通过实际示例来展示它如何安全地处理重叠的内存区域。理解 memmove
有助于编写健壮的程序,避免内存操作中的未定义行为。
什么是 memmove?
memmove
函数安全地将一个内存块从一个位置复制到另一个位置。它在 string.h
中声明,并接受三个参数:目标指针、源指针以及要复制的字节数。memmove
通过在复制前检查内存范围来正确处理重叠的内存区域。与 memcpy
不同,即使源缓冲区和目标缓冲区重叠,它也能保证正确的行为。
memmove 的基本用法
本示例演示了如何使用 memmove
在两个数组之间复制数据。
#include <stdio.h> #include <string.h> int main() { char src[] = "Hello, World!"; char dest[20]; // Copy 14 bytes (including null terminator) memmove(dest, src, 14); printf("Source: %s\n", src); printf("Destination: %s\n", dest); return 0; }
在此,memmove
将 14 个字节从 src
复制到 dest
,包括空终止符。当缓冲区不重叠时,该函数的作用类似于 memcpy
。目标缓冲区必须足够大才能容纳复制的数据。这是在不确定潜在重叠的情况下安全复制内存的方法。
处理重叠内存区域
本示例演示了 memmove
正确处理重叠区域的能力。
#include <stdio.h> #include <string.h> int main() { char data[] = "ABCDEFGHIJ"; // Move data within the same buffer (overlapping) memmove(data + 2, data, 5); printf("Result: %s\n", data); return 0; }
这段代码可以安全地复制数据,即使源和目标重叠。memmove
会检查内存范围并以正确的方向复制,以保持数据完整性。输出将是“ABABCDEFIJ”,因为前 5 个字节是从位置 2 开始复制的。这种行为是有保证的,并且在不同平台之间是可移植的。
移动数组元素
本示例展示了如何使用 memmove
在数组内移动元素。
#include <stdio.h> #include <string.h> int main() { int nums[] = {1, 2, 3, 4, 5, 6, 7, 8}; size_t count = sizeof(nums)/sizeof(nums[0]); // Shift elements left by 2 positions memmove(nums, nums + 2, (count - 2) * sizeof(int)); printf("Shifted array: "); for (size_t i = 0; i < count - 2; i++) { printf("%d ", nums[i]); } printf("\n"); return 0; }
在此,memmove
将数组元素向左移动两个位置。该函数能正确处理重叠的源和目标区域。大小计算使用了 (count - 2) * sizeof(int)
来获取正确的字节数。移动后,数组的前六个位置包含 {3,4,5,6,7,8}。
使用 memmove 复制结构体
memmove
可以安全地复制结构体,即使它们可能重叠。
#include <stdio.h> #include <string.h> typedef struct { int id; char name[20]; float score; } Student; int main() { Student students[3] = { {101, "Alice", 95.5}, {102, "Bob", 88.0}, {103, "Charlie", 91.2} }; // Move second student to first position memmove(&students[0], &students[1], sizeof(Student)); printf("First student is now: %s\n", students[0].name); return 0; }
本示例使用 memmove
在数组内移动一个 Student
结构体。sizeof(Student)
确保我们复制了所需的精确字节数。由于源和目标在同一个数组中,因此 memmove
是正确的选择。执行后,第一个数组元素包含 Bob 的数据。
实现循环缓冲区
本示例演示了如何在循环缓冲区实现中使用 memmove
。
#include <stdio.h> #include <string.h> #define BUF_SIZE 16 void add_to_buffer(char *buf, size_t *count, char data) { if (*count == BUF_SIZE) { // Make room by shifting left memmove(buf, buf + 1, BUF_SIZE - 1); (*count)--; } buf[(*count)++] = data; } int main() { char buffer[BUF_SIZE] = {0}; size_t count = 0; // Fill the buffer for (char c = 'A'; c < 'Q'; c++) { add_to_buffer(buffer, &count, c); } // Add one more, causing a shift add_to_buffer(buffer, &count, 'Q'); printf("Buffer: %.*s\n", (int)count, buffer); return 0; }
这段代码使用 memmove
在缓冲区已满时移动元素,从而实现了一个简单的循环缓冲区。该函数维护最近的 BUF_SIZE
个字符。当添加 'Q' 时,它会将所有字符向左移动以腾出空间。输出显示“BCDEFGHIJKLMNOPQ”——第一个 'A' 被丢弃以保持缓冲区大小。
使用 memmove 的最佳实践
- 优先于 memcpy: 不确定内存重叠时,请使用
memmove
。 - 检查缓冲区大小: 确保目标有足够的空间容纳移动的数据。
- 使用正确的尺寸: 使用
sizeof
仔细计算字节数。 - 验证指针: 确保源指针和目标指针都有效。
- 考虑性能:
memmove
可能比memcpy
稍慢。
来源
本教程从基本用法到高级内存操作,全面介绍了 memmove
函数。它处理重叠区域的能力使其比 memcpy
在许多用例中更安全。在 C 中处理低级操作时,请始终考虑内存安全。
作者
列表 C 标准库。