首页 > 系统相关 >C语言进阶3:字符串+内存函数

C语言进阶3:字符串+内存函数

时间:2024-11-15 15:43:32浏览次数:3  
标签:const 进阶 dest C语言 char int 内存 字符串 函数

本章重点

  1. 求字符串长度

  2. 长度不受限制的字符串函数

  3. 长度受限制的字符串函数

  4. 字符串查找

  5. 误信息报告

  6. 字符操作

  7. 内存操作

0.前言:

C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中

字符串常量 适用于那些对他不做修改的字符串函数

1.求字符串长度

1.1 strlen

函数介绍:strlen(string length)

size_t strlen(const char* str);

头文件:string.h

函数名:strlen

函数参数:str,参数类型是const char* ,即需要进行求字符串长度的起始地址

函数返回类型: size_t,size_t是unsigned int的类型重定义,是无符号整型。库函数使用size_t类型可能考虑的是字符串的长度不可能是负数,所以用了无符号类型size_t。

函数功能:计算字符串的长度

重点内容

1.字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包 含 ‘\0’ )。

2.参数指向的字符串必须要以 ‘\0’ 结束。

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

4.学会strlen函数的模拟实现

strlen函数的模拟实现三种方法:

  1. 计数器方法
  2. 递归方法(不创建临时变量求字符串长度)
  3. 指针 - 指针方法
#include<stdio.h>
#include<assert.h>
//1.计数器实现求字符串长度函数
	int my_strlen1(const char* str)//整个过程不改变指针指向内容,加上const
{
	assert(str != NULL);//加上断言,防止接收空指针
	int count = 0;
	while (*str != '\0')//也可以直接用while(*str)
	{
		count++;
		str++;
	}
	return count;
}

//2.递归实现求字符串长度,不用创建临时变量
int my_strlen2(const char* str)
{
	assert(str != NULL);
	if (*str != '\0')//也可以直接用if(*str)
	{
		return 1 + strlen(str + 1);//不能直接使用str++,可以使用++str,建议直接用str+1
	}
	else
		return 0;
}

//3.指针-指针得到中间元素的个数,实现求字符串长度
int my_strlen3(const char* str)
{
	assert(str != NULL);
	const char* tmp = str;//创建临时指针变量保存str起始值
	while (*str != '\0')
	{
		str++;
	}
	return str - tmp;
}

int main()
{
	char arr[] = "abcdefgh";
	int ret1 = my_strlen1(arr);//1.计数器方法
	int ret2 = my_strlen2(arr);//2.递归方法
	int ret3 = my_strlen3(arr);//3.指针 - 指针方法
	printf("%d\n", ret1);
	printf("%d\n", ret2);
	printf("%d\n", ret3);
    return 0;
}

使用注意事项

int main()
{
	if (strlen("abc") - strlen("abcdef") > 0)
		printf(">\n");
	else
		printf("<\n");
 
	return 0;
}
//看完这段代码,我们回想到3-6=-3,应该打印:<,
//但运行结果是: >

原因:

strlen的返回类型是:size_t(右击点定义可找到),是typrdef unsigned int的重定义.
所以返回的是无符号数,则肯定是正数,是>0的

2.长度不受限制的字符串函数

2.1 strcpy

函数介绍:strcpy(string copy)

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

头文件:string.h

函数名:strcpy

函数参数:

-----参数1:destination, 类型:char* ,表示将字符串拷贝的目的地位置
-----参数2:source,类型:char* ,表示被拷贝字符串拷贝的源地址起始位置。

函数返回类型: char*, 实际上就是返回destination(目的地)的起始位置

函数功能:字符串拷贝

重点内容

  1. Copies the C string pointed by source into the array pointed by
    destination, including the terminating nulcharacter(and stopping at that point).
  2. 源字符串必须以‘\0’结束。 (源字符串如果没有’\0’, 那么strcpy在拷贝的时候,不知道什么时候停止,可能会造成越界访问)
  3. 会将源字符串中的’ \0 ’拷贝到目标空间。(从起始地址到’\0’为止)
  4. 目标空间必须足够大,以确保能存放源字符串。 (目标空间不够大,也会导致越界访问)
  5. 目标空间必须可变(不能是常量字符串,比如:char* arr1 =“asdsffdf”)
    (要将源字符串的内容拷贝到目标空间,目标空间当然要可以变化,才能接收拷贝过来的字符)
  6. 学会模拟实现。

