详解C语言中的字符串函数

前言

  1. 本篇博客的内容来源有c prime puls,(抄书的 ) ,加上鹏哥的视频 (我是白嫖党) ,再加上自己的一些总结。在这里附上本书的pdf文件:链接:https://pan.baidu.com/s/1frLUTJfrjT4mLsQ7wERBnQ?pwd=3nsm
    提取码:3nsm

  2. 由于大部分的字符串函数都位于< string.h >头文件中,所以在介绍各个函数时不会指出。

  3. destination指针简写为dest,其指向的字符串用“第一个字符串”表示
    source指针简写为src,其指向的字符串用“第二个字符串”表示

  4. 本人才疏学浅,能力有限,如有疏漏,还望各位大佬指出

在这里插入图片描述

1、strlen函数

(1)、介绍strlen函数

  • strlen函数用于统计字符串的长度,碰到’\0’后停止计数。

函数原型
在这里插入图片描述


(2)、使用strlen函数时的常见错误

strlen统计的是字符串的长度

int main(){
char arr1[]="abcdef";
char arr2[]={'a','b','c','d','e','f'};
int n = strlen(arr1);  //在vs2022上的运行结果:n=6
int m = strlen(arr2);  //m=33
int i = strlen(*arr2); //error
}

在这里插入图片描述


strlen函数的返回值类型是size_t类型

请看以下代码

int main() {
	if (strlen("abc") -strlen("abcdef")>0 ){
		printf(">\n");
	}
	else {
		printf("<\n");
	}
}

大家觉得答案是什么呢,是不是觉得会打印 “<“呢。
其实打印的是”>”。
因为strlen函数返回值类型是无符号整形,两个无符号整形数做运算,其结果依然是无符号整形数。
无符号整形数:可以简单理解为正数


(3)、模拟实现strlen函数

这里提供三个版本的实现方式

计数器的版本

int my_strlen(const char* str) {
	int count = 0;
	assert(str != NULL); //断言str不为空指针,是代码更安全
	while (*str)  // \0的asc2码值为0,如果*str=\0,循环结束 
	{
		count++;
		str++;  
	}
	return count;
}

指针-指针的版本

//指针-指针的值为两个指针之间的元素个数,
int my_strlen(char* str) {
	char* start = str;
	while (*str) {
		str++;
	}
	return str - start;
}

递归的版本

int my_strlen(char* str) {
	if (*str == '\0') {
		return 0;
	}
	else {
		return 1 + my_strlen(str+1);
	}
}

2、strcpy函数

(1)、 引入strcpy函数

如果要把arr1的存放内容改为字符串"HQUer"

int main(){
   char arr1[10]={1,2,3,4,5}; 
   arr1="HQUer"; //error
}

以上的代码不能完成我们的目标。因为数组名为首元素的地址,地址显然不能为字符串。完成目标的一种方法就是用strcpy函数。


(2)、预备知识(字符串常量)

  • 用双引号括起来的内容被称为字符串字面量(也叫做字符串常量),如 “Hello HQUer”.
  • 双引号内的字符和编译器自动加上的\0字符,都作为字符串存储在内存中。
  • 字符串常量属于静态存储类别,这表明在函数里使用字符串常量,该字符串只会存储一次
  • 最重要的:字符串字面量被视作const数据。如果用指针ptr指向它,就意味着不能用ptr改变这个字符串字面量,但是仍然可以改变ptr的值(即改变ptr指向的位置)。 如 char* ptr =“###”; *ptr = “ABC”; //error

(3)、介绍strcpy函数

函数原型
在这里插入图片描述
翻译成中文

strcpy接受两个字符串的指针为参数。
strcpy函数会将src指针指向的字符串(为了表示方便我们称它为源字符串)复制到dest指针指向的数组里(了表示方便我们称它为目标空间)

注:dest指针不一定要指向数组的开始,这个属性可以用于拷贝数组的一部分。 如strcpy(arr1+2,arr2) 这么写是可以的


(4)、使用strcpy函数的注意事项

  • 目标空间必须足够大,以确保能存放源字符串
  • 目标空间必须可变 (不能是字符串常量)
  • 源字符串必须以\0结束
  • 会将源字符串的\0拷贝到内存空间

因此,我们可以写出几个BUG

 #include<string.h>
 int main(){
   char arr[10]="#########";
   char arr1[5]={'a','b','c','d','e'};  //没有以\0结束
   char arr2[20]="take a seat" //源字符串大于目标空间
   char* str = "******"; //目标空间是字符串常量,不能变化
   strcpy(arr,arr1) // error
   strcpy(arr,arr2) //error
   strcpy(str,arr); //error
}

大家以后不要犯类似的错误啊。

(5)、模拟实现strcpy函数


char* my_strcpy(char* dest, const char* src)  //用const修饰,防止src被修改
{
	char* ret = dest; //记录dest的首地址
	assert(dest && src); //防止dest和src为空指针
	while (*dest++ = *src++)
	{
		;  
	}
	return ret;
}

