C进阶⚡- 03字符函数与字符串函数

我知道的只是  “ 肉随便加  ”和  “ 要加多少加多少  ” 这些词。    ———— 路飞

阶段2目标:

此阶段开始大量刷题,多多参加编程类竞赛,在实战中锻炼编程思维和本领,并且要在不断复习夯实初阶的基础上,刻意地进行编程思维的训练。学无止境!为了精进编程,可以去学习一切为他服务的课程!

目录

本章重点

前言

1.strlen - 字符串测量长度(不算'\0')

2.strcpy - 字符串拷贝(覆盖)

模拟strcpy函数

3.strcat - 字符串追加(原字符串基础上“续写”)

模拟strcat函数

4.※strcmp - 字符串比较(比较的是字符串的内容,不是长度!)  

注意注意!!,返回值不仅仅是1,0,-1三个,只是说返回大于、等于、小于0,并没有特别指出是哪个!!!

模拟strcmp函数

长度不受限制的字符串函数总结1:

5.strncpy - 字符串长度有限制的拷贝

模拟strncpy函数

6.strncat - 字符串有限制的追加

模拟strncat函数

7.strncmp - 字符串有限制的比较内容是否相同(大于、等于、小于)

模拟strncmp函数

8.strstr - 字符串查找

※模拟strstr函数

 9.※strtok - 切割字符串

10.strerror - 返回错误码,所对应的错误信息

11.memcpy - 内存拷贝

※模拟memcpy函数(   写法甚妙~~   )

12.memmove - 用于拷贝内存时,出现的内存重叠现象

※模拟memmove函数(      仔细体会~~      )

memcpy与memmove异同总结2:

13.memcmp - 一个字节一个字节比较字符串内容是否相同(逐字节更细致 )(  区别于strncmp  )

memcmp与strncmp区别:

14.memset - 内存设置 (  memory set  ) - 将内存中的字符改动成自己想要的字符

 C语言库函数中的函数千千万,只有自己不断精进,才能越来越强!!加油,小仇


写在前面

【库函数包括很多:】

  • IO函数  (  printf    scanf  )
  • 字符函数
  • 字符串函数
  • 内存函数
  • 时间日期函数
  • 数学函数
  • ...

(今天我们来探讨字符函数、字符串函数、内存函数的相关~)

本章重点

重点介绍处理字符和字符串的库函数的使用和注意事项

  1. 求字符串长度    strlen
  2. 长度不受限制的字符串函数     strcpy     strcat       strcmp
  3. 长度受限制的字符串函数       strncpy     strncat     strncmp
  4. 字符串查找     strstr     strtok
  5. 错误信息报告     strerror
  6. 字符操作
  7. 内存操作函数     memcpy     memmove     memset     memcmp

前言

C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在 常量字符串 中或者 字符数组 中。 字符串常量 适用于那些对它不做修改的字符串函数。

1.strlen - 字符串测量长度(不算'\0')

size_t strlen ( const char * str );

  • 字符串已经 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数不包含 '\0' )。
  • 参数指向的字符串必须要以 '\0' 结束
  • 注意函数的返回值为size_t,是无符号的( 易错 )
  • 学会strlen函数的模拟实现    (计数器、指针-指针、递归)

讲解

注意点1

有的编译器可能用int来接收strlen函数的返回值会报错,因为strlen函数返回值是size_t(  unsigned  int     无符号整型   )

	char arr[] = "abcdef";
	//错误示范
	int sz1 = strlen(arr);

	//正确示范
	size_t sz = strlen(arr);

注意点2

注意函数的返回值为size_t,是无符号的( 易错 )

//3 - 8 < 0?
//strlen函数是size_t类型,是无符号的,必定大于0!!!
int main()
{
	if (strlen("abc") - strlen("abcdefgh") > 0)
	{
		printf("哈哈哈~~");
	}
	else
		printf("吼吼吼!");

	return 0;
}

//运行结果是   哈哈哈~~

对比代码:

int main()
{
	if ((int)strlen("abc") - (int)strlen("abcdefgh") > 0)
	{
		printf("哈哈哈~~");
	}
	else
		printf("吼吼吼!");

	return 0;
}

//运行结果是   吼吼吼!

2.strcpy - 字符串拷贝(覆盖)

