详解C语言的mem系列函数

目录
  • 1.memchr
  • 2.memcmp
  • 4.memmove
  • 5.memset
  • 总结

1.memchr

memchr的函数声明:

void *memchr(const void *str, int c, size_t n);

作用:

memchr函数从str位置后的n个位置开始寻找,寻找第一个和c相同的字符。如果成功,memchr函数返回一个指向该字符位置的指针,如果没有没有找到指定字符,则返回NULL。

实例:

#include <stdio.h>
#include <string.h>
int main()
{
	const char* a = "my blog";
	if (memchr(a, 'g', 7) != NULL)
		printf("g is found\n");
	if (memchr(a, 'g', 2) != NULL)
		printf("g is found\n");
	return 0;
}

函数的实现:

​void* my_memchr(const char* str,int c,size_t n)
{
	assert(str != NULL);
	while ((n--) && (*(str++) - c));
	if (!(*str - c))
		return NULL;
	return str;
}

注意事项:形参中的c是一个无符号字符。

2.memcmp

函数的声明:

int memcmp( const void *buf1, const void *buf2, size_t count );

作用:

memcmp用于比较buf1 和 buf2 的前count个字节进行比较,如果buf1大于buf2,该函数返回一个正数,如果小于则返回一个负数,相等则返回0。

实例:

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

int main()
{
    char str1[15];
    char str2[15];
    int ret;
    memcpy(str1, "aBcDDDD", 8);
    memcpy(str2, "aBCdddd", 8);
    ret = memcmp(str1, str2, 7);
    printf("%s ", str1);
    if (ret > 0)
        printf("大于");
    else if (ret < 0)
        printf("小于");
    else
        printf("等于");
    printf(" %s\n", str2);
    return 0;
}

函数的实现:

首先我们需要了解memcmp是怎么比较大小的。通过不断地调整上面实例的两个字符串,我发现,该函数是从第一个字节开始比较,如果相同,则继续比较下一个字节,如果有大小差异,则将这两个字节的大小差异作为结果输出。

int my_memcmp(const void* buf1,const void *buf2,size_t count)
{
    assert(buf1 && buf2);
    while ((count--) && !(*(((char*)buf1)++) - *(((char*)buf2)++)));
    return *(--(char*)buf1) - *(--(char*)buf2);//这里要 -- 是因为上面的最后还++了一下
}

3.memcpy

函数的声明:

void *memcpy( void *dest, const void *src, size_t count );

作用:

该函数将 src 的 count 个字节复制到 dest。该函数返回 dest 的起始位置。

实例:

#include <stdio.h>
#include <string.h>
int main()
{
	char arr[50] = { 0 };
	char* b = "csdn.com";
	memcpy(arr, b, strlen(b));
	printf("%s", arr);
	return 0;
}

函数的实现:

void* my_memcpy(void* a, const void* b, size_t count)
{
	assert(a && b);
	void* ret = a;
	while (count--)
	{
		*(char*)a = *(char*)b;
		a = (char*)a + 1;
		b = (char*)b + 1;
	}
	return ret;
}

4.memmove

函数声明:

void *memmove( void *dest, const void *src, size_t count );

作用:

该函数的作用和memcpy类似。但是为什么会有memmove呢?

我们看下面这段代码

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

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memcpy(arr + 3, arr, 7);
	int i = 0;
	for (i = 0; i < 10; i++)
		printf("%d ", arr[i]);
	return 0;
}

我们可能认为答案是 1 2 3 1 2 3 4 5 6 7

但是vs2022给出的结果是

这是因为,内存只有一块,可能会冲突 。比如 4  这个位置,一开始 4 被修改为 1 ,再后来,当dest指针指到这个1的时候,他又会把这个1放到后面的位置。而memmove就能解决这个问题。

它是如何解决的呢?

对于刚才这种情况,我们发现 dest(红) 大于 src(蓝),如果我们从左开始,往右开始修改,那么肯定会出现刚才那种情况,但是如果是从右往左呢?  思考后我们发现,这是可行的,就好像右边的人在追左边的人,然后左边的人不断地往后丢东西,都丢在右边的人的身上。同时,我们发现,如果src(蓝)的最右端超过了dest(红)的最右端,这种方法好像又不适用了,也不能再从右往左了。

我们知道 ,dest和src的大小应该都是count,所以不存在上面这种情况。

那就可以开始具体实现了。

