目录
简介: 在C语言中,有一些函数被广泛用于处理内存操作。其中,memcpy、memmove、memset和memcmp是四个常用的函数,它们在处理字符串和内存拷贝、移动和比较方面起着重要作用。本文将详细介绍这四个函数的用法,实现和区别,帮助读者更好地理解和使用它们。
-
1.memcpy函数: memcpy函数用于将源内存区域的内容复制到目标内存区域。其函数原型如下:
void *memcpy(void *dest, const void *src, size_t n);
其中,dest是目标内存区域的指针,src是源内存区域的指针,n是要复制的字节数。该函数返回指向dest的指针。
自定义memcpy函数的实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include <assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(src && dest);
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[20] = { 0 };
my_memcpy(arr2, arr1, 21);
int i = 0;
for (i = 0; i < 20; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
使用了两个指针变量
dest和src来遍历内存区域,并逐字节地将源内存区域的内容复制到目标内存区域。通过一个循环,遍历
num个字节,将src中的内容逐字节复制到dest中,然后将指针dest和src分别向后移动一个字节。

-
2.memmove函数: memmove函数与memcpy函数类似,也用于内存区域的复制,但其处理方式更为安全,能够处理重叠内存区域的拷贝。其函数原型如下:
void *memmove(void *dest, const void *src, size_t n);
与memcpy函数不同的是,memmove函数保证在重叠拷贝时不会出现问题。这是因为memmove会先将源内存区域的内容拷贝到临时区域,然后再将临时区域的内容复制到目标内存区域。
自定义memmove函数的实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include <assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(dest && src);
if (dest < src)
{
//前->后
while (num--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else
{
//后->前
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
}
}
return ret;
}
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
my_memmove(arr1, arr1+1, 20);
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
通过比较目标地址和源地址的大小,确定是从前向后移动还是从后向前移动。
如果目标地址小于源地址,即从前向后移动,使用一个循环,将源地址的数据逐个复制到目标地址中,并且每次复制后,目标地址和源地址都分别向后移动一个字节。
如果目标地址大于等于源地址,即从后向前移动,同样使用一个循环,从后向前复制数据。
在
main函数中,定义了一个整型数组arr1,包含了一些整数。调用
my_memmove函数,将arr1+1(即数组的第二个元素地址)开始的20个字节的数据移动到arr1中。然后,通过一个循环输出移动后的arr1数组的元素。

-
3.memset函数: memset函数主要用于将指定的内存区域填充为给定的值。这些值可以是字符、整型数字或其他类型的数据。其函数原型如下:
-
void *memset(void *ptr, int value, size_t num);其中,ptr是指向要填充的内存区域的指针,value是要填充的值,num是要填充的字节数。该函数返回指向ptr的指针。
自定义memset函数的实现:
#include <stdio.h> #include <assert.h> void* my_memset(void* ptr, int value, size_t num) { assert(ptr != NULL); unsigned char* p = (unsigned char*)ptr; unsigned char val = (unsigned char)value; for (size_t i = 0; i < num; i++) { p[i] = val; } return ptr; } int main() { char str[20] = "Hello World"; my_memset(str, '*', 5); printf("填充后的字符串为: %s\n", str); return 0; }在自定义的my_memset函数中,首先使用assert断言来确保传入的指针ptr不为空。
然后将ptr强制转换为unsigned char指针类型,并将value强制转换为unsigned char类型,以确保按字节进行填充。
接下来,使用一个循环遍历num次,将value的值复制到ptr指向的内存区域中。
最后,返回指向ptr的指针。
-

-
4.memcmp函数: memcmp函数用于比较两个内存区域的内容是否相等。其函数原型如下:
int memcmp(const void *s1, const void *s2, size_t n);
其中,s1和s2是要比较的两个内存区域的指针,n是要比较的字节数。该函数返回一个整数值,表示两个内存区域的比较结果。如果返回值为0,则表示两个内存区域相等;如果返回值小于0,则表示s1小于s2;如果返回值大于0,则表示s1大于s2。
自定义memset函数的实现:
#include <stdio.h>
int my_memcmp(const void* s1, const void* s2, size_t num) {
const unsigned char* p1 = (const unsigned char*)s1;
const unsigned char* p2 = (const unsigned char*)s2;
for (size_t i = 0; i < num; i++) {
if (p1[i] < p2[i]) {
return -1;
} else if (p1[i] > p2[i]) {
return 1;
}
}
return 0;
}
int main() {
char str1[] = "Hello";
char str2[] = "Hello";
int result = my_memcmp(str1, str2, sizeof(str1));
if (result == 0) {
printf("字符串相等\n");
} else if (result < 0) {
printf("str1 小于 str2\n");
} else {
printf("str1 大于 str2\n");
}
return 0;
}
将传入的指针s1和s2都强制转换为const unsigned char类型,以确保按字节进行比较。
接下来,我们使用一个循环遍历num次,逐字节比较两个内存区域的内容。
如果发现p1中的某个字节小于p2中的相应字节,则返回-1表示p1小于p2。
如果发现p1中的某个字节大于p2中的相应字节,则返回1表示p1大于p2。
如果所有字节都相等,则返回0表示两个内存区域相等。

总结:
memcpy函数用于内存的拷贝,是最常用的内存操作函数之一。
memmove函数也用于内存的拷贝,但能够处理重叠内存区域的拷贝。
memset函数用于将内存区域的每个字节设置为指定的值。
memcmp函数用于比较两个内存区域的内容是否相等。
在使用这些函数时,需要注意以下几点:
确保源和目标内存区域的大小合适,避免越界访问。
对于可能存在内存重叠的情况,使用memmove而不是memcpy函数。
确保目标内存区域的大小足够容纳要填充的字节数,避免越界访问。
在对字符数组进行填充时,确保数组末尾有一个空字符(‘\0’)来表示字符串的结束。
比较内存区域时,确保比较的内存大小一致,避免比较超出范围。
通过对memcpy、memmove、memset和memcmp函数的了解,我们可以更高效地处理字符串和内存操作,提高程序的性能和安全性。
5934

被折叠的 条评论
为什么被折叠?