strcpy函数的模拟实现方法:

#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
	assert(dest != NULL);
	assert(src != NULL);
	char* ret = dest;//储存原字符串首字符地址

//拷贝src指向字符串的内容到dest指向的空间,包括'\0'
	//方法一:常规思路版
	while (*src != '\0')
	{
		*dest = *src;
		dest++;
		src++;
	}
	*dest = *src;

//方法二:代码精简版
	while (*dest++ = *src++)//遇到‘/0’为0,循坏停止
	{
		;
	}
    //返回目的空间起始位置
	return ret;
}
int main()
{
	char arr1[] = "abcdefghik";
	char arr2[] = "hello";
	my_strcpy(arr1, arr2);//模拟实现strcpy函数
	printf("%s", arr1);
	return 0;
}

2.2 strcat

函数介绍:strcat(string concatenate)

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

头文件:string.h

函数名:strcat

函数参数:

-----参数1:destination, 类型:char* ,表示将字符串追加的目的地位置
-----参数2:source,类型:char* ,表示被追加字符串的源地址起始位置。

函数返回类型: char,实际上就是返回destination(目的地)的起始位置*
函数功能:字符串追加

重点内容

  1. Appends a copy of the source string to the destination string.The
    terminating null character in destination is overwritten by the first character of source, and a null - character is included at the end ofthe new string formed by the concatenation of both in destination.
  2. 源字符串必须以‘\0’结束。目标空间也必须包含’\0’,以确定追加的起始位置
  3. 目标空间必须有足够的大,能容纳下源字符串的内容。
  4. 目标空间必须可修改。
  5. 字符串自己给自己追加,如何 ?

用strcat自己给自己追加会导致程序崩溃,无法实现自己追加自己!(从’\0’开始追加,自己追加自己的时候,’\0‘改成了被追加的首字符,再寻找追加字符串结束的’\0’时,找不到’\0’,会导致死循环)

请添加图片描述

strcat函数的模拟实现方法:

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
	assert(dest != NULL);
	assert(src != NULL);
	char* dest_start = dest;
    
	//1.找到目的空间中的'\0'
	while (*dest != '\0')//跳过不是'\0'的字符
	{
		dest++;
	}
	//2.追加
	while (*dest++ = *src++)
	{
		;
	}
	return dest_start;
}

int main()
{
	char arr1[30] = "hello";
	char arr2[] = "world";
	my_strcat(arr1, arr2);//模拟实现strcat
	printf("%s", arr1);
	return 0;
}

2.3 strcmp

函数介绍:strcmp (string compare)

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

头文件:string.h

函数名:strcmp

函数参数:

-----参数1:str1, 类型:char* ,表示将进行比较的第一个字符串
-----参数2:参数2:str2, 类型:char* ,表示将进行比较的第二个字符串
函数返回类型: int, 返回两个字符串比较的结果

函数功能:字符串比较

