【c语言】字符串函数

一、strlen的使用和模拟实现

1.1. strlen的使用

strlen是求字符串长度的函数,它的返回类型是无符号整型,参数是用来接收第一个字符的地址的指针

size_t strlen ( const char * str );

注意:

  1. 字符串以字符 '\0’作为结束表示,strlen返回的是\0之前字符的个数,不包括 \0
  2. 函数参数指向的字符串必须以 \0 结束,不然strlen找不到\0就会一直计算,程序会崩溃;
  3. 函数参数的返回类型为size_t无符号整型,因此返回值不能为负数;

例题:结果打印什么?

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

strlen(str2)-strlen(str1)=-3
-3的补码在32位条件下为:
11111111 11111111 11111111 11111101
strlen返回的是无符号整型,因此符号位无效,换算成十进制位为一个很大的大于0的整数,因此打印的是str2>str1

1.2. strlen的模拟实现

strlen的模拟实现有三种:计数器方法、指针-指针、递归

1.2.1. 计数器方法模拟实现strlen

思路:定义一个计数器count,如果指向字符串首元素的指针*str!='\0',那么count+1,str+1,直到找到 \0,返回count即为字符串元素的个数

size_t my_strlen(const char* str)
{
	assert(str);
	int count = 0;
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}
int main()
{
	char arr[] = "abcdefg";
	int ret=my_strlen(arr);
	printf("%d ", ret);
	return 0;
}

1.2.2. 指针-指针方法模拟实现strlen

思路:用指针str1记录最后一个字符的地址,然后str1-str就是首末元素地址之间元素的个数

size_t my_strlen(const char* str)
{
	assert(str);
	char* str1 = str;
	while (*str1)
	{
		str1++;
	}
	return str1 - str;
}
int main()
{
	char arr[] = "abcdefg";
	int ret=my_strlen(arr);
	printf("%d ", ret);
	return 0;
}

1.2.3. 递归方式模拟实现strlen

该方法可以不用创建临时变量就可以模拟实现strlen
思路:
在这里插入图片描述

size_t my_strlen(const char* str)
{
	if (*str == '\0')
		return 0;
	else
		return 1 + my_strlen(str+1);
}
int main()
{
	char arr[] = "abcdefg";
	int ret=my_strlen(arr);
	printf("%d ", ret);
	return 0;
}

二、strcpy的使用和模拟实现

2.1. strcpy的使用

strcpy是用来拷贝字符串的函数,作用是将源字符串拷贝到目标字符串中,返回的是目标字符串的首元素地址,类型是char*,有两个参数,分别是目标字符串的首元素地址destination和源字符串的首元素地址 source

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

注意:

  1. destination是目标字符串,source是要拷贝的字符串;
  2. 字符串必须以 \0结尾;
  3. 会将源字符串中的 \0也拷贝到目标空间;
  4. 目标空间必须足够大,以确保能存下源字符串;
  5. 目标空间必须可以修改,不能是常量字符串;

2.2. strcpy的模拟实现

char* my_strcpy(char* dest, const char* str)
{
	assert(dest && str);
	char* src = dest;
	while (*dest++=*str++)
	{
		;

	}
	return src;
}
int main()
{
	char arr[] = "abcdef";
	char* p = "nll";
	char* ret=my_strcpy(arr, p);
	printf("%s", ret);
	return 0;
}

三、strcat的使用和模拟实现

3.1. strcat的使用

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

strcat是字符串拼接函数,可以将源字符串拼接到目标字符串的后面,返回目标字符串起始位置的地址.

注意:

  1. 源字符串必须以 \0 结尾;
  2. 目标空间字符串也必须以 \0结尾,不然不知道应该在什么位置进行拼接;
  3. 目标空间必须足够大,能容得下拼接后的字符串;
  4. 目标空间必须可修改

3.2. strcat的模拟实现

思路:先找到目标空间字符串的 \0,找到要拼接的位置,然后进行字符串拷贝

char* my_strcat(char* dest, char* str)
{
	assert(dest && str);
	char* ret = dest;
	while (*dest)//找到拼接位置
	{
		dest++;
	}
	while (*dest++ = *str++)//进行字符串拷贝
	{
		;
	}
	return ret;
}
int main()
{
	char arr[20] = "abcdef";
	char* p = "nll";
	char* ret=my_strcat(arr, p);
	printf("%s", ret);
	return 0;
}

四、strcmp的使用和模拟实现

4.1. strcmp的使用

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

strcmp是比较字符的函数,比较的是在对应位置上字符的ASCII码值的大小,并不在乎字符串长度的大小
如果第一个字符串大于第二个字符串,则返回一个大于零的数字;
如果两字符串相等,返回零;
如果第一个字符串大于第二个字符串,则返回一个大于零的数字;

4.1. strcmp的模拟实现

