字符串操作函数

  • Post author:
  • Post category:其他




一、字符串操作函数

在C语言程序库中为我们提供了多个字符串操作函数,这些函数的原型包含在

string.h

头文件中。其中最常用的有:strlen() 、strcat()、strcmp()、strcpy()、等。



长度受限制的字符串操作函数



1、strlen()函数说明与模拟实现

函数原型:

size_t strlen( const char *string );


功能:

strlen( )函数用于统计字符串的长度,

‘\0’

作为结束标志,返回值返回的是字符串中的长度(返回的长度不包括

‘\0’

)

例:

char str1[]="hello";
char str2[5]={'h','e','l','l','o'};

printf("str1 = %d\n", strlen(str1));
printf("str2 = %d\n", strlen(str2));

运行结果

由运行结果可知:str1的字符串长度为5,str2的长度不是5,而是21(随机值),对结果进行分析:


str1

在内存中的存储方式,strlen()函数读取到

‘\0’

时读取结束,返回值为

‘\0’

前面出现的字符个数(不包含

‘\0’

)。

str1字符串的存储方式


str2

在内存中存放的方式,strlen()函数读取的是

‘\0’

之前的字符个数,所以当读取到最后一个字符 o 时并不会停止,而是会继续向后读取,直至遇到

‘\0’

为止;str2最后一个字符 ’o‘与 **’\0’**之间的个数是不确定的,所以字符串str2的长度是一个大于5的随机值;

str2在内存中的存储方式


strlen()函数的模拟实现


方法一:计数方式

size_t my_strlen(const char *string)
{
	assert(string);
	size_t count = 0;
	while (*string++)
		count++;
		
	return count;
}

方法二:尾指针 — 头指针

size_t my_strlen(const char * string)
{
	assert(string);
	const char* start = string;//将字符串首地址赋值给start
	while (*string)			//当指针指向 '\0' 结束循环,此时指针指向的'\0'的首地址
		string++;			
	return string - start;	
}

示意图:

在这里插入图片描述

方法三:递归的方式实现

size_t my_strlen(const char * string)
{
	assert(string);
	if (!*string)		//当字符串指向 '\0' 时,返回0
		return 0;
	else
		return 1 + my_strlen(string + 1);  //当字符串指向不为 '\0' 时,调用函数自身,实现递归调用
}



2、strcpy()函数说明与模拟实现

函数原型:

char *strcpy( char *strDestination, const char *strSource );


功能:

strcpy()将strSource为首地址的字符串拷贝到以strDestination为首地址的字符串中(包括

‘\0’

),并返回strDestination的地址。

使用案例:

int main()
{
	char str1[]="hello china!";
	char str2[100]={0};
	strcpy(str2,str1);
	printf("%s\n",str2);	//打印的结果为 hello china!
	return 0;
}


注:


1、在赋值和追加字符串时不会进行溢出检查,源字符串必须有明确的结束标志位

‘\0’

,在拷贝过程中结束标志位不可被修改;

2、拷贝过程中遇到

‘\0’

拷贝过程结束,连同 **’\0’**一同拷贝到目标字符串中;

3、目标字符串空间必须足够大且能够改变,以确保能够装下源字符串;


strcpy()函数的模拟实现

char* my_strcpy(char *dest, char * src)
{
	assert(dest && src);
	char* ret =dest;
	while (*dest++ = *src++)	//先将*src中的内容给*dest,再进行dest++,src++,
		;						//直至*src = '\0'时退出循环
	return ret;
}



3、strcat()函数说明与模拟实现

函数原型:(用于拼接字符串)

char *strcat( char *strDestination, const char *strSource );


功能:

strcat()将strSource为首地址的字符串追加到以strDestination为首地址的字符串之后(包括

‘\0’

,strSource字符串保持不变),返回strDestination的地址。

使用案例:

int main()
{
	char str1[20] = "hello ";
	char  * str2 = "china!";
	my_strcat(str1,str2);
	printf("%s\n",str1);	//输出结果为 hello china!
	return 0;
}


注:


1、源字符串一定要有结束标志

‘\0’

;

2、目标空间必须能够改变且足够大。

3、不能对字符串自身进行追加,结果是不可预知的(结束标志位

‘\0’

被覆盖);


strcat()函数的模拟实现

char* my_strcat(char *dest,const char * src)
{
	assert(dest && src);	//对参数进行断言,判断指针是否为NULL
	char* ret = dest;
	while (*dest)	//定位dest字符串的结束位
		dest++;
	while (*dest++ = *src++)	//将src字符串的值赋值给dest;
		;
	return ret;
}



4、strcmp( )函数说明与模拟实现

函数原型:(用于比较两个字符串的ASCII值的大小)

int strcmp( const char *string1, const char *string2 );


功能:

strcmp()比较string1 与string2两个字符串的大小,比较的是字符的ASCII,当:

string1

>

string2, 返回值

>0

;

string1

=

string2, 返回值

=0

;

string1

<

string2, 返回值

<0

;

使用案例:

int main()
{
	char* str1 = "abcdef";
	char* str2 = "abce";
	char* str3 = "abce";
	printf("%d\n",strcmp(str1,str2));		//str1 < str2    返回值 --> -1
	printf("%d\n", strcmp(str2, str1));		//str1 > str2    返回值 --> 1
	printf("%d\n", strcmp(str3, str2));		//str3 = str2    返回值 --> 0
	return 0;
}


strcmp()函数的模拟实现

int my_strcmp(const char * str1,const char * str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (!*str1)		
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;
}