重点内容

  1. This function starts comparing the first character of each string.lf they are equal to each other, itcontinues with the following pairs until the characters differ or until a terminating null - character isreached.
  2. 标准规定︰
  • 第一个字符串大于第二个字符串,则返回大于O的数字。
  • 第一个字符串等于第二个字符串,则返回0
  • 第一个字符串小于第二个字符串,则返回小于0的数字
    strcmp那么如何判断两个字符串? 逐个字符ASCLL码进行比较(不是长度)
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* p1, const char* p2)
{
	assert(p1 && p2);
	while (*p1 == *p2)
	{
		if (*p1 == '\0')
		{
			return 0;
		}
		p1++;
		p2++;
	}

//方法一:vs实现的方式
if (*p1 > *p2)
	return 1;
else
	return -1;
//方法二:linux下gcc实现方式
  int my_strcmp(const char* p1, const char* p2)
{
    return *p1 - *p2;
}
int main()
{
	char* p1 = "abc";
	char* p2 = "ab";
	int ret = my_strcmp(p1, p2);
	printf("ret = %d", ret);
	return 0;
}

3.长度受限制的字符串函数(更安全)

3.1 strncpy

函数介绍: strncpy(string copy with specified number of characters)

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

头文件:string.h

函数名:strncpy

函数参数:

-----参数1: destination,类型:char*,拷贝字符的目的地位置,即接收字符的起始位置
-----参数2: source,类型:char* ,拷贝字符的源地址,即拷贝字符串的开始位置。
-----参数3: num,类型size_t,拷贝字符的个数,用来控制拷贝字符的长度。

函数返回类型:char* ,返回接收字符的起始位置。

函数功能:指定个数的字符串拷贝

重点内容

  1. Copies the first num characters of source to destination.lf the end of the source C string(which issignaled by a null - character) is found before num characters have been copied, destination is paddedwith zeros until a total of num characters have been written to it.
  2. 拷贝num个字符从源字符串到目标空间。
  3. 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。(源字符串有\0,后面将一直补\0,而不是字符)
  4. 如果拷贝的字符长度大于目的地空间的容量,则会破坏dest字符串后面的\0,要避免这种情况发生

strncpy函数的模拟实现方法:

#include<stdio.h>
#include<assert.h>
//模拟实现strncpy
//方法一
//char* my_strncpy(char* dest, const char* src, size_t n)
//{
//	char* dest_start = dest;
//	while ((n > 0) && (*src != '\0'))
//	{
//		*dest = *src;
//		dest++;
//		src++;
//		n--;
//	}
//	while (n > 0)
//	{
//		*dest = '\0';
//		dest++;
//		n--;
//	}
//	return dest_start;
//}

//方法二
char* my_strncpy(char* dest, const char* src, size_t count)
//count比n更有实际意义
{
	assert(dest != NULL);//引用断言
	assert(src != NULL);
	char* start = dest;
	while (count && (*dest++ = *src++) != '\0')
	{
		count--;
	}
	if (count)
	{
		while (count--)
		{
			*dest++ = '\0';
		}
	}
	return start;
}

int main()
{
	char arr1[10] = "abcdefg";
	char arr2[] = "1234";
	size_t len = 0;
	scanf("%d", &len);
	my_strncpy(arr1, arr2, len);
	printf("%s", arr1);
	return 0;
}

3.2 strncat

函数介绍: strncat(string concatenate with specified number of characters)

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

头文件:string.h

函数名:strncat

函数参数:

-----参数1: destination,类型:char*,被追加字符的目的地位置,即接收追加字符的起始位置
-----参数2: source,类型:char* ,追加字符的源地址,即追加字符串的开始位置。
-----参数3: num,类型size_t,追加字符的个数,用来控制追加字符的长度。

函数返回类型:char* ,返回接收字符的起始位置。

函数功能:指定个数的字符串追加

重点内容

  1. Appends the first num characters of source to destination, plus a terminating null - character.
  2. lf the length of the C string in source is less than num, only the content up to the terminating null - character is copied.
  3. 如果追加的字符长度大于目的地空间的剩余容量,则出现越界访问,要避免这种情况发生。

使用注意思事项

  • strncat在追加字符串的时候,会自动在末尾处添加字符串结束标志’\0’。(这也是我们在追加的时候,不用关注原dest, src中’\0’,仅需关注追加字符的个数的原因)

strncat函数的模拟实现方法:

#include<stdio.h>
#include<assert.h>
//方法一
//char* my_strncat(char* dest, const char* src, size_t count)
//{
//	char* start = dest;
//	//dest找到\0的位置
//	while (*dest!='\0')
//	{
//		dest++;
//	}
//	while (count)
//	{
//		//将src中的字符追加给dest
//		*dest = *src;
//		dest++;
//		src++;
//		//如果src以及指向\0的位置,提前结束循环
//		if (*src == '\0')
//		{
//			break;
//		}
//		count--;
//	}
//	*dest = '\0';//字符个数追加完毕后,再单独追加'\0'
//	return start;
//}

//方法二
char* my_strncat(char* dest, const char* src, size_t count)
{
	assert(dest != NULL && src != NULL);
	char* start = dest;
	while (*dest++)
		;
	dest--;
	while (count--)
		if ((*dest++ = *src++) == '\0')
			return start;
	*dest = '\0';
	return start;
}
int main()
{
	char arr1[15] = "12345\0xxxxxxx";
	char arr2[] = "abcd";
	size_t count = 0;
	scanf("%d", &count);
	my_strncat(arr1, arr2, count);
	printf("%s", arr1);
	return 0;
}

3.3 strncmp

函数介绍: strncmp(string compare with specified number of characters)

int strncmp(const char* p1,const char* p2,size_t count);

头文件:string.h

函数名:strcmp

函数参数:

-----参数1: p1,char* 类型,表示用来比较的其中一个字符串。
-----参数2: p2,char* 类型,表示用来比较的另一个字符串。
-----参数3: count,size_t类型,表示参与比较的字符个数。

函数返回类型:int类型,根据比较的具体结果返回相应的数值(>0;<0;=0)

4.字符串查找

4.1 strstr

函数介绍: strstr(string search)

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

头文件:string.h

函数名:strstr

函数参数:

-----参数1: str1,char* ,用于查找字符串的母串。
-----参数2: str2,char*,待查找字符串的子串。

函数返回类型:char* ,返回查找到的地址

函数功能:查找字符串 / 找子字符串>

使用方法

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abbbcdefbcd";
	char arr2[] = "bcd";
	char* ret = strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("Can not find!\n");
	}
	else
	{
		printf("%s\n", ret);
	}
	return 0;
}

