C语言中字符串函数以及内存函数的使用和注意事项

目录

[0. 前言](#0. 前言)

1、求字符串长度函数

1.1、strlen

模拟实现

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

[2.1 strcpy](#2.1 strcpy)

模拟实现

2.2strcat

模拟实现

2.3strcmp

模拟实现

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

3.1strncpy

3.2strncat

3.3strncmp

4、字符串查找函数

4.1strstr

模拟实现

3.2strtok

实现自动分割字符串

4、错误信息报告函数

4.1、strerror

4.2、perror

5.内存操作函数

5.1、memcpy

模拟实现

5.2、memmove

模拟实现

5.3、memset

5.4、memcmp


0. 前言

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

1、求字符串长度函数

1.1、strlen

  • 1.strlen用于求字符串长度。

  • 2.包含头文件<string.h>。

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

  • 4.参数指向的字符串必须要以 '\0' 结束。
    注意:

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

  • 这里输出的应该是大于,为什么呢,就是这里的strlen函数的返回的是无符号类型的,所以-3会被当作无符号数来看待,

  • 由于strlen返回的是size_t类型,所以在输出时应该使用对应的格式说明符,如%zu

  • 因为strlen返回的是 '\0' 前面的字符个数,如果字符串中间本身就一个'\0',那么返回的值就会返回字符串中的'\0'之前的字符个数。

    例如:"abc\0def" 这个字符串,使用strlen函数会返回3

易错提醒

cpp 复制代码
请问ret的值是多少?
int ret = strlen("abc") - strlen("abcdef");

答案是3,因为函数的返回值为size_t,是无符号的整型。


strlen函数是C语言中的一个库函数,用于计算字符串的长度(不包括字符串末尾的空字符\0)。它位于<string.h>头文件中。

strlen函数的原型如下:

cpp 复制代码
size_t strlen(const char *str);
  • const char *str:指向要计算长度的字符串的指针。

strlen函数会从指定的字符串地址开始遍历,直到遇到字符串结束标记\0为止 ,统计期间遇到的字符数量,然后返回计数结果。

下面是一个示例代码,展示了如何使用strlen函数来计算字符串的长度:

cpp 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello, World!";
    size_t len = strlen(str);

    printf("The length of the string is: %zu\n", len);

    return 0;
}

输出结果为:

cpp 复制代码
The length of the string is: 13

在上面的例子中,strlen函数被用来计算字符串str的长度,并将结果存储在len变量中,然后通过printf函数进行输出。



模拟实现

cpp 复制代码
int my_strlen(char* str)
{
	int count = 0;
	while (*arr != '\0')
	{
		count++;
		arr++;
	}
	return count;
}

方法二、

cpp 复制代码
size_t my_strlen(const char* str) {
    const char* end = str;
    while (*end) {
        ++end;
    }
    return end - str;
}

指针-指针的方式实现先把初始地址给end,然后end向后走直到遇到\0,最后返回初始地址和结束地址的差值就是中间的字符个数。

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

2.1 strcpy

`strcpy`函数是C语言中用于字符串复制的函数,其原型为:

cpp 复制代码
char* strcpy(char* destination, const char* source);

`strcpy`函数将源字符串 `source` 复制到目标字符串 `destination` 中,包括字符串结束符 `'\0'` 。复制的过程会覆盖原来 `destination` 中的内容。

`strcpy`函数的工作原理是从源字符串 `source` 的第一个字符开始,逐个将字符复制到目标字符串 `destination` 中,直到遇到字符串结束符 `'\0'` 为止。复制完成后,目标字符串 `destination` 会成为与源字符串 `source` 相同的副本。

需要注意的是,为了避免内存溢出,目标字符串 `destination` 的空间应该足够大,至少能够容纳源字符串 `source` 和字符串结束符 `'\0'`。

`strcpy`函数的返回值是目标字符串 `destination` 的指针,即函数执行完后,返回指向目标字符串的指针。

下面是一个简单的示例代码,演示了 strcpy 函数的使用:

cpp 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char source[] = "Hello, World!";
    char destination[20];

    strcpy(destination, source);

    printf("Copied string: %s\n", destination);

    return 0;
}

上述代码会输出:Copied string: Hello, World!

注意事项:

  • strcpy用于拷贝字符串,将字符串2拷贝到字符串1当中。
  • 包含头文件**<string.h>。**
  • 源字符串必须以 '\0' 结束。
  • 会将源字符串中的 '\0' 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可变。

验证确实是拷贝了\0

