【C语言航路】第十一站:字符串、字符和内存函数

news2025/1/19 19:42:29

目录

一、字符串函数

1.strlen

(1)strlen的库函数文档

(2)strlen的模拟实现

(3)strlen的注意事项

2.strcpy

(1)strcpy的库函数文档

 (2)strcpy的使用以及注意事项

(3)strcpy的模拟实现

3.strcat

(1)strcat的库函数文档

(2)strcat的使用以及注意事项

(3)strcat的模拟实现

(4)strcat自己对自己追加

4.strcmp

(1)strcmp库函数文档

(2)strcmp的使用

(3)strcmp的模拟实现

注意事项(函数不安全的原因)

5.strncpy

(1)strncpy库函数文档

(2)strncpy的使用以及注意事项

(3)strncpy的模拟实现

6.strncat

 (1)strncat的库函数文档

(2)strncat的使用以及注意事项

(3)strncat的模拟实现

7.strncmp

(1)strncmp的库函数文档

(2)strncmp的使用

8.strstr

 (1)strstr库函数文档

(2)strstr的使用

(3)strstr的模拟实现

9.strtok

(1)strtok的库函数文档

(2)strtok的使用以及注意事项

10.strerror

(1)strerror的库函数文档

(2)strerror的使用

(3)perror的使用

二、字符函数

1.字符分类函数

2.字符转换函数

3.利用字符函数,将字符串中的大写字母改为小写打印出来

三、内存函数

1.memcpy

(1)memcpy的库函数文档

 (2)memcpy的使用以及注意事项

(3)模拟memcpy函数

2.memmove

(1)memcpy的缺陷

(2)memmove的库函数文档

(3)memmove的模拟实现

(4)memmove的使用以及注意事项

3.memcmp

(1)memcmp的库函数文档

(2)memcmp的使用

4.memset

(1)memset的库函数文档

(2)memset的使用

总结


一、字符串函数

1.strlen

(1)strlen的库函数文档

如下图所示,是strlen在库函数中的文档。

它的参数是const char*类型的,这是考虑到它不会被改变的原因

返回类型是size_t类型的,这是考虑到它计算的是长度不会是负数的原因

这个函数返回的是一个字符串的长度,传入一个地址,计算的是\0字符之前的长度

(2)strlen的模拟实现

在这里我们采用三种方式来实现:循环计数、递归、指针减指针

#include<stdio.h>
#include<assert.h>
//循环计数
int my_strlen1(const char* str)
{
	assert(str);
	int count = 0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
}
//递归
int my_strlen2(const char* str)
{
	assert(str);
	if (*str == NULL)
	{
		return 0;
	}
	return 1 + my_strlen2(str + 1);
}
//指针减指针
int my_strlen3(const char* str)
{
	assert(str);
	const char* start = str;
	while (*str != '\0')
	{
		str++;
	}
	return str - start;

}
int main()
{
	char arr[] = "abcdef";
	int len = my_strlen3(arr);
	printf("%d\n", len);
	return 0;
}

(3)strlen的注意事项

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

2.参数指向的字符串必须要以 '\0' 结束
3.注意函数的返回值为size_t,是无符号的

关于第三点注意事项,我们在这里着重说一下

#include<stdio.h>
#include<string.h>
int main()
{
	if (strlen("abc") - strlen("abcdef") > 0)
	{
		printf(">\n");
	}
	else
	{
		printf("<=\n");
	}
	return 0;
}

这段代码的运行结果是

肯定与我们的设想是不一样的,因为strlen("abc")计算出来的是3,strlen("abcdef")计算出来的是6,虽然看上去好像3-6是-3,应该是<=,但是要主要这里的都是无符号的,计算出来的结果也是无符号的。所以这个数其实在内存中来看是一个很大的数。还是大于0的,所以是>

2.strcpy

(1)strcpy的库函数文档

它的参数是char* destination 和const char* source,destination的意思是目标空间的地址,

source的意思是源头空间的地址,这个地址里面的值是不可以被修改的。