重点内容

  1. 如果在str1中查找了字串str2,则返回str1中字串str2的起始地址
  2. 如果查找不到,返回空指针NULL
  3. 如果str1中含有多个str2字串内容,返回的是第一个被查找到的str2起始地址

strstr函数的模拟实现方法:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <cassert>

char* my_strstr(const char* p1, const char* p2)
{
	assert(p1 != NULL);   //断言
	assert(p2 != NULL);

	char* s1 = NULL;
	char* s2 = NULL;
	char* cur = p1;

	if (*p2 == '\0')  //如果p2中只放了'/0',返回一个字符串
	{
		return (char*)p1;
	}

	while (*cur != '\0')
	{
		s1 = cur;  
		s2 = p2;

		while ((*s2 != '\0') && (*s1 != '\0') && (*s1 == *s2))
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cur;  //找到字串的情况
		}
		cur++;
	}
	return NULL;   //找不到字符的情况
}

int main()
{
	char* str1 = "abbbchjdfdj";
	char* str2 = "bbc";
	char* ret = my_strstr(str1, str2);
	
	if (ret == NULL)
	{
		printf("找不到\n");
	}
	else
	{
		printf("%s", ret);
	}

	return 0;
}

4.2 strtok

函数介绍: strtok(string tokenize)

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

头文件:string.h

函数名:strtok

函数参数:

-----参数1: str,要被分割的字符串起始位置
-----参数2: sep,被用于分割的字符集合起始位置

函数返回类型:char* ,标记的位置

函数功能:字符串分割

重点内容

  1. sep参数是个字符串,定义了用作分隔符的字符集合
  2. 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
  3. strtok函数找到str中的下一个标记,并将其用\0结尾,返回一个指向这个标记的指针。

(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)

  1. strtok函数的第一个参数不为(NULL),函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  2. strtok函数的第一个参数为(NULL),函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  3. 如果字符串中不存在更多的标记,则返回NULL指针。

使用方法:

int main()
{
	//192.168.31.121  网络ip地址 --点分十进制
	//192 168 31 121  ---strtok  .
	//[email protected] 邮箱地址
	//student_zhang whu edu --- @ .
	char arr[] = "[email protected]";
	char* p = "@."; //分割的字符集合

	char buf[100] = { 0 };
	char* ret = 0;//用于接收分割后标记的位置
	strcpy(buf, arr);//分割字符串之前先进行临时拷贝

	//分割buf中的字符串

	//一次只能分割一次,三段分割一共要调用三次,太挫了这种写
	ret = strtok(buf, p);
	printf("%s\n", ret);
	
	ret = strtok(NULL, p);
	printf("%s\n", ret);

	ret = strtok(NULL, p);
	printf("%s\n", ret);

	//一次性打印
	for (ret = strtok(buf, p); ret != NULL; ret = strtok(NULL, p))
	{
		printf("%s\n", ret);
	}

	return 0;
}

