字符串库函数大合集

本文主要介绍字符函数或字符串函数的使用和使用注意,以及如何模拟实现它
这些函数的头文件都是<sring.h>
包括如下:

  • strlen
  • strcpy
  • strcmp
  • strcat
  • strncpy
  • strncmp
  • strncat
  • strstr
  • strtok
  • strerror

strlen

首先我们要聊一下strlen的返回类型
在这里插入图片描述
可以看见strlen的返回类型是无符号类型

int main()
{
	if (strlen("abc") - strlen("abcde") > 0)
	{
		printf(">");
	}
	else
	{
		printf("<");
	}
	return 0;
}

如图
strlen(“abc”) - strlen(“abcde”)的返回值也是无符号整型,无符号整型有负数吗?

再来谈及它的使用,给一个字符串地址,向后统计字符串的个数,到‘\0’为止

模拟strlen

  1. 计数器
int my_strlen(const char * str)
{
	 int count = 0;
	 while(*str)
	 {
	 	count++;
		str++;
	 }
	 return count;
}
  1. 指针
int my_strlen(const char * str)
{
	char* p = str;
	while(*p)	
	{
		p++;
	}	
	return p - str;
}
  1. 递归
int my_strlen(const char * str)
{
	if(!*str)
		return 0;
	else
		return 1 + my_strlen(str+1);
}

strcpy

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

strcpy就是字符串拷贝,将源头的字符串拷贝到目标字符串上去

注意事项:

  • 源字符串必须以 ‘\0’ 结束。
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可变。
int main()
{
	//目标空间足够大示范
	char arr1[] = "abcddd";
	char arr2[20] = { 0 };
	strcpy(arr2, arr1);
	printf("%s", arr2);

	//目标空间不可修改 错误示范
	char* p = "abcdddddd";	
	char arr[] = "heee";
	strcpy(p, arr);
	printf("%s", p);

	//目标空间要足够大 错误示范
	char arr1[] = "avcc";		
	char arr2[3] = { 0 };
	strcpy(arr2, arr1);
	printf("%s", arr2);
	return 0;
}

其实我们思考一下,strcpy是直接覆盖,并且把’\0’也覆盖过去了

模拟strcpy

void strcpy1(char* pa, const char* pb)
{
	assert(pa && pb);
	while (*pa++ = *pb++)
	{
		;
	}
}

注意,我们要给源头指针加上const,即不可修改,但是目标指针不要加,思考一下为什么
而且,我们要assert断言一下,我们写程序是面向人的,人难免会用奇怪案例测试,我们要保证严谨性

strcat

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

我们来看一下它的作用

在这里插入图片描述
即字符追加函数,将源字符串追加到,目标字符串后面

看作用我们就可以知道一下注意事项了

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

倘若源字符串不以’\0’结尾,那么我追加过去是不是不知道在哪可以停止呢?

int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "word";
	strcat(arr1, arr2);
	printf("%s", arr1);
 
	return 0;
}

我们来思考一下,如果让strcat自己追加自己呢?会发生什么?

int main()
{
	char arr[] = "abcd";
	strcat(arr, arr);
	printf(arr);
	return 0;
}

当你运行的时候,屏幕打印一堆随机值,vs给你崩溃报错
在这里插入图片描述
这是为什么呢?想要知道就要弄清楚它的工作原理

因为要在目标字符串后面开始追加,dest指向末尾,str指针都指向字符串首地址
在这里插入图片描述
随后src赋值给dest,都往后走一步
在这里插入图片描述
依次往后赋值,但你会发生,我们什么时候停止呢?没有’\0’作标志怎么停止呢?

模拟strcat

char *my_strcat(char *dest, const char*src)
{
 char *ret = dest;
 assert(dest != NULL);
 assert(src != NULL);
 while(*dest)
 {
 dest++;
 }
 while((*dest++ = *src++))
 {
 ;
 }
 return ret;
}

strcmp

这个函数都认识,比较字符串

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

注意这不是比较字符串的长度的,是按照ascll值来比较的,从头开始比较,如果不相等就停止,并返回

在这里插入图片描述

int main()
{
	char arr1[] = "abc";
	char arr2[] = "dc";
	printf("%d", strcmp(arr1, arr2));
	return 0;
}

值得注意的是当你遇到这样的代码是不严谨的代码

ifstrcmp(arr1, arr2) == 1printf("1");

注意这样写是错的,只是vs环境下>0是返回1,其他环境不一定

模拟strcmp

int strcmp1(const char* pa, const char* pb)
{
	assert(pa && pb);
	while (*pa++ == *pb++)
	{
		if (*pa == '\0')
		{
			xiangdereturn 0;
		}
	}
	return *pa - *pb;
}

这里的非相等情况为什么不用

if(*pa > * pb)
	return 1;
else
	return -1

因为字符的本质是ascll值啊,而且返回1和-1本身来说是不严谨的

strcpy,strcat,strcmp的缺陷

先前景介绍一下,我们比strcpy多了一个n,明显比它更高级。存在都是有理由的,我们来看strncpy的存在理由

strcpy,strcat,strcmp是长度不限制的字符串函数,即不关心你的长度大小,只关心自己什么时候遇到’\0’,闷头干到’\0’为止

来看代码

int main()
{
	char arr1[] = "abcd";
	char arr2[3] = { 0 };
	strcpy(arr2, arr1);
	printf(arr2);
	return 0;
}

