您现在的位置是:首页 >技术交流 >【C生万物】 字符串&内存函数篇 (上)网站首页技术交流

【C生万物】 字符串&内存函数篇 (上)

Claffic 2024-06-17 11:26:54
简介【C生万物】 字符串&内存函数篇 (上)

 欢迎来到 Claffic 的博客 ???                               ? 专栏:《C生万物 | 先来学C》?

前言:

过了指针这个坎后,下一步就是C语言中关于字符的处理,这一期来讲讲常用字符函数和字符串函数:strlen,strcpy,strcat,memcpy,memmove,memcmp 等。 


目录

Part1:写在前面

Part2:函数介绍

1.strlen

2.strcpy

3.strcat

4.strcmp

5.strncpy

6.strncat

7.strncmp

8.strstr

9.strtok

10.memcpy

11.memmove

12.memcmp 


Part1:写在前面

说到字符串大家应该不陌生了,但你知道如何处理字符串吗?

C 语言中对字符和字符串的处理很是频繁,但是 C 语言本身是没有字符串类型的(在C++中解决了这个问题,引入了string类),字符串通常放在常量字符串中或者 字符数组 中。
字符串常量 适用于那些对它不做修改的字符串函数 .

Part2:函数介绍

1.strlen

strlen - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strlen/?kw=strlen

size_t strlen ( const char * str );

这个函数是获取字符串长度的,下面是注意的点:

• 字符串已经 '' 作为结束标志, strlen 函数返回的是在字符串中 '' 前面出现的字符个数(不包含 '' );
• 参数指向的字符串必须要以 '' 结束;
• 注意函数的返回值为 size_t ,是无符号的。

可以利用此函数来比较两个字符串的大小:

