【C语言】字符函数和字符串函数

目录

前言

一、函数介绍

1.strlen

2.strcmp

3.strcat

总结!!!!!!! 

         4.strcpy 

5.长度受限的字符串函数

二、函数模拟实现

1.strlen的模拟实现

2.strcpy的模拟实现

3.strcmp的模拟实现

5.strstr

总结


前言

C语言中,我们经常要对字符串操作,因此我们要了解和掌握各种字符和字符串函数,以下带来部分C语言库中自带的几个函数。


一、函数介绍

1.strlen

strlen()函数对与我们来说并不陌生,它用来计算一个字符串的长度的,它的规则是,从字符串首元素开始往后查找,直到找到’\0',这之间的元素个数就是strlen()函数的返回值。

我们发现在库函数中strlen()返回值的类型是size_t,size——t的本质是无符号整型。这是我们就要注意,有可能会引起一些错误

#include<stdio.h>
#include<string.h>
int main()
{
	const char* arr1 = "Hello World";
	const char* arr2 = "你好 世界";
	if (strlen(arr2) - strlen(arr1) > 0)
		printf("arr2>arr1");
	else
		printf("arr2<=arr1");
	return 0;
}

 我们看这段代码,我们可能会不假思索就回答出屏幕上会打印出arr2<=arr1,但是结果是出乎意料

打印出来的结果与我们的想法是相反的。 根据我们的观察arr1数组的长度为12,arr2函数的长度是10,它们两个相减得到的是-2,恰好是小于零的整型,-2的源码是10000000000000000000000000000010反码是11111111111111111111111111111101补码是11111111111111111111111111111110。但是strlen()返回的是size_t是无符号整型,没有符号位直接转化为十进制数是4294967293这一定是大于0的数,结果就算出了,arr2>arr1

我们可以这样修改代码,来实现代码原本的功能

#include<stdio.h>
#include<string.h>
int main()
{
	const char* arr1 = "Hello World";
	const char* arr2 = "你好 世界";
	if (strlen(arr2)>strlen(arr1))
		printf("arr2>arr1");
	else
		printf("arr2<=arr1");
	return 0;
}

我们通常会把strlen()和C语言关键字sizeof()混淆,sizeof()是计算类型在内存中所占的字节大小,换到数组的定义来说,数组的类型是去掉数组名剩下的部分,所以它能算出数组在内存中所占内存的大小,它计算出的数组大小包含数组隐藏的'\0',我们可以用整个数组的大小除以数组中一个元素的大小,来计算数组元素的个数。sizeof()只计算在内存中所占字节大小,不会寻找'\0'。

2.strcmp

我们或许对这个函数会比较陌生,我们根据strcmp字面意义上的理解,它是用来比较两个字符串的,但是是比较两个字符串的什么,我们会比较疑惑,其实strcmp()比较的不是字符串长度,比较的是字符串中对应位置上的字符大小,如果相同就比较下一对,直到其中一个字符串到末尾及找到'\0'。

它的返回值是int型,如果返回一个大于0的数,代表string1大于string2,返回0代表string1等于string2,返回小于0代表string1小于string2。

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "hello world";
	char arr2[] = "werrcxzawd";
	if (strcmp(arr1, arr2) > 0)
	{
		printf("arr1>arr2\n");
	}
	else if (strcmp(arr1, arr2) == 0)
	{
		printf("arr1==arr2\n");
	}
	else
	{
		printf("arr1<arr2");
	}
	return 0;
}

 3.strcat

这个函数就十分有意思了,它是用来将一个字符串追加到另一个字符串之后

我们要注意几点,strcat函数在destination字符串中是通过找'\0'来定位要添加的位置,所以destination字符串就必须要有'\0'像这种   

char arr[] = { 'w','q','e','a' };

 不完全初始化的字符串千万不能引用strcat函数,strcat函数会因为无法找到'\0'而使程序死掉。

同时它不能自己追加自己,strcat函数有一个比较有意思的细节,它追加时,源头字符串的首元素会覆盖掉destination字符串的'\0',就会导致strcat函数无法找到'\0'而崩溃。

如果我们定义了一个常量字符串,就会因为常量字符串无法被strcat修改而出现bug

还有destination必须足够大,如果没有提前预留出源头字符串的空间,虽然strcat函数会强行追加上,但是会出现警告和未知的风险

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "Hello";
	char arr2[] = "qwffgfffsdsw";
	strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

虽然出现了错误,但是还是将arr1追加后的内容打印出来了。

总结!!!!!!! 

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

4.strcpy 

 strcpy()-----复制一个字符串

将源头字符串,复制进入目标字符串