功能是将source处的字符串拷贝到destination处

返回类型是char*,意思是将destination处的地址返回

 (2)strcpy的使用以及注意事项

1.源字符串必须以 '\0' 结束。
2.会将源字符串中的 '\0' 拷贝到目标空间。
3.目标空间必须足够大,以确保能存放源字符串。
4.目标空间必须可变。

在下面这段代码中

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "xxxxxxxxxxxxxxxxxx";
	char arr2[] = "hello world";
	strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

我们直接从调试里面查看数组的值

在下面这段代码中

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "xxxxxxxxxxxxxxxxxx";
	char arr2[] = "hello world";
	strcpy(arr2, arr1);
	printf("%s\n", arr1);
	return 0;
}

出现了错误,这是因为,arr2的空间不是足够大。

在下面这段代码中

#include<stdio.h>
#include<string.h>
int main()
{
	char* p = "xxxxxxxxxxxxxxxxxx";
	char arr2[] = "hello world";
	strcpy(p, arr2);
	printf("%s\n", p);
	return 0;
}

程序直接崩溃,这是因为char* p是不可以被修改的

(3)strcpy的模拟实现

#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[] = "xxxxxxxxxxxxx";
	char arr2[] = "hello world";
	char* p = my_strcpy(arr1, arr2);
	printf("%s\n", p);
	return 0;
}

运行结果为

3.strcat

(1)strcat的库函数文档

1.它的参数是char* destination和const char* source,与strcpy是一样的。

2.它的功能是将source处的字符串追加到destination后面

3.它的返回类型是char*,返回destination的地址

(2)strcat的使用以及注意事项

1.源字符串必须以 '\0' 结束。
2.目标空间必须有足够的大,能容纳下源字符串的内容。
3.目标空间必须可修改。
4.字符串自己给自己追加,会陷入死循环

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[20] = "hello ";
	char* p = strcat(arr, "world");
	printf("%s\n", arr);
	return 0;
}

运行结果为

(3)strcat的模拟实现

思路就两步:

1.找到\0字符的位置

2.追加

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	char* ret = dest;
	//1.找到'\0'字符
	while (*dest != '\0')
	{
		dest++;
	}
	//2.追加
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr[20] = "hello ";
	char* p = my_strcat(arr, "world");
	printf("%s\n", arr);
	return 0;
}

(4)strcat自己对自己追加

这个其实是不可以的,会造成死循环的现象

假如说下面的字符串自己对自己追加的话

\0会被修改为a,后面的都会覆盖过去,这样我们就永远也找不到\0了,最终导致分配的空间用完, 使用了未分配的空间而崩溃

下图是我们模拟出来的strcat的自己对自己追加后的效果

如果是官方的库里面的话,似乎没有出现这个问题,这个是visual studio对这个问题进行了优化,在一些其他的ide上可能就会出现这个死循环问题,导致程序出现bug

4.strcmp

(1)strcmp库函数文档

1.这个函数有两个参数都是const char*类型的,因为我们不会进行修改,我们只会进行查看

2.这个函数的作用是比较两个字符串的大小,比较规则是:从第一个字符依次开始比较,一个字符一个字符比较,谁的ASCII码值大,谁就大。如果相等则比较后一个字符。

3.这个函数的返回值是int类型,如果str1大于str2,则返回一个大于0的数,如果相等则返回0,如果小于则返回小于0的一个数

4.在vs环境下:大于返回1,等于返回0,小于返回-1。但是在其他编译器上不一定成立

(2)strcmp的使用

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abc";
	int ret = strcmp(arr1, arr2);
	printf("%d\n", ret);
	return 0;
}

(3)strcmp的模拟实现

#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')
		{
			return 0;
		}
		str1++;
		str2++;
	}
	if (*str1 > *str2)
	{
		return 1;
	}
	else
	{
		return -1;
	}
	//在一些编译器上是这样实现的
	//return *str1 - *str2;
}
int main()
{
	char arr1[] = "abcefg";
	char arr2[] = "abc";
	int ret = my_strcmp(arr1, arr2);
	printf("%d\n", ret);
	return 0;
}