char* strcpy(char * destination, const char * source );

  • 源字符串必须以 '\0' 结束。
  • 会将源字符串中的 '\0' 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串
  • 目标空间必须可变。(    即:不能是不可修改的常量字符串    )
  • 学会模拟实现。 

讲解

注意点1:

我们发现,copy时,将源字符串毫无保留的( 包括末尾的 '\0' )一块copy到目标字符串中!!

注意点2:

如果源字符串中间本身就含有'\0',那么我们同样还是取到遇见的第一个‘\0’ ,不会继续往后打印的!!!

注意点3:

目标空间必须足够大,以确保能存放源字符串。

	//错误示范
	//目标字符串空间太少
	char arr1[] = "xxx";
	char arr2[] = "hello\0abc";
	strcpy(arr1, arr2);

注意点4:

目标空间必须可变。

模拟strcpy函数

代码1:(基础版~~)

#include<stdio.h>
#include<assert.h>
void* my_strcpy(char* dest, const char* src)
{
	assert(dest && src);
	while (*src)
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = '\0';
}
int main()
{
	char arr1[] = "xxxxxxxxxxxxxxxx";
	char arr2[] = "abc";
	my_strcpy(arr1, arr2);

	printf("%s", arr1);

	return 0;
}

代码2:(优化版~~)

#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
	assert(dest && src);
	char* ret = dest;
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[] = "xxxxxxxxxxxxxxxx";
	char arr2[] = "abc";

	printf("%s", my_strcpy(arr1, arr2));

	return 0;
}

3.strcat - 字符串追加(原字符串基础上“续写”)

char*  strcat ( char * destination, const char * source );

  • 源字符串必须以 '\0' 结束。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改
  • 学会模拟实现。 
  • 字符串自己给自己追加,如何?

讲解

注意点1

目标空间必须有足够的大,能容纳下源字符串的内容。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
	//strcar - 字符串连接 - 字符串追加

	char arr[20] = "abc";//空间要预留够
	strcat(arr, "def");

	printf("%s\n", arr);//abcdef

	return 0;
}

注意点2

源字符串必须以 '\0' 结束。

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
	//strcar - 字符串连接 - 字符串追加

	char arr1[20] = "abc";
	char arr2[] = { 'd','e','f'};
	strcat(arr1, arr2);

	printf("%s\n", arr1);//abcdef?   err,因为arr2中没有 '\0'

	return 0;
}

对比记忆

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
int main()
{
	//strcar - 字符串连接 - 字符串追加

	char arr1[20] = "abc";
	char arr2[] = { 'd','e','f','\0'};//此处末尾添加一个'\0'
	strcat(arr1, arr2);

	printf("%s\n", arr1);//abcdef?   对

	return 0;
}

模拟strcat函数

代码1:(基础版~~)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
//strcat返回的是目标函数的起始地址 【  需要提前保存一下  】
char* my_strcat(char* dest, char* src)
{
	char* ret = dest;
	//1.找到目标字符串的末尾\0
	while (*dest != '\0')//也可以简写成while (*dest),因为'\0'的 ASCII码值是0
	{
		dest++;
	}
	//2.追加源字符串直到\0
	while (*dest++ = *src++)
	{
		;
	}

	return ret;
}
int main()
{
	//strcar - 字符串连接 - 字符串追加

	char arr1[20] = "abc";
	const char arr2[] = "def";
	my_strcat(arr1, arr2);

	printf("%s\n", arr1);

	return 0;
}

代码2:(优化版~~)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<assert.h>
//strcat返回的是目标函数的起始地址 【  需要提前保存一下  】
char* my_strcat(char* dest, const char* src)
{
	assert(dest);
	assert(src);
	char* ret = dest;
	//1.找到目标字符串的末尾\0
	while (*dest != '\0')//也可以简写成while (*dest),因为'\0'的 ASCII码值是0
	{
		dest++;
	}
	//2.追加源字符串直到\0
	while (*dest++ = *src++)
	{
		;
	}

	return ret;
}
int main()
{
	//strcar - 字符串连接 - 字符串追加

	char arr1[20] = "abc";
	const char arr2[] = "def";

	printf("%s\n", my_strcat(arr1, arr2));

	return 0;
}