3、strcmp函数

(1)、引入strcmp函数

如果我们要比较两个字符串是否相等,可以直接用==比较吗?

 #include<stdio.h>
 int main(){
 char arr1[10] = "abcd";
 char arr2[10] ="abcd";
 if(arr1==arr2){
     printf("right");
  }else{
    printf("false");
  }
}

在这里插入图片描述
不行,输出的结果不是我们想要的。
原因: arr1和arr2都是首元素的地址,所以arr1==arr2检查的不是arr1和arr2的内容是否相同,而是检查这两个字符串的地址是否相同而两个数组的地址一定不相同,所以这个表达式恒为假。


(2)、strcmp函数的功能

函数原型
在这里插入图片描述
这个函数会比较str1和str2所指向的字符串的大小(本质上是比较两个字符串的asc2码值)。

  • 具体比较方法:首先,这个函数会比较两个字符串的首个字符。如果首个字符不相等,就结束比较并返回一个值。如果首个字符相等,就比较下一个字符。
  • 何时比较结束:当比较的两个字符不相等或者比较到空字符时,结束比较并返回一个值
  • 返回值:返回的是整数。1. 当str1指向的字符的asc2码值>str2指向字符的asc2码值时,返回正数。2. 当str1指向的字符的asc2码值<str2指向字符的asc2码值时,返回负数。3、否则返回0(就是两个字符串相等的时候

(3)、模拟实现strcmp函数

先用伪代码明确一下思路
在这里插入图片描述


然后我们模拟实现strcmp函数

int my_strcmp(const char* s1,const char* s2) {
	assert(s1&&s2);  //保证代码的健壮性
	while (*s1==*s2) {
		if (*s1=='\0') {
			return 0;
		}
		s1++;
		s2++;
	}
	/*if (*s1>*s2) {
		return -1;
	}
	else if (*s1<*s2) {
		return 1;
	}*/
	return *s1 - *s2; //上面注释的语句可以简化为这一行
}

4、strcat函数

(1)、介绍strcat函数

函数原型
在这里插入图片描述
翻译成中文:

strcat函数接受两个字符串的指针为函数参数 ,把源字符串复制到目标字符串后面,返回源字符串的地址,同时,目标字符串内容不变。

(2)、模拟实现strcat函数

void my_strcat(char* dest,char* src) {
   //1、找目标字符串的\0
	while (* dest) {
		dest++;
	}
	
	//2、追加源字符串
	while (*dest++=*src++) {
		;
	}
}

5、strstr函数

(1)、介绍strstr函数

函数原型
在这里插入图片描述
翻译:在str1字符串中寻找str2字符串的位置。如果找到了,返回str2第一次出现在str1的位置,如果找不到,返回空指针。

(2)、模拟实现strstr函数

因个人水平,画不出图解……☹

#include<assert.h>
char* my_strstr(const char* str1,const char* str2) {
	assert(str1&&str2); //只有老司机才这么写

	const char* s1 = NULL;
	const char* s2 = NULL;
//可以更改指针指向的对象,但不能直接更改指针的内容
	
	char* cp = str1; //cp指向第一个字符串的第一个字符
	while (*cp) 
	{
		s1 = cp;
		s2 = str2;
		//上面两行相当于每一次查找前的初始化
		
		if (*str2 =='\0')  //如果第二个字符串为\0
		{
			return str1;
		}

		while (*s1 && *s2 &&(*s1==*s2))
		//当s1和s2指向的字符都相等且不为\0
		{
			s1++;
			s2++;
		}


		if(*s2 == '\0')
		{
			return cp;
		}
		cp++;
	}
	return NULL;
}

6、7、8 strncpy strncmp strncat 函数

我们可以对上面的函数进行分类,
把strcpy strcmp strcat函数归为长度不受限制的字符串函数
把strncpy strncmp strncat函数归为长度受限制的字符串函数

(1)、函数原型

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
为什么要有这几个函数呢?因为strcat,strcpy函数都不能检查目标空间能否容纳源字符串,用strncat和strncpy会更加安全。

(2)、strncpy函数

函数的第三个参数(num)表示拷贝的最大字符个数。

注:strcpy拷贝的字符串长度不会超过num,如果拷贝到第num个字符时还没有拷贝完整个源字符串,那么就不会拷贝空字符。

(3)、strncat函数

函数的第三个参数(num)表示添加的最大字符个数

举例说明: strncat(arr1,arr2,10);
表示将arr2字符串的内容附加给arr1字符串,直到第10个字符或者空字符时停止。(空字符一定会添加)。 所以,arr1数组的空间一定要足够。

(4)、strncmp函数

用strncmp函数比较两个字符串时,只比较到第三个参数指定的字符数。


还有一些字符串函数,如strtok函数,strerror函数,就不细讲了。

好了,大家学会了吗? 我们下次再见。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值