int my_strcmp(char* str1, char* str2)
{
	assert(str1 && str2);
	while (*str1==*str2)//对应位置字符相等进入循环
	{
		if (*str1 == '\0')//如果走到'\0'位置还是相等,str1++,str2++就会越界访问,所以要添加终止循环的条件
			return 0;
		str1++;
		str2++;
	}
	return *str1 - *str2;
}
int main()
{
	char* str1 = "abcdef";
	char* str2 = "nll";
	int ret=my_strcmp(str1, str2);
	printf("%d", ret);
	return 0;
}

五、strncpy、strncat、strncmp的使用

5.1. strncpy的使用

char * strncpy ( char * destination, const char * source, size_t num );
  1. num表示将num个字符从源字符串中拷贝到目标空间;
  2. 如果源字符串中字符个数少于num个,则拷贝完成字符串后,在后面追加\0,直到num个.

示例:

int main()
{
	char arr[20] = "helloxxxxxx";
	char* p = "world";
	strncpy(arr, p, 8);
	printf("%s", arr);
	return 0;
}

从调试窗口可以看出,将“world”拷贝到arr后,向后追加了3个\0
在这里插入图片描述

5.2. strncat的使用

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

将source前num个字符追加到dest字符串的结尾,再追加一个 \0;
若source指向的字符串的个数少于num个时,只会将字符串内容追加到目标字符串结尾,再追加一个\0.

5.3. strncmp的使用

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

比较str1和str2的前num个字符,如果相等就继续向后比较,最多比较num个字符,如果提前发现不一样就提前结束.

六、strstr的使用和模拟实现

6.1. strstr的使用

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

在str1中寻找str2,返回str2在str1中第一次出现的位置,字符串的比较匹配不包括\0,以\0作为结束标志

6.2. strstr的模拟实现

  1. 简单情况,在目标字符串中只需要寻找一次
    在这里插入图片描述

先比较*str1*str2,不相等,让str1++,str2不动,在进行比较,若不想等,str1就一直+1,直到两者相等,之后str1++,str2++,在进行比较,若相等,str1和str2一直+1,直到str1或str2指向\0的位置,就找完了,然后返回str2与str1两个字符第一次相等的地址

注意:
这时候str1和str2都已经移动到末尾的位置,两者第一次相等的位置没有被记录下来,因此需要创建一个指针变量来记录这个位置的地址;此外,在创建两个指针变量来代替str1和str2,尽量让str1和str2始终不变

char* cur = str1;
char* s1 = NULL;
char* s2 = NULL;
while(*cur)//*cur的值不能为\0,如果为\0,说明目标空间字符串已经全都比较完了,跳出循环说明没有找到
{
	s1=cur;//把记录的地址再赋给s1
	s2=str2;
	while(*s1!='\0'&&*s2!='\0'&&*s1==*s2)
	{
		s1++;
		s2++;
	}
	if(*s2=='\0')
		return cur;
	cur++;//记录str1进行比较时候的位置的地址
	
}

这里while(*s1!='\0'&&*s2!='\0'&&*s1==*s2)判断条件中*s1!='\0'有两种情况

  1. a b c d e f \0
    d e f \0
    s1和s2同时走到\0的位置,s2走到\0,说明比较完了,已经找到了,直接返回第一次比较时候位置的地址;
  2. b c d \0
    b c d e f \0
    s1走到d后,s1++,s2++,这时s1指向\0,s2指向e,e和\0 不相等,那么跳出while(*s1!='\0'&&*s2!='\0'&&*s1==*s2)的循环,执行cur++,这时cur指向c,在进行比较,不相等,再cur++,直到cur走到\0,跳出大循环
  1. 复杂情况,需要比较多次
    在这里插入图片描述

s1走到第一个b后,此时cur指向第一个b,*s1==*s2,s1++,s2++,相等,再++,还相等,再++,此时s1指向的b和s2指向的c不相等,那么说明s1从第一b的位置开始找,一定是找不到str2的,因此,s1应该在后一个位置开始比较。这时候跳出循环,cur++,指向第二个b,s1回到第二个b的位置,s2回到str2的位置重新开始寻找。
若找不到,继续重复以上步骤;若找到,此时s2指向\0位置,跳出循环,返回cur.

在这里插入图片描述
3. 找不到的情况
在这里插入图片描述
这种情况下,s1始终找不到s2,最终s1指向末尾\0,跳出循环,返回NULL

最终的代码实现:暴力查找

char* my_strstr(char* str1, char* str2)
{
	assert(str1 && str2);
	char* s1 = NULL;
	char* s2 = NULL;
	char* cur = str1;
	if (*str2 == '\0')
		return (char*)str1;

	while (*cur)
	{
		s1 = cur;
		s2 = str2;
		while (*s1!='\0'&&*s2!='\0'&&*s1==*s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
			return (char*)cur;
		cur++;
	}
	return NULL;
}
int main()
{
	char str1[] = "This is a simple string";
	char* str2= "is";
	char* ret= my_strstr(str1, str2);
	if (*ret == NULL)
		printf("没找到");
	else
		printf("%s \n", ret);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汤姆_511

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值