同样的,屏幕会打印出来,但是vs会给崩溃报错
在这里插入图片描述
vs会认为这是不安全的,跟scanf一样
所以诞生了strncpy等函数

strncpy

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

注意:

  • Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is
    found before num characters have been copied, destination is padded
    with zeros until a total of num characters have been written to it.
  • 拷贝num个字符从源字符串到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

使用方法,就是限制了操作的个数而已,模拟函数也跟原来差不多,就不深究了,这里只说一下注意事项

int main()
{
	char arr1[] = "abcdef";
	char arr2[20] = { 0 };
	strncpy(arr2, arr1, 8);
	printf(arr2);
	return 0;
}

明显arr1里面没有8个元素,所以不够的用\0来筹,但是vs会提醒你

strncat

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

使用的时候,后面自动补上’\0’

int main()
{
	char arr1[20] = "abcd\0xxx";
	char arr2[] = "world";
	strncat(arr1, arr2, 3);
	printf(arr1);
	return 0;
}

追加num个后自动补上‘\0’
所以strncat可以自己跟自己追加

strncmp

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

在这里插入图片描述
strncmp的作用是,比较num个数
比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。

strstr

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

在一个字符串里找另一个字符串,就是找一个字符串有没有包含另一个字符串,找到了返回目标字符串的首地址,找不到返回NULL,即使有多个也返回第一个的地址,如abbb里找bb,返回第一个bb的首地址

我们用代码看一下

int main()
{
	char arr1[] = "abbbcb";
	char arr2[] = "bc";
	char* pa = strstr(arr1, arr2);
	printf("%s", pa);
	return 0;
}

即arr1中找arr2字符串,找到了就返回起始地址

模拟strstr

我们先来看简单情况
在这里插入图片描述
我们str1从头开始对比str2,如果不相等,str1就++,相等了str1 str2一起走直到str2==\0,就说明找到了,当然我们还要记录一下str1起始走的位置,因为是返回起始地址

我们再来看复杂情况
在这里插入图片描述
我们看这个图,如果按照简单情况,这个时候str1和str2的指向分别如图,这个时候我们str1和str2不相等,str2就应该返回到起始位置,所以我们应该用一个指针代替str2和str1走动,而str1应该返回到起始走路位置的下一个,所以我们需要一个指针记录str1起始走的位置

解决方法
在这里插入图片描述

我们使p1和p2负责走动,cp负责记录起始位置,当p1和p2不相等的话,cp++,p2回到str2的地方
p1再到cp的位置,当我们的p2走完的时候就返回cp的位置

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

对于模拟这个函数,我们的方法是暴力的
在一个字符串中找字符串,KMP算法更高效

strtok

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

它的作用是用来分割字符串的
sep就是以什么为标准进行分割的字符集合
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标
记。

例如,192.168.3.132我们想以符号’.'作为分割标记的话,sep就指向它,str就是待分割的目标字符串

我们来看一下它的介绍

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

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

什么意思?我们来看代码

int main() 
{ 
	char arr[] = "192.320.26"; 	
	char arr1[20] = { 0 }; 		
	strcpy(arr1, arr); 				//在拷贝字符串里操作
	const char* p = ".";			//分隔符集合,用const修饰好一些

 	char* pa = strtok(arr1, p);	
	printf("%s\n", pa);

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

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

  	return 0; 
} 
char* pa = strtok(arr1, p);
 第一个参数不为NULL时候
 这一句是在arr1里找到分隔符,并把分隔符改为\0,返回首地址
 并且保存分隔符的位置,用于下一次使用
  • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标
    记。

我们直接来看代码

pa = strtok(NULL, p);
当第一个参数为NULL的时候
从上一次开始保存的地方开始,执行第一步
  • 如果字符串中不存在更多的标记,则返回 NULL 指针。

看上面的使用步骤是不是很麻烦,有几个分隔符我就要写几个重复语句来打印,有没有一劳永逸的方法?
用循环!

int main()
{
	char arr[] = "111111@qq.com";
	char arr1[20] = { 0 };
	strcpy(arr1, arr);
	const char* p = "@.";
 
	char* str = NULL;
	for (str = strtok(arr1,p); str != NULL; str = strtok(NULL, p))
	{
		printf("%s\n", str);
	}
	return 0;
}
我们重点看这个代码
char* str = NULL;
for (str = strtok(arr1,p); str != NULL; str = strtok(NULL, p))
{
	printf("%s\n", str);
}

注意我for循环中;执行的顺序,str不为NULL就打印----即str分割成功一次打印一次

这里的strtok明显有static保留上一次的位置

strerror

char * strerror ( int errnum );

了解前景
C语言在调用库函数,失败的时候,会将错误码放在一个叫,error的变量中
当我们想知道是什么原因调用失败的时候,可以将error中的错误码翻译成错误信息

我们的strerror就是起翻译作用

什么是错误码?
错误码就是数字代表的错误信息

int main()
{
	char* p = strerror(0);
	printf("%s\n",p);
	p = strerror(1);
	printf("%s\n", p);
	p = strerror(2);
	printf("%s\n", p);
	p = strerror(3);
	printf("%s\n", p);

	return 0;
}

在这里插入图片描述

必须包含的头文件:

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

这里我们举一个动态内存的例子

int main()
{
	int* p = (int*) malloc(sizeof(int));
	if(!p)
	{
		printf(strerror(error));
	}
	return 0;
}

这里推荐使用perror这个函数,相当于是printf+strerror的合体版

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值