void* my_memmove(void* a,const void* b,size_t count) //a:dest b:source
{
	assert(a && b);
	void* ret = a;
	//s<d 从右往左
	if (b < a)
	{
		a = (char*)a + count - 1;
		b = (char*)b + count - 1;
		while (count--)
		{
			*(char*)a = *(char*)b;
			a = (char*)a - 1;
			b = (char*)b - 1;
		}
	}
	else
	{
		while (count--)
		{
			*(char*)a = *(char*)b;
			a = (char*)a + 1;
			b = (char*)b + 1;
		}
	}
	return ret;
}

5.memset

函数声明:

void *memset( void *dest, int c, size_t count );

作用:就是可以初始化一块内存为具体值。

实例:

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

int main()
{
	char p[20] = "what is csdn";
	memset(p, '#', 4);
	printf("%s", p);
	return 0;
}

函数实现:

void* my_memset(void* dest, int c, size_t count)
{
	void* tmp = dest;
	while (count--)
		*(((char*)dest)++) = (char)c;
	return tmp;
}

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • C语言memset函数详解

    目录 一.memset函数原型: 二.使用memset函数 三.给int类型赋值为1 四.扒开内存 五.memset给变量赋值 总结 在c语言中,使用变量前,需要先对变量的值进行初始化.数组在内存中占用一片连续的存储块.而c语言提供了memset函数(头文件string.h)对数组进行组团赋值.(memset函数也能对变量赋值,但只有无聊的人才会这么做.详见下文目录五) 一.memset函数原型: void memset ( void *s , char ch, unsigned n ) 函数功

  • 对比C语言中memccpy()函数和memcpy()函数的用法

    C语言memccpy()函数:复制内存中的内容 头文件: #include <string.h> 定义函数: void * memccpy(void *dest, const void * src, int c, size_t n); 函数说明:memccpy()用来拷贝src 所指的内存内容前n 个字节到dest 所指的地址上.与memcpy()不同的是,memccpy()会在复制时检查参数c 是否出现,若是则返回dest 中值为c 的下一个字节地址. 返回值:返回指向dest 中值为c 的

  • C语言memset函数使用方法详解

    C语言memset函数使用方法详解 一.函数原形   void *  memset(void*s, int ch,size_t n) 二.函数作用  将以s内存地址为首的连续n个字节的内容置成ch,一般用来对大量结构体和数组进行清零 三.常见错误 1.搞反了 ch 和 n的位置 对char[20]清零,一定是 memset(a,0,20); 2.过度使用memset 3.其实这个错误严格来讲不能算用错memset,但是它经常在使用memset的场合出现 int fun(strucy someth

  • 详解C语言中的memset()函数

    C语言memset()函数:将内存的前n个字节设置为特定的值 头文件: #include <string.h> memset() 函数用来将指定内存的前n个字节设置为特定的值,其原型为: void * memset( void * ptr, int value, size_t num ); 参数说明: ptr 为要操作的内存的指针. value 为要设置的值.你既可以向 value 传递 int 类型的值,也可以传递 char 类型的值,int 和 char 可以根据 ASCII 码相互转换.

  • C语言中memcpy 函数的用法详解

    C语言中memcpy 函数的用法详解 memcpy(内存拷贝函数) c和c++使用的内存拷贝函数,memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中. void* memcpy(void* destination, const void* source, size_t num); void* dest 目标内存 const void* src 源内存 size_t num 字节个数 库中实现的memcpy函数 struct { ch

  • 深入学习C语言中memset()函数的用法

    头文件: #include <string.h> memset() 函数用来将指定内存的前n个字节设置为特定的值,其原型为: void * memset( void * ptr, int value, size_t num ); 参数说明: ptr 为要操作的内存的指针. value 为要设置的值.你既可以向 value 传递 int 类型的值,也可以传递 char 类型的值,int 和 char 可以根据 ASCII 码相互转换. num 为 ptr 的前 num 个字节,size_t 就是

  • 详解C语言的mem系列函数

    目录 1.memchr 2.memcmp 4.memmove 5.memset 总结 1.memchr memchr的函数声明: void *memchr(const void *str, int c, size_t n); 作用: memchr函数从str位置后的n个位置开始寻找,寻找第一个和c相同的字符.如果成功,memchr函数返回一个指向该字符位置的指针,如果没有没有找到指定字符,则返回NULL. 实例: #include <stdio.h> #include <string.h

  • 详解R语言caret包trainControl函数

    目录 trainControl参数详解 源码 参数详解 示例 trainControl参数详解 源码 caret::trainControl <- function (method = "boot", number = ifelse(grepl("cv", method), 10, 25), repeats = ifelse(grepl("[d_]cv$", method), 1, NA), p = 0.75, search = "

  • 详解C语言编程中的函数指针以及函数回调

    函数指针: 就是存储函数地址的指针,就是指向函数的指针,就是指针存储的值是函数地址,我们可以通过指针可以调用函数. 我们先来定义一个简单的函数: //定义这样一个函数 void easyFunc() { printf("I'm a easy Function\n"); } //声明一个函数 void easyFunc(); //调用函数 easyFunc(); //定义这样一个函数 void easyFunc() { printf("I'm a easy Function\n

  • 详解易语言DLL以及API函数

    易语言 DLL 详细解释 使用易语言多媒体教程中的例子. .版本 2 //DLL文件 ,需要插入一个窗体.标签.按钮 .程序集 窗口程序集1 .子程序 _按钮1_被单击 窗口1.销毁 () .子程序 自创信息框, , 公开 .参数 标题, 文本型 .参数 内容, 文本型 载入 (窗口1, , 假) // 载入(),必须放在前面,放在后两句的后面则提示窗口无法载入 窗口1.标题 = 标题 窗口1.标签1.标题 = 内容 //编译为自创信息框.dll //当你想调用前面的dll时,必须先插入dll命

  • 详解C语言初阶之函数

    目录 1.main函数 2.自定义函数 2.1  函数的的封装和面向过程的思维 3.函数的组成 3.1函数的命名法 3.2函数的返回值 3.2.1void类型 补充: 3.3形参与实参 总结 1.main函数 第一个函数是我们的main函数,它无处不在,main函数被称之为我们的入口函数,程序在运行时,从main函数进入,从main函数出来,main函数其实就是整个程序功能的集合,所有的功能必须被包含在main里面才可以被运行(预处理命令,宏定义,全局变量什么的当然要优先处理,再次不讨论这些).

  • 详解C语言对字符串处理函数的实现方法

    目录 strlen: 1.计数器版本: 2.递归的版本 3.指针-指针版本 strcat: strcmp: 总结 strlen: 1.计数器版本: #include<stdio.h> #include<string.h> #include<assert.h> int my_strlen(const char *str) { int count =0; assert(str!=NULL); while(*str!='\0') { count++; str++; } ret

  • 详解C语言函数返回值解析

    详解C语言函数返回值解析 程序一: int main() { int *p; int i; int*fun(void); p=fun(); for(i=0;i<3;i++) { printf("%d\n",*p); p++; } return 0; }; int* fun(void) { static int str[]={1,2,3,4,5}; int*q=str; return q; } //不能正确返回 虽然str是在动态变量区,而该动态变量是局部的,函数结束时不保留的.

  • 详解C语言gets()函数与它的替代者fgets()函数

    在c语言中读取字符串有多种方法,比如scanf() 配合%s使用,但是这种方法只能获取一个单词,即遇到空格等空字符就会返回.如果要读取一行字符串,比如: I love BIT 这种情况,scanf()就无能为力了.这时我们最先想到的是用gets()读取. gets()函数从标准输入(键盘)读入一行数据,所谓读取一行,就是遇到换行符就返回.gets()函数并不读取换行符'\n',它会吧换行符替换成空字符'\0',作为c语言字符串结束的标志. gets()函数经常和puts()函数配对使用,puts

  • 详解C语言用malloc函数申请二维动态数组的实例

    详解C语言用malloc函数申请二维动态数组的实例 C语言在程序运行中动态的申请及释放内存十分方便,一维数组的申请及释放比较简单. Sample one #include <stdio.h> int main() { char * p=(char *)malloc(sizeof(char)*5);//申请包含5个字符型的数组 free(p); return 0; } 是否申请二维动态内存也如此简单呢?答案是否定的.申请二维数组有一下几种方法 Sample two /* 申请一个5行3列的字符型

  • 详解C语言常用的一些转换工具函数

    1.字符串转十六进制 代码实现: 2.十六进制转字符串 代码实现: 或者 效果:十六进制:0x13 0xAA 0x02转为字符串:"13AAA2" 3.字符串转十进制 代码实现: 第一种,如果带负号 这个就是atoi函数的实现: 效果:字符串:"-123" 转为 -123 第二种,如果不带负号: 效果:字符串:"123" 转为 123 第三种:包含转为浮点数: 效果:字符串:"123.456" 先转为 123456,然后除以1

随机推荐