#include<stdio.h>
#include<string.h>
int main()
{
	const char* str1 = "abcdef";
	const char* str2 = "ggg";
	if (strlen(str2) - strlen(str1) > 0)
	{
		printf("str2>str1
");
	}
	else
	{
		printf("srt1>str2
");
	}
	return 0;
}

?️‍?️运行结果: 

2.strcpy

strcpy - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strcpy/?kw=strcpy

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

这个函数是用来拷贝字符串的

注意传参:将后部的字符串拷贝到前部的空间中

• 源字符串必须以 '' 结束;
• 会将源字符串中的 '' 拷贝到目标空间;
• 目标空间必须足够大,以确保能存放源字符串;
• 目标空间必须可变。

例子:

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[40];
	const char* str2 = "abc";
	char* str = strcpy(str1, str2);
	printf("%s
", str);

	return 0;
}

 ?️‍?️运行结果: 

3.strcat

strcat - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strcat/?kw=strcat

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

这个函数是在一个字符串末尾追加字符串的

• 源字符串必须以 '' 结束;
• 目标空间必须有足够的大,能容纳下源字符串的内容;
• 目标空间必须可修改。

例子:

#include<stdio.h>
#include<string.h>
int main()
{
	char str[80];
	strcpy(str, "these ");
	strcat(str, "strings ");
	strcat(str, "are ");
	strcat(str, "concatenated.");
	puts(str); // 输出字符串,传递char*类型,遇到结束
	return 0;
}

?️‍?️运行结果:

4.strcmp

strcmp - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strcmp/?kw=strcmp

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

这个函数的作用就是比较两个字符串的

标准规定: 

• 第一个字符串大于第二个字符串,则返回大于0 的数字;
• 第一个字符串等于第二个字符串,则返回0;
• 第一个字符串小于第二个字符串,则返回小于0 的数字。

注意注意:不是比较字符串的长度,而是一个字符一个字符地比较字符的 ASCII 码值

例子:

#include<stdio.h>
#include<string.h>
int main()
{
	char* str1 = "abcdef"; 
	char* str2 = "abcdef";
	char* str3 = "abcde";
	char* str4 = "cpp";

	printf("%d
", strcmp(str1, str2));
	printf("%d
", strcmp(str1, str3));
	printf("%d
", strcmp(str1, str4)); // 第一个字符就小

	return 0;
}

 ?️‍?️运行结果:

其实这个函数的最大作用就是0的情况,即判断两个字符串相等。

5.strncpy

strncpy - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strncpy/?kw=strncpy

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

这个函数也是拷贝字符串的,不过它相比 strcpy 多了一个参数 num ,说明可以指定拷贝字符串的字符个数。

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

例子:

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[40] = { '0' };
	char str2[30] = { '0' };
	const char* str3 = "abcdef";

	strncpy(str1, str3, 6);
	strncpy(str2, str3, 2);

	printf("%s
", str1);
	printf("%s
", str2);

	return 0;
}

?️‍?️输出结果: 

6.strncat

 strncat - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strncat/?kw=strncat

这个函数也是,加了 n ,可控制要追加的字符长度

• 追加字符,

例子:

#include <stdio.h>
#include <string.h>
int main()
{
	char str1[20];
	char str2[20];
	strcpy(str1, "To be "); str1 中存入 To be
	strcpy(str2, "or not to be"); str2 中存入 or not to be
	strncat(str1, str2, 6); str1 追加 str2 中的6个字符 or no
	puts(str1);
	return 0;
}

?️‍?️输出结果: 

7.strncmp

 strncmp - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strncmp/?kw=strncmp

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

相比 strcmp,它可以指定最多比较 num 个字符

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

例子:

#include <stdio.h>
#include <string.h>
int main()
{
	char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
	int n;
	puts("Looking for R2 astromech droids...");
	for (n = 0; n < 3; n++)
	{
		if (strncmp(str[n], "R2xx", 2) == 0)
			printf("found %s
", str[n]);
	}
	return 0;
}

 ?️‍?️输出结果: 

这个例子的意思就是在 str 中寻找含有 R2 的字符串。

8.strstr

strstr - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strstr/?kw=strstr

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

这个函数的作用就是寻找相等的字符串,返回指针类型

• 在 str1 中寻找 str2 ,找到了就返回指向 str1 中与 str2 相同字符的指针,如果没有(str2 不是 str1 的一部分),就返回 NULL

• 匹配过程不包括空字符串。 

例子:

#include <stdio.h>
#include <string.h>
int main()
{
	char str[] = "This is a simple string";
	char* pch;
	pch = strstr(str, "simple");
	if (pch != NULL)
		strncpy(pch, "sample", 6);
	puts(str);
	return 0;
}

?️‍?️输出结果:

简单解释,在 str 中寻找字符串 simple,将其地址保存到 pch 中,再将 simple 替换为 sample,最终输出替换后的结果。

9.strtok

strtok - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strtok/?kw=strtok

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

这个函数是做字符串切分的

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

看着挺复杂的,其实... ...就是复杂的。

接下来看个例子,相信会好些:

#include <stdio.h>
#include <string.h>
int main()
{
	char str[] = "- This, a sample string.";
	char* pch;
	printf("Splitting string "%s" into tokens:
", str);
	pch = strtok(str, " ,.-"); // 分割符可以是字符集合
	while (pch != NULL)
	{
		printf("%s
", pch);
		pch = strtok(NULL, " ,.-");
	}
	return 0;
}

 ?️‍?️输出结果:

这个例子就是将字符串 - This, a sample string. 按照 , - . 三个分隔符切割,注意进行多个字符的切割时,要进行 pch = strtok(NULL, " ,.-"); 操作,对应 strtok 函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记 

10.memcpy

 
memcpy - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/memcpy/?kw=memcpy

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

这个 void 类型不是没有,而是可以接受多种类型 

这个函数是复制数据用的

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

例子:

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

struct 
{
	char name[40];
	int age;
} person, person_copy;

int main()
{
	char myname[] = "Pierre de Fermat";

	/* using memcpy to copy string: */
	memcpy(person.name, myname, strlen(myname) + 1);// +1是要把''拷贝上 
	person.age = 46;

	/* using memcpy to copy structure: */
	memcpy(&person_copy, &person, sizeof(person));

	printf("person_copy: %s, %d 
", person_copy.name, person_copy.age);

	return 0;
}

?️‍?️输出结果:

解释:定义了一个结构体,包含名字和年龄,先将 myname 中的内容拷贝到结构体的 name 成员中,再将整个结构体拷贝给自己(可拷贝类型有多种)。 

11.memmove

 
memmove - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/memmove/?kw=memmove

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

参数类型与 memcpy 是相同的,两者的不同在哪里呢?

• 差别就是 memmove 函数处理的源内存块和目标内存块是可以重叠的;

• 如果源空间和目标空间出现重叠,就得使用 memmove 函数处理。

也就是说,在不确定源空间和目标空间是否重叠的情况下,memmove 可以保证拷贝的内容是正确的,所以 memmove 相比 memcpy 更安全。

例子:

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

int main()
{
	char str[] = "memmove can be very useful......";
	memmove(str + 20, str + 15, 11);
	puts(str);
	return 0;
}

?️‍?️输出结果:

这个例子可以充分说明源空间和目标空间存在重叠的时候可以保证拷贝成功。

12.memcmp 

memcmp - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/memcmp/?kw=memcmp

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

看返回类型是 int 类型,啊哈,这个函数是比较两个数据的

• 比较从  ptr1    ptr2  指针开始的  num  个字节;

例子:

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

int main()
{
	char buffer1[] = "DWgaOtP12df0";
	char buffer2[] = "DWGAOTP12DF0";
	int n;
	n = memcmp(buffer1, buffer2, sizeof(buffer1));
	// 注意:大写字符的ASCII码值 小于 小写字符的ASCII码值
	if (n > 0) 
		printf("'%s' is greater than '%s'.
", buffer1, buffer2);
	else if (n < 0) 
		printf("'%s' is less than '%s'.
", buffer1, buffer2);
	else 
		printf("'%s' is the same as '%s'.
", buffer1, buffer2);

	return 0;
}

?️‍?️输出结果:

大写字符的ASCII码值 小于 小写字符的ASCII码值

所以才会有这样的结果,跟想想中的不一样... ... 


总结: 

这期主要是带大家认识各种常见的字符串处理函数,知道有这些好用的函数并且会应用就可以了,下期带大家尝试实现几个其中的函数。

码文不易 

如果你觉得这篇文章还不错并且对你有帮助,不妨支持一波哦  ???

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。