长度受限制的字符串操作函数

常用的长度受限制的字符串操作函数有:

  1. char *strncat(char *dest, const char *src, size_t n)
  2. char *strncpy(char *dest, const char *src, size_t n)
  3. int strncmp(const char *str1, const char *str2, size_t n)

以strncat()函数为例

strcat()函数无法检查第1个数组是否能容纳第2个字符串,如果分配给第1个数组的空间不够大,多出来的字符溢出到相邻的存储单元,就会出现不可预知的问题,要保证拼接后的字符串长度加1才有空间存放末尾的空字符;

strncat()函数的第三个参数指定了最大添加字符的个数,这样在一定程度避免了数组非法访问的问题;

char *strncat(char *dest, const char *src, size_t n)

参数说明:

  • dest – 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串,包括额外的空字符。
  • src – 要追加的字符串。
  • n – 要追加的最大字符数,如果src的字符数大于n,那么该函数只将src的前n个字符附加在dest末尾,如果src中的字符数小于n,该字符会将str2的所有字符附加在dest末尾。无论哪种情况,都会在新字符串的末尾添加空字符。必须为dest分配足够的空间以存储新的字符串。strncat()函数返回指向dest的指针

    使用案例:
int main()
{
	char dest[50], src[50];

	strcpy(dest,"hello china!");
	strcpy(src,"hello world!");

	strncat(dest,src,strlen(src));

	printf("%s\n",dest);

	return 0;
}

在这里插入图片描述



字符串查找函数



strstr()

函数原型:(用于比较两个字符串的ASCII值的大小)

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


功能:

在字符串 str1中查找第一次出现字符串 str2 的位置,不包含终止符 ‘\0’,如果str2是str1 的子串,则该函数返回str2在str1 中首次出现的地址;否则,返回NULL

使用案例:

int main()
{
	char str1[] = "hello china!";
	char* str2 = "china1";
	char* result = strstr(str1,str2);

	if (result)
		printf("%s\n", result);
	else
		printf("not find!");
	return 0;
}


strstr()函数的模拟实现

char* my_strstr(const char * str1,const char* str2)
{
	assert(str1 && str2);
	if (!*str2)
		return (char *)str1;
	const char* cp = str1;
	while (*cp)
	{
		const char* p1 = cp;
		const char* p2 = str2;
		while ((*p1) && (*p2) &&(*p1 == *p2))
		{
			p1++;
			p2++;
		}
		if (!*p2)
			return (char *)cp;
		cp++;
	}
	return NULL;
}



字符串分割函数



strtok()

函数原型:(字符串分割函数)

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


功能:

strtok()用来将字符串分割成一个个片段。参数str指向欲分割的字符串,参数delim 则为分割字符串,当strtok()在参数str 的字符串中发现到参数delim 的分割字符时则会将该字符改为\0 字符。在第一次调用时,strtok()必需给予参数s 字符串,往后的调用则将参数s 设置成NULL。每次调用成功则返回下一个分割后的字符串指针。

返回值:返回下一个分割后的字符串指针,如果已无从分割则返回NULL

使用案例:

//方式一:
int main()
{
	char str[] = "hello@china.123.world@456";
	
	printf("%s\n", strtok(str, "@."));	//在第一次调用时,要给定分割字符串
	
	printf("%s\n", strtok(NULL, "@."));	//在后面的调用中参数str设置为NULL
	printf("%s\n", strtok(NULL, "@."));
	printf("%s\n", strtok(NULL, "@."));
	printf("%s\n", strtok(NULL, "@."));
	printf("%s\n", strtok(NULL, "@."));
	return 0;
	//输出结果为
	//hello
	//china
	//123
	//world
	//456
	//null
}

//方式二:在上面的方法中,有多少个分割的字符,就需要多少个printf(),代码很多,也需要自己计算,很不方便
int main()
{
	char str[] = "hello@china.123.world@456";
	char* p;
	printf("%s\n", strtok(str, "@."));
	while (p = strtok(NULL, "@."))
			printf("%s\n", p);
	return 0;
}

//方式三:
```C
int main()
{
	char str[] = "hello@china.123.world@456";
	char* p;
	char* delim = "@.";
	for (p = strtok(str, delim); p; p = strtok(NULL, delim))
		printf("%s\n",p);
	return 0;
}



错误报告errno、perror() 和 strerror()

C 语言不提供对错误处理的直接支持,但是作为一种系统编程语言,它以返回值的形式允许您访问底层数据。在发生错误时,大多数的 C 或 UNIX 函数调用返回 1 或 NULL,同时会设置一个错误代码 errno,该错误代码是全局变量,表示在函数调用期间发生了错误。可以在 errno.h 头文件中找到各种各样的错误代码。

  • void perror( const char *string ); 函数显示传给它的字符串,首先打印string,然后是一个冒号,然后是产生错误的最后一个库调用的系统错误消息,最后是一个换行字符。如果string是空指针或指向空字符串的指针,perror只打印系统错误消息。

  • char *strerror( int errnum ); 函数,函数将errnum映射到错误消息字符串,并返回指向该字符串的指针,指针指向当前 errno 值的文本表示形式,strerror不会打印消息所以需要调用一个输出函数,比如printf:

    在这里插入图片描述

    使用案例:(两种情况打印结果相同)

int main()
{
	FILE* fp = fopen("test.txt","r");
	if (fp == NULL)
		printf("the error message is:%s\n",strerror(errno));
	perror("the error message is");
	return 0;
}

在这里插入图片描述



版权声明:本文为m0_54489492原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。