4.strcmp - 字符串比较(比较的是字符串的内容,不是长度!)  

int  strcmp ( const char * str1, const char * str2 );

标准规定:

  • 第一个字符串大于第二个字符串,则返回大于0的数字
  • 第一个字符串等于第二个字符串,则返回0
  • 第一个字符串小于第二个字符串,则返回小于0的数字
  • 学会模拟实现
  • 那么如何判断两个字符串?

比较的是c与q的ASCII码值的大小,因为cASCII值小于q,所以返回-1。那如果是abcdef与abc比较呢??相等??

int main()
{
    //strcmp比较的是字符串的内容,不是长度
	char arr1[] = "abcdef";
	char arr2[] = "abq";
	//c  的ASCII码小于  q
	//即:arr1 < arr2,返回的是-1
	int ret = strcmp(arr1, arr2);

	printf("%d\n", ret);//-1

	return 0;
}

 非也非也,字符d的ASCII值大于\0,所以,返回值是1

int main()
{
    //strcmp比较的是字符串的内容,不是长度
	char arr1[] = "abcdef";
	char arr2[] = "abc";
	//d  的ASCII码大于  \0
	//即:arr1 > arr2,返回的是1
	int ret = strcmp(arr1, arr2);

	printf("%d\n", ret);//1

	return 0;
}

注意注意!!,返回值不仅仅是1,0,-1三个,只是说返回大于、等于、小于0,并没有特别指出是哪个!!!

	int ret = strcmp(arr1, arr2);
	//这样写是有风险的错误写法
	if (ret == 1)
	{
		printf("大于");
	}

正确示范:

	int ret = strcmp(arr1, arr2);
	if (ret == 0)
	{
		printf("等于");
	}
	else if (ret > 0)
	{
		printf("大于");
	}
	else
		printf("小于");

模拟strcmp函数

#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char* s1, const char* s2)
{
	assert(s1 && s2);
	//字符相等,并且不等于\0,就继续往后比较字符大小
	while (*s1 == *s2)
	{
		//在前提*s1 是等于 *s2的情况下,*s1、*s2都等于'\0',说明他们比较到末尾\0都是一样的,所以返回值是0
		if (*s1 == '\0')
			return 0;
		s1++;
		s2++;
	}
	return *s1 - *s2;
}
int main()
{
    //strcmp比较的是字符串的内容,不是长度
	char arr1[] = "abcdef";
	char arr2[] = "abc";

	int ret = my_strcmp(arr1, arr2);

	printf("%d\n", ret);//1

	return 0;
}

长度不受限制的字符串函数总结1

我们以上所讲的中的三个字符串函数:strcpy        strcat          strcmp  是属于长度不受限制的字符串函数。比如,拷贝字符串strcpy,我们就是无脑拷贝—— 将一个源字符串拷贝到另一个目标字符串上;比如,追加字符串strcat,我们依旧是无脑追加,将一个源字符串追加到目标字符串后面......

这样,无脑的行为可能会造成不安全,访问到不该访问的空间,所以我们引入了长度受限制的字符串函数————  strncpy   strncat  strncmp,来使其相对安全

5.strncpy - 字符串长度有限制的拷贝

char*  strncpy ( char * destination, const char * source, size_t num );

  • 拷贝num个字符从源字符串到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个
  • 学会模拟实现

实例:

int main()
{
	char arr1[20] = "abcdefgh";
	char arr2[] = "xxxx";
	strncpy(arr1, arr2, 2);

	printf("%s\n", arr1);//结果是:xxcdefgh

	return 0;
}

注意点:

如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个

模拟strncpy函数

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strncpy(char* dest, const char* src, int num)
{
	assert(dest && src);
	char* ret = dest;
	while (num--)
	{
		*dest++ = *src++;
	}
	return ret;
}
int main()
{
	char arr1[20] = "abcdefgh";
	char arr2[] = "xxxx";
	int num = 2;//num是2
	char* ret = my_strncpy(arr1, arr2, num);

	printf("%s", ret);

	return 0;
}

6.strncat - 字符串有限制的追加

char*   strncat ( char * destination, const char * source, size_t num );

实例:源字符串拷贝的时候,是在目标字符串第一个\0的地方开始追加字符串,最后在末尾补一个\0字符。