注意事项(函数不安全的原因)

strcpy,strcat,strcmp这些函数都是不安全的函数,因为他们都是长度不受限制的函数,如果目标空间不是很大,则会出现问题。所以我们vs上使用这些函数需要使用开头的那个预处理指令

#define _CRT_SECURE_NO_WARNINGS 1

而为了让这些更安全,我们就有了strncpy,strncat,strncmp这些长度受限制的函数

5.strncpy

(1)strncpy库函数文档

这个函数有三个参数,char* destination,const char* source和size_t num,前两个参数的意思是目标空间的地址和源头的地址,num的意思是要拷贝几个字节

意思是拷贝前num个字节到destination中

返回类型是char*返回destination的地址

 

(2)strncpy的使用以及注意事项

1.拷贝num个字符从源字符串到目标空间。
2.如下图1所示,如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
3.如下图2所示,我们在使用的时候要注意,不会将最后的\0给拷贝进来,需要拷贝几个字符就拷贝几个字符.

(3)strncpy的模拟实现

需要注意的事项是,由于拷贝受两个条件控制

如果num为0导致的结束的话,也就是拷贝了一部分,那么我们就不会补充\0

如果是由于源头字符串拷贝完了,但是num还没结束导致的结束,那么我们就要补充\0,要注意我们这个num是少减了一次1的,所以要前置--

第一个循环中,num和赋值的操作是不可以进行交换顺序的,这是因为&&的短路现象

#include<stdio.h>
#include<assert.h>
char* my_strncpy(char* dest, const char* src, size_t num)
{
	assert(dest && src);
	char* ret = dest;
	while (num && (*dest++ = *src++))
	{
		num--;
	}
	if (num)
	{
		while (--num)
		{
			*dest++ = '\0';
		}
	}
	return ret;
}
int main()
{
	char arr[] = "xxxxxxxxxxxxxxxxxxxxx";
	char* p = my_strncpy(arr, "hello", 10);
	printf("%s\n", p);
	return 0;
}

6.strncat

 (1)strncat的库函数文档

这个的参数和返回类型与strncpy是一样的

不同的是函数的功能是追加source的前n的字符

这前n个字符追加后是需要补充一个\0的

(2)strncat的使用以及注意事项

1.对于这个函数,我们需要注意的就是追加之后后面会补充一个\0的

2.即便超出了source的范围,也只是补一个\0,不会补充多个\0

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "xxx\0xxxxxxxxxxxxxxx";
	char* p = strncat(arr, "hello", 3);
	return 0;
}

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "xxx\0xxxxxxxxxxxxxxx";
	char* p = strncat(arr, "hello", 10);
	return 0;
}

(3)strncat的模拟实现

#include<stdio.h>
#include<assert.h>
char* my_strncat(char* dest, const char* src, size_t num)
{
	assert(dest && src);
	char* ret = dest;

	while (*dest != '\0')
	{
		dest++;
	}
	while (num--)
	{
		if ((*dest++ = *src++) == '\0')
		{
			return ret;
		}
	}
	*dest = '\0';
	return ret;
}
int main()
{
	char arr[] = "xxx\0xxxxxxxxxxxxxxx";
	char* p = my_strncat(arr, "hello", 3);
	return 0;
}

7.strncmp

(1)strncmp的库函数文档

函数的功能是比较前n个字符的大小,返回一个值。

如果str1大,则返回大于0的数

如果str2大,则返回小于0的数

如果相等,则返回0

(2)strncmp的使用

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

#include<stdio.h>
#include<string.h>
int main()
{
	char* p1 = "abcdef";
	char* p2 = "abcfda";
	int ret = strncmp(p1, p2, 3);
	printf("%d\n", ret);
	return 0;
}

