一:memcpy函数及实现
用于在内存中复制数据块。函数原型定义在 <string.h>
头文件中。其基本用法如下:
void *memcpy(void *dest, const void *src, size_t n);
这个函数的功能是从源(
src
)所指向的内存地址开始复制n
个字节到目标(dest
)所指向的内存地址。memcpy
函数会返回目标内存区域的指针。以下是
memcpy
函数的参数说明:
dest
:指向复制数据的目标内存地址的指针。src
:指向要复制的数据源内存地址的指针。n
:要复制的字节数。
使用 memcpy
时需要注意以下几点:
memcpy
函数不会检查源和目标内存区域是否有重叠,如果源和目标内存区域重叠,使用memcpy
可能会导致未定义的行为。在这种情况下,应该使用memmove
函数,它会正确处理重叠区域。- 使用
memcpy
时,确保目标内存区域有足够的空间来容纳源数据,以避免缓冲区溢出。
示例:
#include <stdio.h>
#include <string.h>int main() {
char src[50] = "Hello, World!";
char dest[50];// 使用 memcpy 复制字符串
memcpy(dest, src, strlen(src) + 1); // 加 1 是为了复制字符串结尾的空字符printf("Source: %s\n", src);
printf("Destination: %s\n", dest);return 0;
}
函数实现:
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* sur, size_t num)
{
void* ret = dest;//记录初始指针位置
assert(dest && sur);//确保非空
while (num--)//复制字节的次数
{
*(char*)dest = *(char*)sur;//先将void*强制类型转换为1字节大小的char*再逐字节复制;
dest = (char*)dest + 1;//指针移动一位//void*类型的指针本身不能进行自增自减和解引用操作,所以要强制类型转换;
sur = (char*)sur + 1;//指针移动一位;
}
return ret;返回dest初始指针位置
}
int main()
{
int a[] = { 1,2,3,4,5 };
int b[20] = { 0 };
my_memcpy(b, a, 20);
for (int i = 0; i < 20; i++)
{
printf("%d", b[i]);
}
二:memmove函数及实现
用于在内存中复制数据块,与 memcpy
类似,但是 memmove
能够正确处理源内存区域和目标内存区域重叠的情况。
void *memmove(void *dest, const void *src, size_t n);
这个函数的功能是从源(src
)所指向的内存地址开始复制n
个字节到目标(dest
)所指向的内存地址,即使源和目标内存区域有重叠也能正确复制。memmove
函数会返回目标内存区域的指针。以下是
memmove
函数的参数说明:
dest
:指向复制数据的目标内存地址的指针。src
:指向要复制的数据源内存地址的指针。n
:要复制的字节数。
memmove
函数返回一个指向目标内存区域的指针。
示例:
#include <stdio.h>
#include <string.h>int main() {
char str[] = "Hello World!";
// 将 "World" 复制到 "Hello" 的位置
memmove(str + 6, str, 5);printf("Resulting string: %s\n", str);
// 输出应为 "HelloHello!"return 0;
}
函数实现:
它有两种办法,一个是先将原字符串拷贝一份,再用这一份进行复制操作,不会造成覆盖的问题,但这样做浪费空间。推荐第二个办法:
可以总结得到结论,当des指针在sur之前从前往后复制不会产生覆盖,当des指针在sur之后,从后往前复制,不会产生覆盖。
代码实现:
void* my_memmove(void* dest, const void* sur, size_t num)
{
void* ret = dest;//记录指针初始位置
assert(dest && sur);//确保指针非空
if (dest < sur)//dest指针在sur之前时从前往后复制
{
while (num--)
{
*(char*)dest = *(char*)sur;
dest = (char*)dest + 1;
sur = (char*)sur + 1;
}
}
else//dest指针在sur之后,从后往前复制
{
while (num--)
{
*((char*)dest + num) = *((char*)sur + num);
}
}
return ret;//返回初始指针
}int main()
{
int a[] = { 1,2,3,4,5 };
my_memmove(a + 2, a, 12);
for (int i = 0; i < 5; i++) {
printf("%d", a[i]);
}
}
三:memset函数
memset
是 C 语言标准库中的一个函数,用于将指定的内存块中的所有字节设置为特定的值。这个函数通常用于初始化结构体、数组或内存缓冲区。
函数原型定义在 <string.h>
头文件中,如下所示:
void *memset(void *s, int c, size_t n);
s
:指向要设置值的内存块的指针。c
:要设置的值。这个值通常是一个整数值,但是因为memset
是按字节操作的,所以实际上只会使用c
的最低字节(即c & 0xFF
)。n
:要设置的内存块的字节数。
示例:
#include <stdio.h>
#include <string.h>int main() {
char str[50] = "This is a string for testing memset function.";// 将内存块的前20个字节设置为字符 'X'
memset(str, 'X', 20);printf("Modified string: %s\n", str);
// 输出应为 "XXXXXXXXXXXXXXXXXXXX for testing memset function."return 0;
}
//注意是逐个字节复制,而不是逐元素复制!
四:memcmp函数
memcmp
是 C 语言标准库中的一个函数,用于比较两个内存区域的前 n
个字节。它逐字节比较两个内存块,并根据比较结果返回一个整数值。
函数原型定义在 <string.h>
头文件中,如下所示:
int memcmp(const void *s1, const void *s2, size_t n);
s1
:指向第一个内存区域的指针。s2
:指向第二个内存区域的指针。n
:要比较的字节数。- 如果两个内存区域完全相同,返回0。
- 如果在比较过程中,
s1
指向的内存区域中的某个字节大于s2
指向的内存区域中的对应字节,返回一个正整数。- 如果在比较过程中,
s1
指向的内存区域中的某个字节小于s2
指向的内存区域中的对应字节,返回一个负整数。
示例:
#include <stdio.h>
#include <string.h>int main() {
const char *str1 = "Hello, World!";
const char *str2 = "Hello, C World!";
size_t n = 7; // 比较前7个字符int result = memcmp(str1, str2, n);
if (result == 0) {
printf("The first %zu bytes of the strings are equal.\n", n);
} else if (result < 0) {
printf("The first differing byte in str1 is less than in str2.\n");
} else {
printf("The first differing byte in str1 is greater than in str2.\n");
}return 0;
}
在这个例子中,我们比较两个字符串 str1
和 str2
的前7个字符。由于前7个字符在这两个字符串中是相同的,所以 memcmp
将返回0。