5.误信息报告

5.1 strerror

函数介绍: strerror(string error message)

char* strerror(int errnum);

头文件:string.h , errno.h

函数名:strerror

函数参数:errnum, int类型,表示错误码编号

函数返回类型:char* ,返回错误码对应的错误信息

函数功能:Get a system error message(strerror) or prints a user - supplied error

message(_strerror). 返回系统的错误信息(就是程序出错时,用这个函数返回错误的原因信息)

请添加图片描述

实际在使用的时候,错误码并非由我们来控制的,而是接收系统返回的错误信息

printf("%s\n", strerror(errno));
//errno是一个全局的错误码的变量
//当C语言的库函数在执行的过程中发生了错误,就会把对应的错误码,赋值到errno中
//errno需要引用头文件 errno.h

使用方法:

打开文件

#include<stdio.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	//当前路径下是没有test.txt文件的,所以应该会打开文件失败,错误码会储存
    
	if (pf == NULL)  //fopen函数返回指针,打开文件失败返回空指针
	{
		printf("%s\n", strerror(errno));//打印储存错误码对应错误
	}
	else
	{
		printf("Open file success!\n");
	}
	return 0;
}

5.2 perror

函数介绍:perror(print error message)

void perror(const char *s);

头文件:<string.h>, <stdio.h>

函数名:perror

函数参数:s, const char * 类型,表示一个可选的错误前缀字符串

函数返回类型:void,不返回任何值

函数功能:Print a system error message on standard error output, prefixed by the string s (if s is not NULL), and the program’s error message.

使用方法:

请添加图片描述

perror括号中的东西也会被打印出来,并加上“: ”
perror函数依然打印的时errno变量中错误码所对应的信息。

6.字符操作

6.1 字符分类

如果是,返回非零 ; 不是,返回零

函数如果其参数符合下列条件就返回真
iscntrl任何控制字符
isspace空白字符:空格 ’ ',换页 ‘\f’,换行 ‘\n’,回车 ‘\r’,制表符 '\t’或者垂直制表符 ‘\v’
isdigit十进制数字 0 ~ 9
isxdigit十六进制数字,包括所有十进制数字,小写字母a ~ f,大写字母A ~ F
islower小写字母a~z
isupper大写字母A~Z
isalpha字母a ~ z或A ~ Z
isalnum字母或者数字,a ~ z ,A ~ Z ,0 ~ 9
ispunct标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph任何图形字符
isprint任何可打印字符,包括图形字符和空白字符

6.2 字符转换

int tolower ( int c );转化为小写字母
int toupper ( int c );转化为大写字母

#include <stdio.h>
#include <ctype.h>
int main()
{
	int i = 0;
	char str[] = "I AM A STUDENT ";

	while (str[i])
	{
		if (isupper(str[i])) //判断是否是大写
		{
			str[i] = tolower(str[i]);//转为小写
		}
		i++;
	}
	printf("%s\n", str);
	return 0;
}

7.内存操作

7.1 memcpy

函数介绍:memcpy(memory copy)

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

头文件:string.h

函数名:memcpy

函数参数:

-----参数1:destination, 类型:char* ,表示内存拷贝的目的位置
-----参数2:source,类型:char *,表示内存拷贝的起始位置
-----参数3:count,类型:size_t,表示拷贝内存字节的个数

函数返回类型: void*, 实际上就是返回destination(目的地)的起始位置

函数功能:内存拷贝

重点内容

  1. 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
  2. 这个函数在遇到’\0’的时候并不会停下来。
  3. 如果source和destination有任何的重叠,复制的结果都是未定

memcpy函数的模拟实现方法:

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

void* my_memcpy(void* dest, const char* src, size_t num)
{   //void* 可接受所有类型指针,但不能解引用操作和运算,那肯定要使用强制类型转换
	void* dest_start = dest; //存储地址

	assert(dest && src);

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

		*((char*)dest)++ = *((char*)src)++;
	}
	return dest_start;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };

	my_memcpy(arr2, arr1, 20);//20是字节,强制类型转换为char*步长为1
	return 0;
}