#include<stdio.h>
#include<string.h>
int main()
{
	char* p1 = "abcdef";
	char* p2 = "abcfda";
	int ret = strncmp(p1, p2, 4);
	printf("%d\n", ret);
	return 0;
}

#include<stdio.h>
#include<string.h>
int main()
{
	char* p1 = "abdef";
	char* p2 = "abcfda";
	int ret = strncmp(p1, p2, 4);
	printf("%d\n", ret);
	return 0;
}

8.strstr


 (1)strstr库函数文档

这个函数有两个参数,都是const char* 类型的

功能是子str1中查找是否存在str2字符串

返回一个const char* 类型的地址,如果存在,则返回在str1中第一次出现str2的地址,如果不存在,则返回NULL

(2)strstr的使用

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

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "bcdf";
	const char* ret = strstr(arr1, arr2);
	if (ret != NULL)
	{
		printf("%s\n", ret);
	}
	else
	{
		printf("找不到\n");
	}
	return 0;
}

(3)strstr的模拟实现

我们在这里采用的是暴力循环遍历的方法。当然也可以使用KMP算法,在此不做介绍了

#include<stdio.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	if (*str2 == '\0')
	{
		return (char*)str1;
	}
	const char* s1 = NULL;
	const char* s2 = NULL;
	const char* cp = str1;

	while (*cp)
	{
		s1 = cp;
		s2 = str2;
		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cp;
		}
		cp++;
	}
	return NULL;
}
int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "bcdef";
	char* ret = my_strstr(arr1, arr2);
	if (ret != NULL)
	{
		printf("%s\n", ret);
	}
	else
	{
		printf("找不到\n");
	}
	return 0;
}

9.strtok

(1)strtok的库函数文档

这个函数有两个参数,str是目标字符串。它是需要被修改的

delimiters是一个字符串,定义了用作分隔符的集合

函数的功能是,在str字符串中找到,delimiter这个集合中的任意一个字符,然后将最先出现的这个字符修改为\0,并且返回分割好的这个字符串的地址,并且内部有一个静态变量记录之前切割的位置

这个str可以是一个null,如果传的是空指针的话,那么就在后面的字符串中找到集合中的某个元素,并且修改为\0,然后返回这个字符串。

(2)strtok的使用以及注意事项

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

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "192.168.120.86#56789";
	char sep[] = ".#";
	char buf[30] = { 0 };
	strcpy(buf, arr);
	char* ret = NULL;
	for (ret = strtok(buf, sep); ret != NULL; ret = strtok(NULL, sep))
	{
		printf("%s\n",ret);
	}
	return 0;
}

10.strerror

(1)strerror的库函数文档

这个函数它会接受一个整型的数字,这个数字是一个错误码,然后返回一个字符串的地址,我们可以打印出这个字符串的地址,显示我们的错误信息

C语言在运行时,如果发生错误,就会将错误码存放到errno

这个变量中,而这个函数可以将错误码翻译成字符串

 

(2)strerror的使用

#include<stdio.h>
#include<string.h>
int main()
{
	printf("%s\n", strerror(0));
	printf("%s\n", strerror(1));
	printf("%s\n", strerror(2));
	printf("%s\n", strerror(3));
	printf("%s\n", strerror(4));

	return 0;
}

 

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		printf("%s\n", strerror(errno));
		return 0;
	}

	fclose(pf);
	return 0;
}

 

(3)perror的使用

perror和strerror很相似,区别就是它是可以自己打印出错误信息的

perror在打印错误信息之前,会先打印出自定义的信息。

 perror==printf+strerror

#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 0;
	}

	fclose(pf);
	return 0;
}

 

二、字符函数

对于这部分的函数,我们用的很少,当我们想要使用的时候,直接去文档搜索一下用法即可

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任何可打印字符,包括图形字符和空白字符

2.字符转换函数

注意:这两个函数不会改变自身本来的值,是返回转换后的值

大写转小写int tolow(int c)
小写转大写int toupper(int c)

3.利用字符函数,将字符串中的大写字母改为小写打印出来