源字符串必须以\0结尾
目标空间必须可变化
这里就没法完成复制了,因为arr1是一个常量字符串没有办法被修改

模拟实现

cpp 复制代码
char* my_strcpy(char* dest,const char* src)
{
	char* ret = dest;
	while (*dest = *src)
	{
		dest++;
		src++;
	}
	return ret;
}

2.2strcat

catconcatenate(连接)的缩写。

strcat函数是C语言中用于字符串拼接的函数,其原型为:

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

效果 strcat函数将源字符串 source 追加 到目标字符串 destination 的末尾,拼接的结果会改变目标字符串 destination
工作原理:strcat函数的工作原理 是首先定位目标字符串 destination 的结束符 '\0' 的位置 ,然后从源字符串 source 的第一个字符开始,逐个将字符复制到目标字符串的结束符之前 ,直到遇到源字符串的结束符 '\0' 为止。完成拼接后,目标字符串 destination 会包含原有内容和源字符串 source 的内容。
需要注意的是,为了避免内存溢出,目标字符串 destination 的空间应该足够大,以容纳源字符串 source 的内容及拼接后的结果。

源字符串必须以 '\0' 结束(保证找得到目标空间的末尾),在拷贝时会把源字符串的 '\0 '也拷贝过去

不能字符串自己追加自己,因为当自己追加自己的时候,追加的过程中会将目标字符串的 '\0' 覆盖掉,(因为自己追加自己两个指针指向的是同一块空间)而有因为此时目标字符串就是源字符串,就会导致源字符没有 '\0' ,将会一直拼接下去导致死循环。

虽然有些环境中该函数可以完成自己拼接自己,但是C语言的标准中并未规定strcat可以自己拼接自己,所以这个函数最好不要使用在自己拼接自己的情况下。如果真有自己追加自己的场景,建议使用strncat函数
返回值:strcat函数的返回值 是目标字符串 destination 的指针,即函数执行完后,返回指向目标字符串的指针。

模拟实现

1.先找到目标空间的\0

cpp 复制代码
char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);

	char* ret = dest;
	//1. 找目标空间中的\0
	while (*dest)
	{
		dest++;
	}
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";
	my_strcat(arr1, arr2);

	printf("%s\n", arr1);
	return 0;
}

问题:字符能不能自己给自己追加?

不能

源头和目标都是一块空间了,当src把h替代了\0,之后src就没有办法遇到\0了,因为追加第一个的时候就修改掉了\0

2.3strcmp

strcmp 函数用于比较两个字符串,它返回一个整数值,表示两个字符串的大小关系。

函数原型如下:

cpp 复制代码
int strcmp(const char* str1, const char* str2);

参数 str1str2 是需要比较的两个字符串。

  • 如果 str1str2 相等,strcmp 返回值为 0。
  • 如果 str1 大于 str2strcmp 返回值大于 0。
  • 如果 str1 小于 str2strcmp 返回值小于 0。

下面是一个示例代码,演示了 strcmp 函数的用法:

cpp 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char str1[] = "apple";
    char str2[] = "banana";

    int result = strcmp(str1, str2);

    if(result == 0) {
        printf("str1 和 str2 相等\n");
    } else if(result > 0) {
        printf("str1 大于 str2\n");
    } else {
        printf("str1 小于 str2\n");
    }

    return 0;
}

输出结果为:

cpp 复制代码
str1 小于 str2

上述示例中,strcmp 函数比较了两个字符串 "apple""banana",并根据比较结果输出相应的信息。由于字母 "a" 的 ASCII 值小于字母 "b",因此 str1 小于 str2

易错:strcmp不是比较字符串长度的,而是比较对应位置上字符的大小(ASCII)

模拟实现

cpp 复制代码
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);

	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;

		str1++;
		str2++;
	}

	return (*str1 - *str2);
}
//VS
//> 1
//= 0
//< -1
//