它的具体细节是将这两个字符串的字符,一个一个的替换,直到将源头字符串的'\0'复制进入目标字符串结束。

我们要注意:源字符串必须以 '\0' 结束。会将源字符串中的 '\0' 拷贝到目标空间。 目标空间必须足够大,以确保能存放源字符串。 目标空间必须可变。

这些注意都是每一个字符串函数都要注意的。

strcmp  strcat  和strcpy函数长度都是不受限制的字符串函数

以下介绍的是长度受限的字符串函数

5.长度受限的字符串函数

 这几个函数都是在原函数的基础上多加了一个参数n用来限制字符串函数操作的字节数

其中stncpy函数会在复制结束末尾在加上'\0'就相当于将字符串截断。

strncat函数虽然你指定它追加n个元素,但实际上会追加n+1个元素,它会自动的追加'\0'

但是这个函数的n如同fgets()函数的参数n一样,你如果实际的字符串长度小于n,剩下的用'\0'来补充。

二、函数模拟实现

1.strlen的模拟实现

#include<stdio.h>
int my_strlen(char* arr)
{
	int count = 0;
	while (*arr++)
	{
		count++;
	}
	return count;
}

int main()
{
	char arr[] = "Hello World";
	
	printf("%d\n", my_strlen(arr));
	return 0;
}

strlen()函数本质上是用来找'\0'这是第一种用指针来实现

下面是用递归实现

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

int main()
{
	char arr[] = "Hello World";
	
	//printf("%d\n", my_strlen(arr));
	printf("%d\n", my_strlen_recursion(arr));
	return 0;
}

我们可以利用递归的思想,字符串arr的长度等于1+my_strlen_recursion(arr+1)来替换,相当于1加上arr字符串长度减1,我们大体的思路有了,但是要写出有效的递归程序,我们必须考虑递归的出口及达到什么条件递归才会终止,我们这个程序目的是算出字符串的长度,因此字符串结束的标准'\0'也为递归程序的出口。

2.strcpy的模拟实现

char* my_strcpy(char* des, const char* src)
{
	char* ret = des;
	while (*des++ = *src++)
	{
		;
	}
	return ret;
}

strcpy函数在之前的文章中模拟实现过就不在赘述了。

3.strcmp的模拟实现

#include<stdio.h>
#include<assert.h>
int my_strcpy(const char* e1, const char* e2)
{
	assert(e1 && e2);
	return *e1 - *e2;
}

int main()
{
	char arr1[] = "egfddssdfs";
	char arr2[] = "dbhsjuhi";
	if (my_strcpy(arr1, arr2) > 0)
	{
		printf("arr1>arr2");
	}
	else if (my_strcpy(arr1, arr2) == 0)
	{
		printf("arr1==arr2");
	}
	else
	{
		printf("arr1<arr2");
	}
	return 0;
}

5.strstr

这个函数还是比较有意思的,它是用来看一个字符串是不是另一个字符串的子串,它的返回类型是char *类型,如果不是另一个字符串的子串,它会返回NULL,如果是子串它会返回子串的起始地址。

你现在听我说可能会比较懵,现在上代码!!!!!!!!!!!!!!

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[] = "abcdefghigk";
	char arr2[] = "cdef";
	if (strstr(arr1, arr2) == NULL)
	{
		printf("arr1不是arr2的子串\n");
	}
	else
	{
		printf("%s\n", strstr(arr1, arr2));
	}
	return 0;

}

接下来我们来模拟实现

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

char* my_strstr(char* des,  char* src)
{
	assert(des && src);

	const char* s1 = des;
	const char* s2 = src;

	const char* sur = des;
	while (*sur)
	{
		s1 = sur;
		s2 = src;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
			return (char*)sur;
		sur++;
	}
	return NULL;
}





int main()
{
	char arr1[] = "abcdefghigk";
	char arr2[] = "cdef";
	/*if (strstr(arr1, arr2) == NULL)
	{
		printf("arr1不是arr2的子串\n");
	}
	else
	{
		printf("%s\n", strstr(arr1, arr2));
	}*/
	if (my_strstr(arr1, arr2) == NULL)
	{
		printf("arr1不是arr2的子串\n");
	}
	else
	{
		printf("%s", my_strstr(arr1, arr2));
	}

	return 0;

}

我们通过三个指针来控制,s1来控制主字符串,s2是用来控制子字符串的,sur是用来记录如果src是des子字符串的起始地址的。往复循环直到src字符串被遍历。


总结
以上就是今天要讲的内容,本文仅仅简单介绍了字符和字符串函数,还有很多有关字符串的函数没有介绍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值