#include<stdio.h>
#include<string.h>
#include<ctype.h>
int main()
{
	char arr[] = "I Have An Apple";
	int i = 0;
	int len = strlen(arr);
	for (i = 0; i < len; i++)
	{
		if (isupper(arr[i]))
		{
			arr[i] = tolower(arr[i]);
		}
		printf("%c", arr[i]);
	}
	return 0;
}

 

三、内存函数

我们已经有了字符串的操作函数,但是这些函数只针对字符串,我们有时候需要对整型数组等进行字符串类似的操作。所以我们就需要使用内存函数

1.memcpy

(1)memcpy的库函数文档

它有三个参数,第一个参数是目标空间的起始地址,第二个参数第源头空间的地址,第三个变量是拷贝num个字节

我们这个函数的功能是将source的前num个字节拷贝到destination中

返回一个指针指向dest处的指针,这个指针是void类型的

 (2)memcpy的使用以及注意事项

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

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, 20);
	return 0;
}

 

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1 + 2, 20);
	return 0;
}

 

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1 + 2, 17);
	return 0;
}

17个字节可行的原因是因为小端存储造成的

(3)模拟memcpy函数

#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret; 
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr1 + 2, 20);
	return 0;
}

2.memmove

(1)memcpy的缺陷

在memcpy函数中,我们可以将一个地址的前n个字节复制到一个地址动。但是如果我们自身对自身进行拷贝的话,会出现一些问题

假如下图是src和dest的地址

 那么按照我们的思路,最终的现象就是下图所示的

 

我们发现会出现1212这样似乎处于一个循环的情景,这与我们的字符串追加造成的现象是极其相似的。而且strcpy中也会出现这样的情况。为了避免出现这个现象,我们可以这样做,从后向前拷贝。

但是这样的话,如果dest又在src前面的话,又不符合我们的想法了,又会陷入一种类型于死循环的情况

 这时候我们就需要从前向后拷贝了

于是我们发现,这个似乎需要分情况,经过我们的分析,我们可以得出以下结论

 当然对于这四种情况,我们可以进行一次简化

如果是这样拷贝,那么我们的目标就实现了

而这个功能其实在memmove函数中就已经实现了

(2)memmove的库函数文档

这个函数的参数与memcpy是一样的,功能也是一样的,唯一不同的就是,可以自己拷贝自己了

(3)memmove的模拟实现

#include<stdio.h>
#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(src && dest);
	void* ret = dest;
	if (dest < src)
	{
		//从前向后拷贝
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		//从后向前拷贝
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	my_memmove(arr1, arr1 + 2, 20);
	return 0;
}

(4)memmove的使用以及注意事项

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

3.在vs上memcpy和memmove没有任何区别。但是其他编译器上不一定

 

3.memcmp

(1)memcmp的库函数文档

它的功能是比较ptr1和ptr2两个指针所指向空间的前num个字节

ptr1>ptr2返回大于0的数

ptr1==ptr2返回0

ptr1<ptr2返回小于0的数

(2)memcmp的使用

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

 

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

 

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[] = { 1,2,7 };
	int arr2[] = { 1,2,5 };
	int ret = memcmp(arr1, arr2, 12);
	printf("%d", ret);
	return 0;
}

 

4.memset

(1)memset的库函数文档

它是一个内存设置函数

将ptr空间中的前num个字节,以字节为单位设置为value

 

(2)memset的使用

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "hello world";
	memset(arr, 'x', 5);
	printf("%s\n", arr);
	memset(arr + 6, 'y', 5);
	printf("%s\n", arr);

	return 0;
}

#include<stdio.h>
#include<string.h>
int main()
{
	int arr[10] = { 0 };
	memset(arr, 1, 40);
	return 0;
}

 

 


总结

本节讲解了最常使用的字符串函数,内存函数,字符函数的使用,以及一些重要的函数的实现

如果对你有帮助,不要忘记点赞加收藏哦!!!