int main()
{
	int ret = my_strcmp("bbq", "bcq");
	if (ret>0)
		printf(">\n");

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

先排除相等的部分,剩下不相等的部分才进行比较,第一个while循环中*str1=='\0'判读是不是读完了

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

3.1strncpy

函数介绍:

strncpy 函数是一个用于复制字符串的函数。它的原型如下:

cpp 复制代码
char *strncpy(char *dest, const char *src, size_t n);

strncpy 函数将从源字符串 src 复制最多n 个字符到目标字符串 dest 中。

如果 src 的长度小于 n,则复制完 src 中的所有字符后,将剩余部分用空字符 \0 填充直到n

如果 src 的长度大于等于 n,则仅复制前 n 个字符,不会添加额外的空字符。
需要注意的是,strncpy 函数没有在目标字符串 dest 的末尾自动添加终止符 \0 的能力。因此,在使用 strncpy 复制字符串后,需要手动在 dest 的最后一个元素添加 \0,以确保目标字符串正确终止。

相比较于strcpy函数多了一个参数 n。

下面是一个示例代码,展示了如何使用 strncpy 函数:

cpp 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, World!";
    char dest[20];

    strncpy(dest, src, sizeof(dest));
    dest[sizeof(dest) - 1] = '\0';

    printf("Source: %s\n", src);
    printf("Destination: %s\n", dest);

    return 0;
}

输出结果:

cpp 复制代码
Source: Hello, World!
Destination: Hello, World!

在这个示例中,我们将源字符串 "Hello, World!" 复制到了目标字符串 dest 中,并保证了目标字符串的正确终止。由于 dest 的大小为 20,所以在复制后,目标字符串中的剩余部分将被空字符 \0 填充。

3.2strncat

  • 区别也仅与strcat差一个参数,记录要操作的个数。
  • 使用strncat追加,当结束追加时,就算没到\0,也会在末尾追加一个\0。
  • 如果源字符串的长度小于num ,则追加完源字符串之后,会自动停止追加。注意此处与strncpy的区别。
  • 包含头文件**<string.h>。**

下面是示例代码:

cpp 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char s1[20] = "Hello ";
    char s2[] = "world!";
    
    strcat(s1, s2);
    printf("Result of strcat: %s\n", s1);
    
    char s3[20] = "Hello ";
    char s4[] = "world!";

    strncat(s3, s4, 5);
    printf("Result of strncat: %s\n", s3);
    
    return 0;
}

输出结果为:

cpp 复制代码
Result of strcat: Hello world!
Result of strncat: Hello world

可以看到,在使用strncat函数时,只拼接了源字符串的前5个字符。

3.3strncmp

  • 区别也仅与strcmp差一个参数,记录要操作的个数。
  • 包含头文件**<string.h>。**

下面是一个使用strncmp函数比较两个字符串的示例代码:

cpp 复制代码
#include <stdio.h>
#include <string.h>

int main()
{
    char str1[] = "Hello";
    char str2[] = "World";
    int result = strncmp(str1, str2, 3); // 只比较前3个字符

    if (result == 0)
    {
        printf("str1和str2的前3个字符完全相同\n");
    }
    else if (result < 0)
    {
        printf("str1小于str2\n");
    }
    else
    {
        printf("str1大于str2\n");
    }

    return 0;
}

以上代码输出结果为"str1小于str2",因为在比较前3个字符时,'H'的ASCII值为72,'W'的ASCII值为87,72小于87。

4、字符串查找函数

4.1strstr

strstr函数是一个C语言字符串处理函数,用于在一个字符串中查找另一个字符串的第一次出现位置。

函数原型如下:

cpp 复制代码
char* strstr(const char* str1, const char* str2);

函数接受两个参数:str1和str2。str1是源字符串,在该字符串中进行查找操作。str2是要查找的目标字符串。

函数的返回值是一个指向第一次在str1中出现str2的位置的指针。如果未找到str2,函数返回NULL。

strstr函数的工作原理是基于字符串匹配算法,通常使用的是KMP算法或Boyer-Moore算法等。它会从str1的第一个字符开始比较,如果找到了一个匹配的字符,就会继续比较下一个字符。如果完全匹配,就返回匹配位置的指针。如果未能找到匹配,就继续在剩余的str2中继续查找。

cpp 复制代码
int main()
{
	char arr1[] = "abcdefghidef";   //def出现了两次
	char arr2[] = "def";
	char* ret = strstr(arr1, arr2);
	if (ret == NULL)
		printf("找不到\n");
	else
		printf("%s\n", ret);
	return 0;
}

结果是defghidef

模拟实现

cs 复制代码
char* my_strstr(char *str1, char* str2)
{
	char* cp = str1;
	char* s1 = cp;
	char* s2 = str2;

	if (*str2 == '\0')
		return str1;

	while (*cp)
	{
		//开始匹配
		s1 = cp;
		s2 = str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
			return cp;

		cp++;
	}

	return NULL;
}


int main()
{
	char arr1[] = "abbbcdef";
	char arr2[] = "bbc";

	char* ret = my_strstr(arr1, arr2);
	if (ret != NULL)
		printf("%s\n", ret);
	else
		printf("找不到\n");

	return 0;
}