要追加的字符串已经超过源字符串本身长度,这样报错吗?错吗?    ————    并不会报错

int main()
{
	char arr1[20] = "abc\0xxxxxxx";
	char arr2[] = "def";
	strncat(arr1, arr2, 6);

	return 0;
}

解释:

依旧和原来规则一样,把源字符串追加到目标字符串后,由于要追加的数已经超过了源字符串长度,则,追加时,已经把源字符串末尾的\0一并追加到了目标字符串上。

模拟strncat函数

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<assert.h>
//strcat返回的是目标函数的起始地址 【  需要提前保存一下  】
char* my_strncat(char* dest, const char* src, int num)
{
	assert(dest);
	assert(src);
	char* ret = dest;
	//1.找到目标字符串的末尾\0
	while (*dest != '\0')//也可以简写成while (*dest),因为'\0'的 ASCII码值是0
	{
		dest++;
	}
	//2.追加源字符串直到\0

	while (num--)
	{
		*dest++ = *src++;
	}

	return ret;
}
int main()
{
	//strcar - 字符串连接 - 字符串追加

	char arr1[20] = "abc";
	const char arr2[] = "def";
	int num = 2;
	char* ret = my_strncat(arr1, arr2, num);
	printf("%s\n", ret);

	return 0;
}

7.strncmp - 字符串有限制的比较内容是否相同(大于、等于、小于)

int strncmp ( const char * str1, const char * str2, size_t num );

实例:

int main()
{
	//strcar - 字符串连接 - 字符串追加

	char arr1[20] = "abcdef";
    char arr2[]   = "abcqwe";
	int num = 3;
	int ret = strncmp(arr1, arr2, num);//比较两字符串前3个字符是否相同

	printf("%d\n", ret);//0

	return 0;
}

注意点:比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完

例如:虽然我们比较的是前5个字符,但是第二个字符已经出现不一样了,所以,没必要再往后比较了。

int main()
{
	char arr1[20] = "abcdef";
    char arr2[]   = "aqcbwe";
	int num = 3;
	int ret = strncmp(arr1, arr2, 5);

	printf("%d\n", ret);//-1

	return 0;
}

模拟strncmp函数

( —————————————————————— 后续我再优化哈~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~)

#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strncmp(const char* s1, const char* s2, int num)
{
	assert(s1 && s2);
	//字符相等,并且不等于\0,就继续往后比较字符大小
	while (--num)
	{
		if (*s1 == *s2)
		{
			s1++;
			s2++;
		}
	}
	return *s1 - *s2;
}
int main()
{
	//strcmp比较的是字符串的内容,不是长度
	char arr1[] = "abcdef";
	char arr2[] = "abcqws";
	int num = 3;//比较前三个字符是否相同

	int ret = my_strncmp(arr1, arr2, num);

	printf("%d\n", ret);//0

	return 0;
}

8.strstr - 字符串查找

char*  strstr ( const char *, const char * );

  • Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1
     
#include<stdio.h>
#include<string.h>

int main()
{
	char arr1[] = "I am a boy ,I am a good boy!";
	char arr2[] = "boy";

	//查找arr1中arr2第一次出现的位置
	char* ret = strstr(arr1, arr2);

	if (ret == NULL)//空指针,说明没找到
	{
		printf("没找到!\n");
	}
	else
		printf("%s\n", ret);//结果是   boy ,I am a good boy!

	return 0;
}

※模拟strstr函数

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(char* str1, char* str2)
{
	assert(str1, str2);
	char* s1;
	char* s2;
	char* cp = str1;//用cp指针,保留记录
	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		//while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
        while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cp;
		}
		cp++;
	}

	//找不到
	return NULL;
}
int main()
{
	char arr1[] = "I am a boy ,I am a good boy!";
	char arr2[] = "boy";

	//查找arr1中arr2第一次出现的位置
	char* ret = my_strstr(arr1, arr2);

	if (ret == NULL)//空指针,说明没找到
	{
		printf("没找到!\n");
	}
	else
		printf("%s\n", ret);//结果是   boy ,I am a good boy!

	return 0;
}

仔细考虑一下三种不同的情况:

 9.※strtok - 切割字符串

char * strtok ( char * str, const char * sep );

  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
  • strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
  • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  • 如果字符串中不存在更多的标记,则返回 NULL 指针。

