内存函数-C语言

 在之前学过一些内存函数, 但时间过了久了点就模糊了,甚至将其记忆成了字符串函数,现写篇博客记忆它。

memcpy

函数声明:
void * memcpy ( void * destination, const void * source, size_t num );

该函数的作用就是从source的位置开始向后复制num个字节的数据到destination指向的内存位置。

他操作的对象是内存,也就是说它不仅仅可以操作字符串,也可以操作其他类型的数据,接下来看代码:

#include<stdio.h>  
#include<stdlib.h>  
#include<string.h>  
  
int main()  
{  
    int arr1[12] = {1,2,3,4,5,6,7,8,9};  
    int arr2[2]; // 只分配两个int的空间  
    int* p = arr1;  
    int* q = arr2;  

    // 复制两个int元素(即8个字节,假设int是4字节)  
    memcpy(q, p, 2 * sizeof(int));  
  
    for (int i=0; i<2; i++) // 只遍历arr2的前两个元素  
    {  
        printf("%d ", arr2[i]);  
    }  
  
    return 0;  
}

这个函数将arr1的前两个元素值复制给了arr2,因而就对arr2进行了赋值,但是这个函数在遇到'\0'并不会停下来,并且这个函数存在一个风险,就是两个指针操作的地址如果存在相互重叠(相同地址)部分,那么函数结果就会是未定义的。

接下来是函数的实现:

void* own_memcpy(void* sou,const void* src,size_t num)
{
	void* ret = sou;
	while (num--)
	{
		*(char*)sou = *(char*)src;
		sou = (char*)sou + 1;//将内存数据以单个字节逐一传值
		src = (char*)src + 1;
	}
	return ret;
}

因为是操作内存,所以就要函数的逐一为每一个字节传值,而参数num就会是类型大小*元素个数了。在数据类型中只有char类型大小才是1个字节,并且对地址操作就要使用指针类型,那么这样就合理了。

​​​详见:memcpy - C++ 参考 (cplusplus.com)

memmove 

函数声明:

void * memmove ( void * destination, const void * source, size_t num );

该函数的作用跟memcpy函数的作用类似,但是此函数可以实现两个内存块上的重叠,因此源空间和目标空间上存在内存重叠,就只能用memmove函数来实现;

。使用示例:

#include <stdio.h>  
#include <string.h>  
  
int main() {  
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};  
    int *src = arr + 2; // 指向 arr[2],即值为3的元素  
    int *dest = arr; // 指向 arr 的开始位置  
  
    // 假设我们想要将 arr[2] 到 arr[4] (包含arr[4])复制到 arr 的开始位置  
    memmove(dest, src, 3 * sizeof(int));  
    
    for (int i = 0; i < 10; i++) 
    { 
        printf("%d ", arr[i]);  
    }  
    printf("\n");  
  
    return 0;  
}

上面讲过了memcpy函数,对此这里不必多说,直接实现一下:

void* own_memmove(void*destnation,const void* source,size_t num)
{
	
	void* ret = destnation;
		if (destnation<=source)
		{
			while (num--)
			{
				(char*)destnation = (char*)source;
				destnation=(char*)destnation+1;
				source = (char*)source+1;
			}
		}
		else
		{
			destnation = (char*)destnation + num - 1;//从末尾开始
			source = (char*)source + num - 1;
			while (num--)
			{
				*(char*)destnation = *(char*)source;
				destnation = (char*)destnation-1;
				source = (char*)source-1;
			}
		}
		return ret;
}

函数的复制分为两种情况,主要是针对内存的重叠情况,如果说源地址和目标地址之间存在重叠,并且源地址的起始位置在目标地址之前,那么就应该让函数从两个地址的结束位置开始从后往前赋值,否则采用从前往后赋值就会改变重叠部分,重叠部分也为源地址范围,这样会改变源地址的值

源地址采用const修饰为不可改变,那么编译器就会报错了。那么其余情况如内存间不存在重叠,或者存在重叠,但是源地址在目标地址之后,都可以从两个地址的起始位置从前往后赋值。

详见:memmove - C++ 参考 (cplusplus.com)

memset

函数声明:

void * memset ( void * ptr, int value, size_t num );

memset就是用来设置内存的值的,将内存的值设置为想要的值,

#include <stdio.h>
#include <string.h>

int main ()
{
  char str[] = "this is string!";
  memset (str,'-',6);
  puts (str);
  return 0;
}

在这里采用了int类型的参数值进行传递,但该函数使用此值的无符号字符转换填充内存块。,因此str数组的前6个字符元素变成'-'。

接下来代码的实现:

void* own_memset(void* ptr, int value, size_t num)
{
	unsigned char* p = (unsigned char*)ptr; // 转换为无符号字符指针
	while (num--)
	{
		*p = (unsigned char)value;
		p++;
	}
	return ptr;
}

在这里我们将其转换成char/unsigned类型进行赋值(char类型是1个字节)。

memset - C++ 参考 (cplusplus.com)

memcmp

函数声明如下:

int memcmp ( const void * ptr1, const void * ptr2, size_t num );

该函数是一个比较函数,目的为比较ptr1和ptr2指针指向位置开始,向后的num个字节,一旦比较出字符的不相等,就会返回值。由于memcmp函数不会改变某一内存的值,为了方便,我直接将函数的实现和memcmp原本的函数放在同一代码好中。

#include<string.h>
#include<stdio.h>
int own_memcmp(const void * ptr1,const void *ptr2,size_t num)
{
	while (num--)
	{
		if (*(char*)ptr1 == *(char*)ptr2)
		{
			ptr1 = (char*)ptr1 + 1;
			ptr2 = (char*)ptr2 + 1;
		}
		else
			return (char*)ptr1 - (char*)ptr2;

	}

}
//后者比较前者,如果后者大于前者 返回大于0数,相等返回0,小于0数


int main()
{
	char arr[20] = "Hello word ";
	char arr2[] = "Helloword";
	int a=own_memcmp(arr,arr2,7);//模拟函数在这
	printf("%s\n",arr);
	printf("%d\n", a);
	int b = memcmp(arr, arr2, 7);//这里为库里的memcmp函数使用
	printf("%d\n", b );

	return 0;
}

如果判断的值有不同的地方,就会直接将两个值相间的值返回,这很合理。

详见:memcmp - C++ 参考 (cplusplus.com)

在以上的强转类型中我都是用的是char/unsigned char,由于C语言引入stdint.h用于uint8_t  ,也可以将char/unsigned char改成uint8_t 。

以上就是博客全部内容,欢迎各位的观看、指正。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值