Cp最开始指向起始位置,cp赋给s1

*cp不等于\0,因为等于\0说明检查完了,就返回NULL

S1和s2来遍历字符串

没有匹配完全的话,跳出第二个while

循环,然后cp++,改变开始匹配的位置,然后把cp赋给s1,重新赋值给s1是因为要找到开始匹配的正确位置,每次cp都像后面移动一位

应该返回cp因为只有*s1==*s2才会进入循环,这个时候cp里面是第一次出现位置的指针。

只有*s2为\0才是才是在str1中匹配到了str2

最前面是特殊情况是str2是空字符串

3.2strtok

strtok函数是C语言中的一个字符串分割函数,其原型为:

cpp 复制代码
char *strtok(char *str, const char *delim);

该函数的作用是将字符串str按照指定的分割符delim进行分割,并返回分割后的第一个子字符串。同时,该函数会静态地记录当前的分割位置,便于下一次调用时继续分割剩余的字符串。

函数的使用步骤如下:

  1. 在第一次调用时,需要将待分割的字符串str传入,之后的调用中将传入NULL。strtok函数会将其修改,将分割出的子字符串以'\0'结尾并返回该子字符串的指针。
  2. 在第一次调用时,需要将分割符delim传入。之后的调用中,delim可以传入NULL。如果传入NULL,则将沿用上一次调用时的分割符。
  3. 使用返回的子字符串指针进行处理操作,之后再次调用strtok函数可以获取下一个分割出的子字符串指针。直到返回NULL,表示没有更多的子字符串可供分割。
  4. delimiters参数是个字符串,定义了用作分隔符的字符集合。

    第一个参数指定一个字符串,它包含了0个或者多个由delimiters字符串中一个或者多个分隔符分割的标记。

    strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)

    strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。

    strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。

    如果字符串中不存在更多的标记,则返回 NULL 指针

下面是一个简单的示例代码,展示了如何使用strtok函数分割一个字符串:

cpp 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "Hello,World!How,are,you?";
    char *token;

    // 第一次调用strtok函数
    token = strtok(str, ",!");
    printf("%s\n", token);  // 输出"Hello"

    // 之后的调用
    while ((token = strtok(NULL, ",!")) != NULL) {
        printf("%s\n", token);
    }

    return 0;
}

该代码首先将字符串"Hello,World!How,are,you?"传给strtok函数进行第一次调用。由于传入的分割符为",!",所以它会将字符串分割成"Hello"、"World"、"How"、"are"和"you?"五个子字符串。然后,通过循环调用strtok函数,我们可以依次输出这五个子字符串。

第一次调用把,改为\0然后返回H的地址,第二次函数已经记住了第一次标记的位置,然后向后访问直到找到下一个标记然后改为\0,再传回来W的地址。

实现自动分割字符串

cpp 复制代码
	char* ret = NULL;

	for (ret = strtok(copy, sep); ret != NULL; ret=strtok(NULL, sep))
	{
		printf("%s\n", ret);
	}

初始部分就是第一次调用strtok函数,判断部分是判断

调整部分是传空指针直到切割完了。

循环中的判断部分 ret != NULL 是用来判断 strtok 函数返回的切割结果是否为 NULL,如果是 NULL,则意味着没有更多的切割结果了,循环就会结束。换句话说,当 strtok 函数切割完所有的子字符串之后,它会返回 NULL,这时循环就会终止。

4、错误信息报告函数

4.1、strerror

strerror 函数是一个 C 标准库中的函数,它可以根据给定的错误码返回对应的错误消息字符串。

strerror 函数的原型如下:

cpp 复制代码
#include <string.h>

char *strerror(int errnum);

其中,errnum 是一个整数类型的参数,表示错误码。函数会根据 errnum 找到对应的错误消息字符串,并返回该字符串的指针。

使用 strerror 函数,我们可以根据系统函数返回的错误码获取相应的错误信息,从而更好地了解问题所在,方便进行调试和错误处理。

  • strerror函数是将错误码翻译成错误信息,返回错误信息的字符串起始地址。
  • 包含头文件**<string.h>。**
  • C语言中使用库函数的时候,如果发生错误,就会将错误码放在errno的变量中,errno是一个 全局变量,可以直接使用。
cpp 复制代码
int main()
{
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d: %s\n", i, strerror(i));//
	}
	return 0;
}

每一个错误码都对应一个错误信息。

【使用方式】