先来讲讲,啥时候会用到它叭~:
如下,我们想要把192.322.4.77yong' . '拆分成散开的  192  322  4   77;我们想要把qbj@xuhai.stu用  '  @  '   ' . '拆分成qbj   xuhai   stu,该怎么做?

用法解释:

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "qbj@xuhai.stu";

	char arr2[] = { 0 };//用来临时拷贝,从而不去改变原始的arr1
	//qbj@xuhai.stu\0

	char sep[] = "@.";//用来存放 用来分割的符号
	strcpy(arr2, arr1);

	strtok(arr2, sep);
	//strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置
	//在该程序中,第一个参数是arr2,不是NULL,所以找到str中的@符号,将其置为\0,指针指向"qbj"中的‘q’字符
	//即:此时arr2:qbj\0xuhai.stu\0
	
	strtok(NULL, sep);
	//strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记
	//在改程序中,第一个参数确实是NULL,所以,strtok函数将从"qbj\0"中的'\0'位置开始往后继续查找
	
	//也就是说,在程序中,除了第一个编写的strtok函数的第一个参数位置不是NULL外,其余都是NULL,来查找
	//即:
	//strtok(arr2, sep);
	//strtok(NULL, sep);
	//strtok(NULL, sep);
	//strtok(NULL, sep);
	//...

	return 0;
}

应用:

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "qbj@xuhai.stu";

	char arr2[] = { 0 };//用来临时拷贝,从而不去改变原始的arr1
	//qbj@xuhai.stu\0

	char sep[] = "@.";//用来存放 用来分割的符号
	strcpy(arr2, arr1);

	char* ret = NULL;//用来指向标记位置
	//分割字符串
	for (ret = strtok(arr2, sep); ret != NULL;ret = strtok(NULL, sep))
	{
		printf("%s\n", ret);
	}

	return 0;
}

10.strerror - 返回错误码,所对应的错误信息

char*   strerror (  int errnum );

举例理解

总结

//0 1 2 3 4 5 ......
//在C语言中,产生错误,由012345...组合,会有很多码,我们称之为错误码
//每一种组合的错误码,都有所对应的错误信息
//strerror - 就是返回错误码对应的错误信息(的首地址) 

注意:在C语言中,错误信息会存储在errno变量中

应用

#include<stdio.h>
#include<string.h>
//0 1 2 3 4 5 ......
//在C语言中,产生错误,由012345...组合,会有很多码,我们称之为错误码
//每一种组合的错误码,都有所对应的错误信息
//strerror - 就是返回错误码对应的错误信息(的首地址)

int main()
{
	FILE* pf = fopen("test.txt", "r");
	//errno
	//strerror - 就是返回错误码对应的错误信息(的首地址)
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		printf("打开成功!");
	}

	return 0;
}

 打印结果:

No such file or directory

11.memcpy - 内存拷贝

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

  • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
  • 这个函数在遇到 '\0' 的时候并不会停下来。
  • 如果source和destination有任何的重叠,复制的结果都是未定义的。
  • 学会模拟实现
     

实例:

#include<stdio.h>
int main()
{
	//想要把arr1的数据copy到arr2中
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };

	//拷贝的是整型数据
	memcpy(arr2, arr1, 10 * sizeof(int));
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		printf("%d ", arr2[i]);
	}
	//结果:1 2 3 4 5 6 7 8 9 10 0 0 0 0 0 0 0 0 0 0
	return 0;
}

※模拟memcpy函数(   写法甚妙~~   )

#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t count)
{
	char* ret = dest;
	assert(dest && src);
	while (count--)
	{
		*(char*)dest = *(char*)src;
		//错误写法,因为dest、src都是void类型,++并不知道跳过了几个字节!!
		//dest++; src++;

		//正确写法
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
	//想要把arr1的数据copy到arr2中
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };

	//拷贝的是整型数据
	my_memcpy(arr2, arr1, 10 * sizeof(int));
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		printf("%d ", arr2[i]);
	}
	//结果:1 2 3 4 5 6 7 8 9 10 0 0 0 0 0 0 0 0 0 0

	return 0;
}