想获得更多优质内容,一定要关注我哦!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/161546.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何使用机器学习进行图像识别|数据标注

什么是图像识别&#xff1f;图像识别是一种用于识别图像中的对象并将其分类为特定类别的机制&#xff0c;基于人类识别不同图像集中对象的方式。图像识别如何为人类工作&#xff1f;当我们看到一个物体或图像时&#xff0c;作为人类&#xff0c;我们能够立即准确地知道它是什么…

浅谈STL——适配器

一、适配器&#xff08;Adapters&#xff09; 它是一种设计模式&#xff0c;为STL中能够将一个类的接口转化为用户更加想要使用的接口&#xff0c;适配器就扮演者轴承、转换器的功能 就是一个wrapper的模式&#xff0c;将要修饰的接口进行二次包装&#xff0c;展露出可以更容…

紧急事故的流程管理

嵌套式职责分离 在事故处理中&#xff0c;让&#xff1a;每个人清楚自己的职责是非常重要的。有点反直觉的是&#xff0c;明嘶职费反而能够使每个人可以更独立自主地解决问题&#xff0c;因为他们不用怀疑和担心他们的同事都在干什么。 如果一个人目前要处理的事情大多了&…

[TPAMI 2022] 用深度神经网络解决欠定问题——考虑鲁棒性?

Solving Inverse Problems With Deep Neural Networks – Robustness Included?https://ieeexplore.ieee.org/abstract/document/9705105摘要在过去的五年中&#xff0c;深度学习方法已经成为解决各种反问题的最先进方法。在此类方法可以应用于安全关键领域之前&#xff0c;必…

2022年度总结和展望2023年

文章目录 前言 2022年的成就总结 2023年的行动目标 如何完成这些目标&#xff1f; 前言 从2018年更新CSDN第一篇的博文&#xff0c;我就和CSDN产生联系。当时想法很纯粹&#xff0c;就是将积累的知识写成文章&#xff0c;无论去到哪里都能查到&#xff0c;所以前面三年都是…

Python实现预测客户是否会购买房车险源码+数据集,基于伯努利朴素贝叶斯预测客户购买房车险源码,Python预测客户购买房车险

伯努利朴素贝叶斯预测客户购买房车险 根据2000年数据挑战赛保险公司的客户特征数据&#xff0c;预测客户是否会购买房车险。 使用伯努利朴素贝叶斯模型&#xff0c;我获得了更好的预测效果 完整代码下载地址&#xff1a;Python实现预测客户是否会购买房车险源码数据集 数据集…

中国化工发展的新态势

顺势而为的企业才可能有好的未来&#xff0c;在一年之初&#xff0c;回顾总结一下中国化工行业的发展态势&#xff0c;对企业认清形势&#xff0c;确定企业的行业发展方向和发展战略至关重要。 自2022年以来&#xff0c;中国快速增长的化工行业按收入计算一直是世界上最大的&am…

【Java、Redis】通过中心经纬度与半径获取范围内的结果集(类似附近的人)

文章目录需求解决方案什么是Redis GeoHashJava实现InitEquLongLatTask.javaControllerservicexml sql语句引用的pom依赖需求 通过百度地图的覆盖物功能&#xff0c;用户在页面上画圈选定某个区域&#xff0c;前端传输中心点经纬度与半径给后端&#xff0c;后端需要返回位置在圈…

表格存储 Tablestore 十年发展总结

作者&#xff1a;周赵锋 阿里云基础产品团队 ​表格存储Tablestore上线已有十年&#xff0c;随着业务规模变大&#xff0c;稳定性挑战也随之而来&#xff0c;需要不断优化架构来提升可用性。本文将为大家分享表格存储Tablestore在技术层面近年来的功能演进、技术架构演进以及稳…

与哈希函数有关的结构:布隆过滤器、一致性哈希

1、认识哈希函数 &#xff08;out f(in data)&#xff09; 输入参数in&#xff0c;其值域范围可以看作是无穷大的。输出函数out&#xff0c;其值域范围可能性很大&#xff0c;但是一定是有穷尽的哈希函数没有任何随机的机制&#xff0c;固定的输入一定是固定的输出输入无穷多但…