以打开文件为例子,fopen以读的形式打开文件,当文件存在时打开成功,文件不存在时打开失败,并返回空指针。可以利用这个来设置一个打开失败时的错误信息告知。

【使用方法】

cpp 复制代码
int main()
{
	FILE* pf = fopen("add.txt", "r");  //当前文件路径中并没有add.txt文件,打开失败
	if (pf == NULL)
	{
		printf("打开文件失败,原因是:%s\n", strerror(errno));
		return 1;
	}
	else
	{
		printf("打开文件成功\n");
	}
	return 0;
}

fopen 是 C 语言标准库中的一个函数,用于打开一个文件。函数声明如下:

FILE *fopen(const char *filename, const char *mode);

fopen 函数接受两个参数,第一个参数 filename 是一个字符串,表示文件的路径或名称;第二个参数 mode 是一个字符串,表示文件的打开模式,可以是以下几种之一:

  • "r":以只读方式打开文件。
  • "w":以写入方式创建文件,如果文件已存在则清空文件内容。
  • "a":以写入方式打开文件,如果文件不存在则创建文件,新增的内容会被追加到文件末尾。
  • "rb":以二进制只读方式打开文件。
  • "wb":以二进制写入方式创建文件,如果文件已存在则清空文件内容。
  • "ab":以二进制写入方式打开文件,如果文件不存在则创建文件,新增的内容会被追加到文件末尾。

fopen 函数返回一个 FILE* 类型的指针,如果打开文件成功,则返回指向该文件的指针;如果打开文件失败,则返回 NULL

4.2、perror

perror 是 C 语言标准库中的一个函数,用于打印与当前错误代码相对应的错误信息到标准错误文件 stderr 中。函数声明如下:

void perror(const char *s);

perror 函数接受一个参数 s,表示要输出的错误信息前缀。它会根据全局变量 errno 的值,在标准错误文件上输出一个相应的错误信息,形如 s: 错误信息
perror也是用于翻译错误信息 ,但与strerror不同的是,perror会直接打印错误码所对应的错误信息。而perror中传递的字符串参数就是自定义显示信息的部分,打印的结果就是 自定义显示信息:错误信息

包含头文件<stdlib.h>

可以简单理解为:perror = printf + strerror 即翻译又打印

5.内存操作函数

为了满足各种数据都可以使用的情况而不只是字符串,我们要从内存入手。下面我们来学习一下内存操作函数。

5.1、memcpy

memcpy() 函数是 C 语言中的一个标准库函数,它用于将内存块的内容从源地址复制到目标地址。它的函数原型如下:

cpp 复制代码
void *memcpy(void *dest, const void *src, size_t n);
  • dest:目标地址,即复制后的数据将存储的位置。
  • src:源地址,即要被复制的数据的起始位置。
  • n:要复制的字节数。
  • 拷贝结束之后返回目标空间的起始地址
    memcpy() 函数会将 src 地址开始的 n 个字节的内容复制到 dest 地址开始的内存区域。需要注意的是,复制过程中不会考虑字符的含义,只是简单地复制二进制数据

函数memcpy从source的位置开始向后拷贝num个字节的数据到destination的内存位置。

包含头文件<string.h>

这个函数在遇到 '\0' 的时候并不会停下来。

如果source和destination有任何的重叠,复制的结果都是未定义的。

因为C语言标准中并未规定memcpy能适用于重叠内存的拷贝,因此不重叠内存的拷贝才使用memcpy,而重叠内存的拷贝使用接下来讲解的memmove函数。

下面是一个使用 memcpy() 函数的示例:

cpp 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    const char src[] = "Hello, World!";
    char dest[100];

    memcpy(dest, src, strlen(src) + 1);
    printf("Copied string: %s\n", dest);

    return 0;
}

在这个示例中,我们首先定义了一个源字符串 src,然后创建了一个足够大的目标字符串 dest 来存储复制后的内容。然后,memcpy() 函数将 src 字符串的内容复制到 dest 字符串,并通过 printf 函数打印出复制结果。

模拟实现

