【c语言】字符串函数

文章目录

  • 一、strlen的使用和模拟实现
    • [1.1. strlen的使用](#1.1. strlen的使用)
    • [1.2. strlen的模拟实现](#1.2. strlen的模拟实现)
      • [1.2.1. 计数器方法模拟实现strlen](#1.2.1. 计数器方法模拟实现strlen)
      • [1.2.2. 指针-指针方法模拟实现strlen](#1.2.2. 指针-指针方法模拟实现strlen)
      • [1.2.3. 递归方式模拟实现strlen](#1.2.3. 递归方式模拟实现strlen)
  • 二、strcpy的使用和模拟实现
    • [2.1. strcpy的使用](#2.1. strcpy的使用)
    • [2.2. strcpy的模拟实现](#2.2. strcpy的模拟实现)
  • 三、strcat的使用和模拟实现
    • [3.1. strcat的使用](#3.1. strcat的使用)
    • [3.2. strcat的模拟实现](#3.2. strcat的模拟实现)
  • 四、strcmp的使用和模拟实现
    • [4.1. strcmp的使用](#4.1. strcmp的使用)
    • [4.1. strcmp的模拟实现](#4.1. strcmp的模拟实现)
  • 五、strncpy、strncat、strncmp的使用
    • [5.1. strncpy的使用](#5.1. strncpy的使用)
    • [5.2. strncat的使用](#5.2. strncat的使用)
    • [5.3. strncmp的使用](#5.3. strncmp的使用)
  • 六、strstr的使用和模拟实现
    • [6.1. strstr的使用](#6.1. strstr的使用)
    • [6.2. strstr的模拟实现](#6.2. strstr的模拟实现)

一、strlen的使用和模拟实现

1.1. strlen的使用

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

c 复制代码
size_t strlen ( const char * str );

注意:

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

例题:结果打印什么?

c 复制代码
#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即为字符串元素的个数

c 复制代码
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就是首末元素地址之间元素的个数

c 复制代码
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

思路:

c 复制代码
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

c 复制代码
char* strcpy(char * destination, const char * source );

注意:

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

2.2. strcpy的模拟实现

c 复制代码
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的使用

c 复制代码
char * strcat ( char * destination, const char * source );

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

注意:

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

3.2. strcat的模拟实现

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

c 复制代码
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的使用

c 复制代码
int strcmp ( const char * str1, const char * str2 );

strcmp是比较字符的函数,比较的是在对应位置上字符的ASCII码值的大小,并不在乎字符串长度的大小

如果第一个字符串大于第二个字符串,则返回一个大于零的数字;

如果两字符串相等,返回零;

如果第一个字符串大于第二个字符串,则返回一个大于零的数字;

4.1. strcmp的模拟实现

c 复制代码
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的使用

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

示例:

c 复制代码
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的使用

c 复制代码
char * strncat ( char * destination, const char * source, size_t num );

将source前num个字符追加到dest字符串的结尾,再追加一个 \0;

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

5.3. strncmp的使用

c 复制代码
int strncmp ( const char * str1, const char * str2, size_t num );

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

六、strstr的使用和模拟实现

6.1. strstr的使用

c 复制代码
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始终不变

c 复制代码
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.

  1. 找不到的情况

这种情况下,s1始终找不到s2,最终s1指向末尾\0,跳出循环,返回NULL

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

c 复制代码
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;
}
相关推荐
Demons_kirit13 分钟前
LeetCode 1007. 行相等的最少多米诺旋转 题解
算法·leetcode·职场和发展
n33(NK)20 分钟前
【算法基础】插入排序算法 - JAVA
java·数据结构·算法·排序算法
YuforiaCode30 分钟前
第十六届蓝桥杯 2025 C/C++组 密密摆放
c语言·c++·蓝桥杯
时时三省39 分钟前
【时时三省】(C语言基础)怎样定义和引用一维数组
c语言
Echo``1 小时前
13:图像处理—畸变矫正详解
图像处理·人工智能·数码相机·算法·计算机视觉·视觉检测
EanoJiang1 小时前
排序
算法
forth touch2 小时前
C与指针——输入输出
c语言·开发语言
Chandler242 小时前
LeetCode:DP-回文串问题
算法·leetcode·动态规划
hzxxxxxxx3 小时前
类和对象(上)
算法
qq_447429413 小时前
数据结构与算法:图论——最短路径
c语言·数据结构·c++·图论