使用方法

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr, 20);
	//arr2拷贝参数,也就是目的地
	//arr是源头
	//拷贝5个字符,一个字符4个字节,也就是20个字节
	return 0;
}

7.2 memmove

引入

假设我们有一个整型数组 1 2 3 4 5 6 7 8 9 10 ,如果我们想要将前5个数字拷贝到第3 - 8个位置上,也就是:

请添加图片描述

如果我们通过my_memcpy可以做到吗?试验以下就知道了:

得到的结果是: 1 2 1 2 1 2 1 8 9 10,
并不是想要的: 1 2 1 2 3 4 5 8 9 10

为什么呢?

从我们刚刚模拟实现memcpy中方法中,我们知道memcpy在进行拷贝的时候,是按照从前往后的方式进行的,如果这个地方按照从前往后的方式进行拷贝,那么拷贝一开始的时候,就会出现后面需要被拷贝的数据被覆盖掉,比如说3,一开始将1放到3这个位置,3就被覆盖掉了,后面如果要拷贝3,从这个位置取出数据的时候,实际上取出的是1。
既然从前往后的拷贝方式不行,那么从后往前拷贝呢?

分析后,可以发现从后向前的拷贝方式是可以的,不会出现后面需要被拷贝的数据提前被覆盖的情况。

但是,如果我们拷贝 3 4 5 6 7 到 1 2 3 4 5的位置上,那么从前往后的拷贝方式还行得通吗?
是不是发现从后向前拷贝会出现数据提前被覆盖的情况。所以这时候我们需要进行分情况讨论:
如下:

  1. 如果从低地址拷贝向高地址,需要从后往前(即示例)
  2. 如果从高地址拷贝向低地址,需要从前往后

函数介绍:memmove(memory move)

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

头文件:string.h

函数名:memmove

函数参数:

-----参数1:destination, 类型:char* ,表示内存移动的目的位置
-----参数2:source,类型:char* ,表示内存移动的起始位置
-----参数3:count,类型:size_t,表示移动内存字节的个数

函数返回类型: void*, 实际上就是返回destination(目的地)的起始位置

函数功能:内存移动

重点内容

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

memmove函数的模拟实现方法:

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

void* my_memmove(void* dest, const void* src, size_t num)
{
	void* dest_start = dest;
	assert(dest && src);
	if (dest < src)
	{
		//从前向后拷贝
		while (num--)
		{
			*(char*)dest = *(char*)src;
			++(char*)dest; //dest = (char*)dest + 1;
			++(char*)src;  //src = (char*)src + 1;
		}
	}
	else
	{
		//从后向前拷贝
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);//+num字节找到最后的字节就实现从后往前拷贝
		}
	}
	return dest_start;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };

	my_memmove(arr1 + 2, arr1, 20);
	return 0;
}

7.3 memcmp(简单了解)

函数介绍与重点内容

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

  1. 比较从ptr1和ptr2指针开始的num个字节
  2. 返回值如下 :
    请添加图片描述

使用方法

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[4] = { 1,2,3,5 };
	int arr2[4] = { 1,2,3,4 };
	int ret = memcmp(arr1, arr2, sizeof(arr1));
	if (ret > 0)
	{
		printf("arr1 > arr2");
	}
	else if (ret == 0)
	{
		printf("arr1 == arr2");
	}
	else
	{
		printf("arr1 < arr2");
	}
	return 0;
}

7.4 memset(简单了解)

函数介绍与重点内容

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

  1. 用:Sets buffers to a specified character.(将缓冲区设置为指定的字符)

使用方法:以字节为单位设置内存

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "abcdefg";
	memset(arr, '*', 4);
	printf("%s", arr);
	return 0;
}
int main()
{
	int arr[] = { 1,2,3,4 };
    //原来的内存:
    01 00 00 00
    02 00 00 00
    03 00 00 00
    04 00 00 00
 
	memset(arr, 1, 9);
    //修改后的内存:
    01 01 01 01
    01 01 01 01
    01 00 00 00
    04 00 00 00
 
	int i = 0;
 
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
 
	return 0;
}

标签:const,进阶,dest,C语言,char,int,内存,字符串,函数
From: https://blog.csdn.net/ydm_ymz/article/details/143702826