cpp 复制代码
函数拷贝结束后,返回目标空间的起始地址
void* my_memcpy(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(src && dest);

	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	//01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00

	int arr2[20] = { 0 };
	my_memcpy(arr2, arr1, 21);
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

写成(char*)dest++是不能实现指针先后走一个bit的,因为这里强制转换是临时的,++的时候已经没用了。

如果拷贝有重叠的空间会怎么样呢

比如传参为arr+2和arr1

cpp 复制代码
void* my_memcpy(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(src && dest);

	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

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

结果不是我们想要的那样1 21 2 3 4 5 8 9 10

因为空间上有重叠的地方

把34拷贝为12之后想要把56拷贝为34就没有办法实现了因为34已经被改成12了。

memcpy函数是用来处理不重叠的内存的拷贝的,处理有重叠的内存的拷贝的使用memmove函数

5.2、memmove

原来出现的错误的原因是因为拷贝给后面的空间的时候前


想办法不被覆盖。到着来拷贝可以解决问题先把5拷贝到7的位置,4拷贝到6的位置,


但是不能一劳永逸。比如如果我把src和des调换就出错了

dest在src前面就要倒着拷贝,dest在src后面就要
一次性解决:

如果dest落在src前面那就是从前向后拷贝就是说先把src的第一个位置拷贝到dest依次往后

如果dest落在src到末尾之间的位置,那就是从后向前面拷贝

指针可以比较大小

模拟实现

cpp 复制代码
void* my_memmove(void* dest, const void* src, size_t num)
{
	void* ret = dest;
	assert(dest && src);

	if (dest < src)
	{
		//前->后
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		//后->前
		while (num--)//20
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}

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

后向前拷贝要先找到src+num的位置,这个是第一个要拷贝的。

5.3、memset

memset()函数用于将一块内存区域的每个字节都设置为特定的值。其函数原型如下:

void *memset(void *ptr, int value, size_t num);
  • ptr:指向要设置值的内存区域的指针。
  • value:要设置的值,它的类型是int,但会被转换成unsigned char
  • num:要被设置的字节数。
  • 将ptr所指向空间的前num个字节设置为指定值value。
  • 包含头文件**<string.h>**
    memset()函数在初始化内存块、清零内存块、以及将内存块中的特定字节设置为某个值时非常有用。例如:
cpp 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char str[50];
    
    strcpy(str, "Hello");
    printf("Before memset: %s\n", str);
    
    memset(str, '$', 3);
    printf("After memset: %s\n", str);
    
    return 0;
}

输出结果为:

cpp 复制代码
Before memset: Hello
After memset: $$$lo

在上述示例中,memset()函数将字符串str的前3个字节设置为'$',修改了字符串的一部分内容。

5.4、memcmp

memcmp()函数用于比较两个内存区域的内容是否相同。其函数原型如下:

int memcmp(const void *ptr1, const void *ptr2, size_t num);
  • ptr1:指向要比较的第一个内存区域的指针。
  • ptr2:指向要比较的第二个内存区域的指针。
  • num:要比较的字节数。

memcmp()函数将比较两个内存区域中的字节内容,并返回一个整数结果,表示比较结果的大小关系:

  • 如果ptr1ptr2指向的内存区域完全相同,则返回值为0。
  • 如果ptr1指向的内存区域小于ptr2指向的内存区域,则返回值小于0。
  • 如果ptr1指向的内存区域大于ptr2指向的内存区域,则返回值大于0。

下面是一个使用memcmp()函数的示例:

cpp 复制代码
#include <stdio.h>
#include <string.h>

int main() {
    char str1[] = "Hello";
    char str2[] = "World";
    
    int result = memcmp(str1, str2, 5);
    
    if (result == 0) {
        printf("str1 and str2 are equal.\n");
    } else if (result < 0) {
        printf("str1 is less than str2.\n");
    } else {
        printf("str1 is greater than str2.\n");
    }
    
    return 0;
}

输出结果为:

str1 is less than str2.

在上述示例中,memcmp()函数比较了两个字符串str1str2的前5个字节内容 ,发现str1小于str2,因此打印出相应的结果。

相关推荐
代码雕刻家26 分钟前
数据结构-3.9.栈在递归中的应用
c语言·数据结构·算法
吾爱星辰1 小时前
Kotlin 处理字符串和正则表达式(二十一)
java·开发语言·jvm·正则表达式·kotlin
ChinaDragonDreamer1 小时前
Kotlin:2.0.20 的新特性
android·开发语言·kotlin
IT良1 小时前
c#增删改查 (数据操作的基础)
开发语言·c#
Kalika0-02 小时前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法
_.Switch2 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
代码雕刻家2 小时前
课设实验-数据结构-单链表-文教文化用品品牌
c语言·开发语言·数据结构
一个闪现必杀技2 小时前
Python入门--函数
开发语言·python·青少年编程·pycharm
Fan_web2 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
龙图:会赢的2 小时前
[C语言]--编译和链接
c语言·开发语言