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 );

04F5C2B3-670D-48C7-5E9A-B1C854F46992.png

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

讲解

注意点1:

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

E398D960-0CCC-8AB1-D750-61E3C91B2202.png

注意点2:

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

E79D6ED8-363B-C785-A0D6-F4CC7C0B6E11.png

注意点3:

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

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

注意点4:

目标空间必须可变。

303D9054-CAE0-96C7-4254-DC510FEFF82A.png

模拟strcpy函数

代码1:(基础版~~)

#include<stdio.h>
#include<assert.h>
void* my_strcpy(char* dest, const char* src)
{
	assert(dest && src);
	char* ret = dest;
	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 );

C14C63F6-4F48-69F4-6770-830127B80300.png

标准规定:

  • 第一个字符串大于第二个字符串,则返回大于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个

1402760B-6E37-3788-1A13-821AB72BF2C9.png

模拟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字符。

736998E5-EFA6-EECC-6C79-10879B7B228B.png

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

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_strcmp(const char* s1, const char* s2, int num)
{
	assert(s1 && s2);
	//字符相等,并且不等于\0,就继续往后比较字符大小
	while (num--)
	{
		if (*s1 == *s2)
		{
			s1++;
			s2++;
		}
	}
	s1--;
	s2--;

	return *s1 - *s2;
}
int main()
{
	//strcmp比较的是字符串的内容,不是长度
	char arr1[] = "abcdef";
	char arr2[] = "abcqws";
	int num = 3;//比较前三个字符是否相同

	int ret = my_strcmp(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;
}

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

04C92AD3-C292-A16F-4BEF-DDED80304ED4.png

 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,该怎么做?

A919582D-4209-DD67-423D-500AEEBD63D4.png

用法解释:

#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.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只要完成了不重叠的内存拷贝就算完成任务了!

CBBCEBD0-7CC9-6ACB-5004-C0E784AA950A.png

所以我们就引出了memmove函数

11.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;
}
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的功能】)

CE1520B1-6CCE-B445-CFDE-A62E6B9D6B4A.png

收藏 (0)
评论列表
正在载入评论列表...
我是有底线的
为您推荐
    暂时没有数据