内存操作函数

内存操作函数也是在<string.h>头文件中的

四个内存函数:
memcpy(内存拷贝)
memmove(内存移动)
memcmp(内存比较)
memset(内存设置)

memcpy

void * memcpy ( void * dst, const void * src, size_t num );

函数功能:函数memcpy从src的位置开始向后复制num个字节的数据到dst的内存位置。num是字节数。

这个函数在遇到 ‘\0’ 的时候并不会停下来。不管是什么数据类型,它都能来;strcpy只能针对字符串
要保证dst有足够的容量能容纳src。

如果src和dst有任何的重叠,复制的结果都是未定义的。
C 学习笔记 —— 内存操作函数-LMLPHP

实例

#include <stdio.h>
#include <string.h>
 
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, 5 * sizeof(int));//拷贝5个整型进去
    for (int i = 0; i < 5; i++)
    {
        printf("arr2[%d]=%d ,", i, arr2[i]);
    }
    printf("\n");
    
 
	float str1[] = { 1.0f,2.0f,3.0f,4.0f };//如果不写f编译器会把他当成double类型的数据
	float str2[5] = { 0.0 };
	memcpy(str2, str1, 8 * sizeof(float));
    for (int i = 0; i < 8; i++)
    {
        printf("str2[%d]=%f ,", i, str2[i]);
    }
	return 0;
}

memmove

void * memmove ( void* dst, const void* src, size_t num );

函数功能:memmove和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。

如果源空间和目标空间出现重叠,就得使用memmove函数处理。

num是字节个数。

memmove的复制过程就好像是将src中的字节首先被复制到一个不重叠的临时数组中,然后将字节从临时数组复制到dest。

内存重叠问题

#include <stdio.h>
#include <string.h>
 
int main(){
	int d[10]={1,2,3,4,5,6,7,8,9,10};
	memcpy(d+3, d, 7*sizeof(int));// 注意第三函数为字节数
	for(int i=0;i<10;i++){
		printf("%d ", d[i]);
	}
	return 0;
}
/*输出
1 2 3 1 2 3 4 5 6 7
*/

这里的结果虽然是预期的,可能是在最新版本中解决了,但是这个是不可靠的,也就是这里可能存在问题,结果不符合预期,因为memcpy不保证内存重叠部分的正确性。所以这里应该使用memmove

memcmp

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

比较从ptr1和ptr2指针开始的num个字节,注意这里的比较是每个byte逐一比较

返回的结果=0,表示ptr1和ptr2的相等,
返回结果为>0,表示ptr1比ptr2的大,
返回结果为<0,表示ptr1比ptr2的小。

num是比较的字节的个数

void*又暗示着参数可以是任意类型
strncmp只能比较字符串的大小;而memcmp可以比较任意类型

实例

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

int main()

{
    int arr1[] = { 1,2,3,4,5 };
    int arr2[] = { 1,2,5,4,3 };
    //在内存中的存储,小端存储模式,十六进制表示,两个数一组表示一个byte
    //01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
    //01 00 00 00 02 00 00 00 05 00 00 00 04 00 00 00 03 00 00 00

    //int ret = memcmp(arr1, arr2, 8);//num = 8,表示8个字节的大小。这里比较数组中前两个数字。 =0
    int ret = memcmp(arr1, arr2, 9);//num = 9,表示9个字节的大小。 = -2

    printf("ret = %d\n", ret); //-2
    return 0;
}

返回值-2表示pt1<pt2

memset

void *memset( void *dst, int c, size_t num );

将缓冲区设置为指定的字符,num是字节的个数,一个字节一个字节的改。
返回类型是一个指向存储区dst的指针
memset是一个初始化函数,作用是将某一块内存中的全部设置为指定的值。

其实c的实际范围应该在0~255,因为memset函数只能取c的后八位给所输入范围的每个字节。也就是说无论c多大只有后八位二进制是有效的。

不能任意赋值

注意memset函数是按照字节对内存块进行初始化,所以不能用它将int数组初始化为0和-1之外的其他值(除非该值高字节和低字节相同)。初始化其他值可能并不是预期的结果,请看下面这个例子

    int a[] = { 1,2,3,4,5 };
	memset(a, 1, 5*sizeof(int));
 
	for (int i = 0; i < 5; i++)
		printf("%d ", a[i]);
    //16843009 16843009 16843009 16843009 16843009
    printf("\n");

我想把数组元素全部设置为1,但实际上得到的却是非预期值
原因:
数组a是整型的,整型大小为4Byte,而memset函数是按照字节为单位进行赋值,取后8位,将1(00000001)赋给每一个字节。那么对于a[0]来说,其值为(00000001 00000001 00000001 00000001),即十进制的16843009。

-1或者0则没问题

 int a[] = { 1,2,3,4,5 };
	memset(a, 0, 5*sizeof(int));//0 0 0 0 0 
    memset(a, -1, 5*sizeof(int));//-1 -1 -1 -1 -1 
	for (int i = 0; i < 5; i++)
		printf("%d ", a[i]);

    return 0;

字符数组也没问题,因为memset是按1byte来修改的

    char a[5];
	memset(a, 'd', 5); //d d d d d

	for (int i = 0; i < 5; i++)
		printf("%c ", a[i]);

    return 0;

https://blog.csdn.net/weixin_44162361/article/details/115790452

参考资料

https://blog.csdn.net/m0_68814541/article/details/127334335
https://blog.csdn.net/weixin_56810796/article/details/128308824

05-22 01:34