相关文章

  • 网页直播/点播播放器EasyPlayer.js RTSP播放器出现多路视频卡顿、内存开始飙升的原因
    EasyPlayer.jsRTSP播放器是TSINGSEE青犀流媒体组件系列中关注度较高的产品,经过多年的发展和迭代,目前已经有多个应用版本,包括RTSP版、RTMP版、Pro版以及js版,其中js版本作为网页播放器,受到了用户的广泛使用。1、问题说明在已经使用硬解码基础上,播放多路视频,会出现卡顿,内存开始飙......
  • Tomcat Windows 服务 JVM 内存参数设置
    Tomcat在Windows平台上启动服务的方式是CommonsDaemon,JVM的启动参数可以有多种设置方法。本文介绍CommonsDaemon的大致组成和参数设置方法。CommonsDaemon由两部分组成。一是由C语言开发负责和操作系统交互的平台相关程序,在Windows上平台相关部分是procrun,在Un......
  • 指针(进阶)
    重点讲述:1.字符指针2.数组指针3.指针数组4.数组传参和指针传参5.函数指针6.函数指针数组7.指向函数指针数组的指针8.回调函数1.字符指针在指针的类型中我们知道有一种指针类型为字符指针char*一般使用:还有一种使用方式如下:代码constchar*pstr="zhuying.";有......
  • Python小白学习教程从入门到入坑------第三十二课 生成器(语法进阶)
    目录一、生成器generator1.1生成器表达式1.1.1表达式一1.1.2表达式二二、可迭代对象、迭代器、生成器三者之间的关系2.1定义与特性2.2关系与区别一、生成器generator在Python中,生成器(Generators)是一种用于迭代对象的特殊类型函数。它们允许你生成一个序列......
  • Python小白学习教程从入门到入坑------第三十一课 迭代器(语法进阶)
    目录一、可迭代对象Iterable1.1可迭代对象的条件1.2for循环工作原理1.3isinstance()二、迭代器 Iterator2.1 __iter__() 和 __next__()2.2 可迭代对象&迭代器2.2.1定义与特性2.2.2 关系与转换2.2.3应用场景三、迭代器协议(了解即可)四、自定义迭代器类......
  • Git进阶实用命令
    总结最常用的git命令操作。Mac推荐可视化软件Sourcetree1.本地仓库gitinit#初始化本地git以下所有操作的前提条件gitadd-A#添加当前所有变动文件到本地缓存区gitcommit-m'<commit-word>'#提交缓存区内容到本地仓库gitcommit-am'<commit-word>'#上......
  • Elasticsearch:管理和排除 Elasticsearch 内存故障
    作者:来自Elastic StefNestor随着ElasticCloud提供可观察性、安全性和搜索等解决方案,我们将使用ElasticCloud的用户范围从完整的运营团队扩大到包括数据工程师、安全团队和顾问。作为Elastic支持代表,我很乐意与各种各样的用户和用例互动。随着受众的扩大,我看到了......
  • 分布式管理进阶:HarmonyOS Next 中的设备信息查询与状态监听
    本文旨在深入探讨华为鸿蒙HarmonyOSNext系统(截止目前API12)的技术细节,基于实际开发实践进行总结。主要作为技术分享与交流载体,难免错漏,欢迎各位同仁提出宝贵意见和问题,以便共同进步。本文为原创内容,任何形式的转载必须注明出处及原作者。在探索HarmonyOSNext的分布式管理服务时......
  • Chrome DevTools Protocol 进阶: Page域
    前言本章开始我们将进一步学习ChromeDevToolsProtocol(CDP),首先切入的内容是CDP中的域。在ChromeDevToolsProtocol(CDP)中,Page域是一个至关重要的部分,它负责控制浏览器页面的导航、加载、渲染以及其他与页面相关的操作。通过Page域,你可以执行页面跳转、截图、处理弹......
  • C语言-指针及变量的概念与使用
    1、指针的概念计算机中所有的数据都必须放在内存中,不同类型的数据占用的字节数不一样,例如int占用4个字节,char占用1个字节。为了正确地访问这些数据,必须为每个字节都编上号码,就像门牌号、身份证号一样,每个字节的编号是唯一的,根据编号可以准确地找到某个字节。下图是4......