C 语言内存操作函数入门:memcpy、memmove、memset、memcmp
·
作为 C 语言初学者,我们经常需要对一块内存进行复制、移动、填充或比较等操作。虽然 C 语言标准库提供了强大的字符串处理函数(如strcpy、strcmp),但它们只能处理以'\0'结尾的字符数组。当我们需要处理任意二进制数据(如结构体、数组)时,就需要用到今天要介绍的四个内存操作函数:memcpy、memmove、memset和memcmp。
1. memcpy 使用和模拟实现
函数介绍
memcpy 用于从源内存块复制指定数量的字节到目标内存块。它的函数原型如下:
void *memcpy(void *dest, const void *src, size_t n);
- dest: 指向目标内存块的指针。
- src: 指向源内存块的指针(
const表示源数据不会被修改)。 - n: 要复制的字节数。
- 返回值: 返回指向目标内存块
dest的指针。
使用示例
#include <stdio.h>
#include <string.h>
int main() {
char src[] = "Hello, memcpy!";
char dest[20] = {0};
// 复制前13个字节
memcpy(dest, src, 13);
printf("复制后的 dest: %s\n", dest); // 输出: Hello, memcpy!
int arr1[] = {1, 2, 3, 4, 5};
int arr2[5] = {0};
// 复制整个数组
memcpy(arr2, arr1, sizeof(arr1));
for (int i = 0; i < 5; i++) {
printf("%d ", arr2[i]); // 输出: 1 2 3 4 5
}
return 0;
}
注意事项
memcpy假设源和目标内存区域不重叠。如果内存区域重叠,行为是未定义的,此时应使用memmove。- 它不检查目标缓冲区的大小,因此必须确保目标缓冲区足够大,以容纳
n个字节,否则会导致缓冲区溢出。
模拟实现
我们可以自己实现一个简单的 memcpy 来理解其工作原理:
void *my_memcpy(void *dest, const void *src, size_t n) {
// 检查指针有效性
if (dest == NULL || src == NULL) {
return NULL;
}
// 为了避免修改指针本身,我们用临时指针
char *d = (char *)dest;
const char *s = (const char *)src;
while (n--) {
*d++ = *s++;
}
return dest;
}
2. memmove 使用和模拟实现
函数介绍
memmove 和 memcpy 功能非常相似,都是复制内存。关键区别在于,memmove 可以安全地处理重叠的内存区域。
void *memmove(void *dest, const void *src, size_t n);
为什么需要 memmove?
想象一下,如果源地址 src 小于目标地址 dest,并且它们的内存区域有重叠。如果我们像 memcpy 那样从低地址向高地址复制,就会覆盖掉还没复制的源数据。memmove 会根据地址关系选择复制方向,从而避免这个问题。
使用示例
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "abcdefghij";
// 从 str+2 复制 5 个字节到 str+5,内存区域重叠
memmove(str+5, str+2, 5);
printf("%s\n", str); // 输出: abcde cdehij
return 0;
}
模拟实现
void *my_memmove(void *dest, const void *src, size_t n) {
if (dest == NULL || src == NULL) {
return NULL;
}
char *d = (char *)dest;
const char *s = (const char *)src;
// 如果目标地址在源地址之后,且有重叠,从后往前复制
if (d > s && d < s + n) {
d += n - 1;
s += n - 1;
while (n--) {
*d-- = *s--;
}
} else {
// 否则从前往后复制
while (n--) {
*d++ = *s++;
}
}
return dest;
}
3. memset 函数的使用
函数介绍
memset 用于将一块内存的前 n 个字节设置为指定的值。它通常用于初始化内存。
void *memset(void *ptr, int value, size_t n);
- ptr: 指向要填充的内存块。
- value: 要设置的值。虽然是
int类型,但实际会被转换为unsigned char填充到每个字节。 - n: 要设置的字节数。
使用示例
#include <stdio.h>
#include <string.h>
int main() {
char buffer[10];
// 将 buffer 的所有字节设置为 'A'
memset(buffer, 'A', sizeof(buffer));
for (int i = 0; i < 10; i++) {
printf("%c ", buffer[i]); // 输出: A A A A A A A A A A
}
printf("\n");
int arr[5];
// 将数组 arr 清零
memset(arr, 0, sizeof(arr));
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]); // 输出: 0 0 0 0 0
}
return 0;
}
注意事项
memset是按字节填充的。因此,如果你想初始化一个int数组为1,直接使用memset(arr, 1, sizeof(arr))是错误的,它会把每个字节都设为0x01,导致每个int变成0x01010101(十进制 16843009)。
4. memcmp 函数的使用
函数介绍
memcmp 用于比较两块内存区域的前 n 个字节。它按字节逐位比较。
int memcmp(const void *ptr1, const void *ptr2, size_t n);
- 返回值:
< 0:ptr1指向的内存块小于ptr2指向的内存块。= 0: 两个内存块的前n个字节完全相同。> 0:ptr1指向的内存块大于ptr2指向的内存块。
使用示例
#include <stdio.h>
#include <string.h>
int main() {
char str1[] = "Hello";
char str2[] = "Helium";
// 比较前3个字节
int result1 = memcmp(str1, str2, 3);
if (result1 == 0) {
printf("str1 和 str2 的前3个字节相同\n"); // 输出此句
}
int arr1[] = {1, 2, 3};
int arr2[] = {1, 2, 4};
// 比较整个数组
int result2 = memcmp(arr1, arr2, sizeof(arr1));
if (result2 < 0) {
printf("arr1 小于 arr2\n"); // 输出此句
}
return 0;
}
总结
| 函数 | 功能 | 关键特点 |
|---|---|---|
memcpy |
内存复制 | 不处理重叠区域,速度快 |
memmove |
内存移动 | 安全处理重叠区域 |
memset |
内存填充 | 按字节初始化内存 |
memcmp |
内存比较 | 按字节逐位比较 |
掌握这四个函数,能让你在处理 C 语言中的内存数据时更加得心应手。它们是构建更复杂数据结构和算法的基础工具。
更多推荐
所有评论(0)