计算机基础——无处不网络

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.计算机网络概述 1.计算机网络发展史 二.计算机网络应用领域 三.计算机网…

基于YOLOv6m的接打电话检测识别分析系统

本身在实际项目开发应用中YOLO都是目标检测任务的绝对主力&#xff0c;从v3一直跟着到了v7&#xff0c;做了很多的项目&#xff0c;处理了很多的数据&#xff0c;当然了也积累了一些自己的成果和心得&#xff0c;这里主要是以不常用到的yolov6m系列的模型来开发构建接打电话行为…

python基础篇之函数

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a;lqj_本人的博客_CSDN博客-微信小程序,前端,vue领域博主lqj_本人擅长微信小程序,前端,vue,等方面的知识https://blog.csdn.net/lbcyllqj?spm1000.2115.3001.5343 哔哩哔哩欢迎关注&…

最简最速搭建grpc分布式服务的Mac系统开发环境

文章目录环境详情基本原理什么是 Protobuf工具安装环境搭建编写服务类的实现启动服务客户端测试环境详情 golang 1.18 macOS Big Sur protobuf 3 基本原理 整个RPC过程就是&#xff1a; 客户端 发送 数据&#xff08;以字节流的方式&#xff09;服务端接收&#xff0c;并…

Spring Boot 大型线上商城项目实战教程试学(文末视频版)

视频链接在文末 在学习一门技术的时候&#xff0c;相信很多开发者会在开源网站上寻找对应技术栈的开源项目&#xff0c;通过阅读源码&#xff0c;学习项目作者的开发思路、解决问题的方法&#xff0c;这一过程&#xff0c;对大多人来说没那么容易&#xff0c;要么一开始不知从…

共享模型之管程(八)

1.线程的活跃性 1>.定义: 线程内的有限代码因为某种原因一直无法执行完毕(/执行不完); 1.1.线程活跃性的现象-死锁 1>.有这样的情况&#xff1a;一个线程需要同时获取多把锁,这时就容易发生死锁; 2>.案例 ①.t1线程已经获得A对象锁,接下来想获取B对象的锁; ②.t2线…

Python和MySQL对比(4):用Pandas 实现MySQL的行列转换语法效果

文章目录一、前言二、语法对比数据表concat&#xff08;多列合并为一列&#xff09;group_concat&#xff08;多行合并为一行&#xff09;一列拆分为多列一行拆分为多行多行转为多列多列转为多行三、小结一、前言 环境&#xff1a; windows11 64位 Python3.9 MySQL8 pandas1.4.…

【Linux】make/Makefile的简单使用

人生的态度是&#xff0c;抱最大的希望&#xff0c;尽最大的努力&#xff0c;做最坏的打算。 – 柏拉图 《理想国》 目录一.Linux项目自动化构建工具-make/Makefile1.为什么需要使用make/Makefile2.简单理解make和Makefile3.如何编写Makefile文件3.1生成可执行程序&#xff1a…

智算中心掀落地热潮,加速AI普惠化

11日&#xff0c;国家信息中心与浪潮信息联合发布的《智能计算中心创新发展指南》显示&#xff0c;目前全国有超过30个城市正在建设或提出建设智算中心&#xff0c;“十四五”期间&#xff0c;对智算中心的投资可带动人工智能核心产业增长约2.9-3.4倍。 《科创板日报》记者注意…

python+人脸识别+opencv实现真实人脸驱动的阿凡达(中)

目录一、前言二、消除图片拼接缝隙三、基于一张图片正脸转侧脸的实现1、人体头部的二维成像知识2、用特征点驱动的方法实现侧脸2.1python核心代码三、后续工作一、前言 我们在上篇名叫python人脸识别opencv实现真实人脸驱动的阿凡达&#xff08;上博文里已经实现了基于三角映射…