那么我们想要把arr中的前4个数据在copy到arr中,即:想要实现arr[10] = {1,2,1,2,3,4,7,8,9,10};,我们用memcpy可以实现吗??

——————    可见,memcpy并没有实现效果,而是输出了   1 2 1 2 1 2 7 8 9 10      ,为什么呢??

#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t count)
{
	//省略方法,详情见上段代码
}
int main()
{
	//想要把arr中的前4个数据在copy到arr中,
	//即:想要实现
	//  arr[10] = {1,2,1,2,3,4,7,8,9,10};
	//我们用memcpy可以实现吗??
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

	//想拷贝前4个数据
	my_memcpy(arr+2, arr, 4 * sizeof(int));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	//结果:1 2 1 2 1 2 7 8 9 10

	return 0;
}

解释:

其实memcpy只要完成了不重叠的内存拷贝就算完成任务了!

 所以我们就引出了memmove函数

12.memmove - 用于拷贝内存时,出现的内存重叠现象

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

  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。
     

实例:(    在memcpy基础上的代码   )

#include<stdio.h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };

	//想拷贝前4个数据
	//拷贝内存时,出现内存重叠现象,要用memmove函数
	memmove(arr+2, arr, 4 * sizeof(int));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	//结果:1 2 1 2 3 4 7 8 9 10

	return 0;
}

※模拟memmove函数(      仔细体会~~      )

#include<stdio.h>
#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t count)
{
	void* ret = dest;
	assert(src && dest);
	if (dest < src)
	{
		//前->后
		while (count--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		//后->前
		while (count--)
		{
			*((char*)dest + count) = *((char*)src + count);
		}
	}
	return ret;
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr + 2, arr, 16);
	//想要效果:
	//1 2 1 2 3 4 7 8 9 10

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	//结果:1 2 1 2 3 4 7 8 9 10

	return 0;
}

memcpy与memmove异同总结2:

相同:语法相同

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

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

区别:重叠现象

memcpy只要完成了不重叠的内存拷贝就算完成任务了。

memmove -主要用于拷贝内存时,出现的内存重叠现象。

(注:其实啊,C语言中的memcpy是可以实现重叠拷贝的,刚刚我们试的是自定义的my_memcpy函数,至少在我们的VS2019中是可以实现的。代码效果实现如下;但是我想说的是,对于memcpy我们不要过分的要求,想要拷贝重叠内存,是,在VS2019中的确是可以实现的,但我们还是不要去逼他,(他有能考60的水平,但是他努努力可以考100分);而memmove函数,针对拷贝重叠内存是完完全全可以胜任的,(本身就有考100分的能力),【memmove具有memcpy的功能】)

13.memcmp - 一个字节一个字节比较字符串内容是否相同(逐字节更细致 )(  区别于strncmp  )

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

注意size_t num在此处表示字节  

实例1:

#include<stdio.h>
#include<string.h>
int main()
{

	int arr1[] = { 1,2,3,4,5 };
	//01 00 00 00 02 00 00 00 03 00 00 00  ...
	int arr2[] = { 1,2,3,6,6 };
	//01 00 00 00 02 00 00 00 03 00 00 00  ...

	int ret = memcmp(arr1, arr2, 12);//比较两字符串中的前12个字节

	printf("%d\n", ret);//0

	return 0;
}

实例2:

#include<stdio.h>
#include<string.h>
int main()
{

	int arr1[] = { 1,2,3,4,5 };
	//01 00 00 00 02 00 00 00 03 00 00 00 04  ...
	int arr2[] = { 1,2,3,6,6 };
	//01 00 00 00 02 00 00 00 03 00 00 00 06  ...

	int ret = memcmp(arr1, arr2, 13);//比较两字符串中的前13个字节

	printf("%d\n", ret);//-1

	return 0;
}

memcmp与strncmp区别:

strncmp函数是比较字符串内容是否相同(单单从字符表面去看   )

memcmp函数更加深入内存,从一个字节一个字节去看,去比较,比strncmp更加细致!!

14.memset - 内存设置 (  memory set  ) - 将内存中的字符改动成自己想要的字符

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

注释:dest是目标     c是要改动成的字符    count是字节数

改动后:

             🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈                    💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖

              C语言库函数中的函数千千万,只有自己不断精进,才能越来越强!!加油,小仇 !

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.阿Q.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值