【编程之路(012)字符串相关函数】(C语言实现)

C语言中对字符和字符串的处理很是频繁,但是 C语言本身是没有字符串类型的,字符串通常放在
常量字符串(char* arr="abc") 中或者 ( 字符数组char arr[] ="abc")中。
字符串常量 适用于那些对它不做修改的字符串函数
接下来将会介绍些函数,并且将模拟部分函数,实现它们的功能
求字符串长度
strlen
长度不受限制的字符串函数                             长度受限制的字符串函数介绍
strcpy                                                               strncpy
strcat                                                                strncat
strcmp                                                              strncmp
字符串查找
strstr
strtok
错误信息报告
strerror

目录

1.求字符串长度——strlen

strlen函数介绍:

模拟实现strlen函数:

2.复制字符串——strcpy

strcpy函数的介绍:

模拟实现strcpy函数:

3.追加字符串——strcat

strcat函数的介绍:

模拟实现strcat函数:

4.比较字符串——strcmp

strcmp函数介绍:

模拟实现strcmp:

5.复制n个字符串——strncpy

strncpy函数介绍:

模拟实现strncpy函数:

 6.追加n个字符串——strncat

strncat函数介绍:

strncat函数的模拟实现:

7.比较字符串——strncmp

strncmp函数介绍:

strncmp函数的模拟实现:

8.寻找相同字串——strstr

strstr函数介绍:

strstr函数的模拟实现:

9.分割字符串——strtok

strtok函数的介绍:

strtok函数具体使用:

10.报错字符串——strerror

strerror函数介绍:

strerror函数演示:


1.求字符串长度——strlen

strlen函数介绍:

返回类型:size_t

参数类型:const char*

其中size_t:

        size_t在32位架构中定义为:typedef   unsigned int size_t;

        size_t在64位架构中被定义为:typedef  unsigned long size_t;

其类型的原因就导致了容易出一些错误。

#include <stdio.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; 
}

 

出现这个结果的原因就是相减表面上结果为-3,但内存中-3被认作无符号数,所以就变成了很大的数。数据在内存中的存储不再详细介绍,具体参考【编程之路(010)数据的存储(进阶)】(C语言实现)_p_fly的博客-CSDN博客

模拟实现strlen函数:

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

size_t my_strlen(const char* arr)
{
	//首先需要判断传过来的指针是否为空
	assert(arr);

	size_t n = 0;
	while (*arr != '\0')
	{
		n++;
		arr++;
	}
	return n;
}

int main()
{
	char arr[] = "abcdef";
	int len = my_strlen(arr);
	printf("%d\n", len);

	return 0;
}

2.复制字符串——strcpy

strcpy函数的介绍:

返回类型:

返回被复制空间的地址,即char*类型

参数类型:

第一个参数是被复制空间的地址,第二个要复制的字符串地址

 注:

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

模拟实现strcpy函数:

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

char* my_strcpy(char* strdes, const char* strsou)
{
	//判断目标地址和复制的地址是否为空
	assert(strdes && strsou);

	//因为会移动被赋值空间的地址,所以先记录,方便后续返回
	char* ret = strdes;

	while (*strdes++ = *strsou++)
		;
	return ret;
}

int main()
{
	char arr1[100];
	char arr2[] = "abcdef";
	printf("%s\n", my_strcpy(arr1, arr2));
	return 0;
}


3.追加字符串——strcat



strcat函数的介绍:

 返回类型:

被追加字符串的地址,所以是char*

参数类型:

第一个参数:被追加字符串的地址

第二个参数:所要追加的字符串的地址

注:
源字符串必须以 '\0' 结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
字符串不能自己给自己追加,因为'\0'会被覆盖,所以就会出问题。

模拟实现strcat函数:

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

char* my_strcat(char* strdes, const char* strsou)
{
	//还是一上来先判断指针是否为空
	assert(strdes && strsou);

	//由于还是要返回原字符串的地址,所以还是要先保存地址
	char* ret = strdes;

	while (*strdes != '\0')
		strdes++;
	while (*strdes++ = *strsou++)
		;

	return ret;
}

int main()
{
	char arr1[100] = "hello ";
	char arr2[] = "world";

	printf("%s\n", my_strcat(arr1, arr2));

	return 0;
}


4.比较字符串——strcmp

strcmp函数介绍:

返回类型:

参数类型:两个要比较的字符串的地址。

注:这里所比较的大小是字符串的内容,依次比较每个字符的大小(ASCII值),当有一个字符不相等是立即停止比较。万不可当成比较字符串的长度。

模拟实现strcmp:

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

int my_strcmp(const char* str1, const char* str2)
{
	//判断是否为空
	assert(str1 && str2);

	while (*str1 == *str2)
	{
		//如果*str1==*str2=='\0'就说明走到头了二者还是相等
		if (*str1 == '\0')
		{
			return 0;
		}

		str1++;
		str2++;
	}

	//这里如果*str1>*str2,相减会返回大于零的值,反正返回小于零的值
	return (*str1 - *str2);
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abd";
	int tmp = my_strcmp(arr1, arr2);
	if (tmp > 0)
	{
		printf("arr1>arr2\n");
	}
	else if (tmp == 0)
	{
		printf("arr1==arr2\n");
	}
	else
	{
		printf("arr1<arr2\n");
	}

	return 0;
}


以上三个函数都是字符串长度不受限制的函数,换言之它们都是找到'\0'才罢休,不加限制通常是不太安全的,所以C语言还提供了三者的改良版。


5.复制n个字符串——strncpy

strncpy函数介绍:

 返回类型与前两个参数类型相同,多出来的size_t count就是复制count个字符到字符串strDest中去。

注:如果想要复制的字符个数count超过了strSource字符串本身的字符个数,通过监视我们可以发现,多出的部分自动复制成'\0'了

模拟实现strncpy函数:

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

char* my_strcpy(char* strdes, const char* strsou,size_t n)
{
	//判断目标地址和复制的地址是否为空
	assert(strdes && strsou);

	//因为会移动被赋值空间的地址,所以先记录,方便后续返回
	char* ret = strdes;

	while (n && (*strdes++=*strsou++))
	{
		n--;
	}
	if (n)
	{
		while (--n)
		{
			*strdes = '\0';
			strsou++;
		}
	}
	return ret;
}

int main()
{
	char arr1[15]="**********";
	char arr2[] = "abcdef";
	printf("%s\n", my_strcpy(arr1, arr2,8));

	return 0;
}


 6.追加n个字符串——strncat

strncat函数介绍:

与上面的函数同理。

strncat函数的模拟实现:

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

char* my_strncat(char* strdes, const char* strsou, int n)
{
	//还是一上来先判断指针是否为空
	assert(strdes && strsou);

	//由于还是要返回原字符串的地址,所以还是要先保存地址
	char* ret = strdes;

	while (*strdes != '\0')
		strdes++;
	while ((*strdes++ = *strsou++) && --n)
		;

	return ret;
}

int main()
{
	char arr1[15] = "*****";
	char arr2[] = "abcd";
	my_strncat(arr1, arr2, 3);
	return 0;
}


7.比较字符串——strncmp

strncmp函数介绍:

 与上面函数一样,仅仅多了比较的字符个数count。

strncmp函数的模拟实现:

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

int my_strcmp(const char* str1, const char* str2, size_t n)
{
	//判断是否为空
	assert(str1 && str2);

	while ((*str1 == *str2) && --n)
	{
		
		if (*str1 == '\0')
		{
			return 0;
		}

		str1++;
		str2++;
	}

	//这里如果*str1>*str2,相减会返回大于零的值,反正返回小于零的值
	return (*str1 - *str2);
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "accde";
	int tmp = my_strcmp(arr1, arr2, 2);
	if (tmp > 0)
	{
		printf("arr1>arr2\n");
	}
	else if (tmp == 0)
	{
		printf("arr1==arr2\n");
	}
	else
	{
		printf("arr1<arr2\n");
	}

	return 0;
}

8.寻找相同字串——strstr

strstr函数介绍:

 返回类型:这里返回的是长串中相同字串一开始出现的位置。

参数类型:第一个参数:

                 长串的位置(要背查找的串的位置)

                 第二个参数:

                 要查找的字串的位置

注:如果没有查找到子串,那就返回NULL

strstr函数的模拟实现:

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

char* my_strstr(const char* str1, const char* str2)
{
	//判断指针是否为空
	assert(str1 && str2);

	char* s1 = str1;
	char* s2 = str2;
	char* t = s1;

	//当t指针走到最后的时候,就结束了
	while (*t)
	{
		//提前记录好指针
		t = s1;
		s2 = str2;
		while (*s1 == *s2 && *s1 != '\0' && *s2 != '\0')
		{
			s1++;
			s2++;
		}
		//从上面循环走出来之后,若s2走到了头,就说明找到了相同的字串
		if (*s2 == '\0')
		{
			return t;
		}
		//不排除被找的串比要找的串短
		else if (*s1 == '\0')
		{
			return NULL;
		}
		//暂时还没找到相同的子串,需要往后继续找
		else
		{
			s1 = t + 1;
		}

	}

	return NULL;
}

int main()
{
	char arr1[] = "abd";
	char arr2[] = "zzdge";
	printf("%s\n", my_strstr(arr1, arr2));

	return 0;
}

9.分割字符串——strtok

strtok函数的介绍:

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

使用该函数后会达到如下效果:

 

 可以看出,它都是把sep中的字符对应到str中,让后换成'\0'。

那么改函数是如何具体的工作的呢?

第一个参数指定一个字符串,它包含了 0 个或者多个由 sep 字符串中一个或者多个分隔符分割的标
记。
第二个参数的字符串只能是常量字符串。(因为不可修改)
strtok 函数找到 str 中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:
strtok 函数会改变被操作的字符串,所以在使用 strtok 函数切分的字符串一般都是临时拷贝的内容
并且可修改。)
strtok 函数的第一个参数不为 NULL ,函数将找到 str 第一个标记 strtok 函数将保存它在字符串
中的位置
strtok 函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标
记。
如果字符串中不存在更多的标记,则返回 NULL 指针。

strtok函数具体使用:

//由上面的介绍,我们写出了以下代码
#include<stdio.h>
#include<string.h>

int main()
{
	char str[] = "ab#cde*f&gh@ijk";
	char* sep = "#*@";
	char arr[20];
	strcpy(arr, str);

	char* arr1 = strtok(arr, sep);
	char* arr2 = strtok(NULL, sep);
	char* arr3 = strtok(NULL, sep);
	char* arr4 = strtok(NULL, sep);

	printf("%s\n", arr1);
	printf("%s\n", arr2);
	printf("%s\n", arr3);
	printf("%s\n", arr4);

	return 0;
}

可以看出,上面的代码非常冗余,我们可以利用for循环,或者while循环改进一下。

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

int main()
{
	char str[] = "ab#cde*f&gh@ijk";
	char* sep = "#*@";
	char arr[20];
	strcpy(arr, str);

	//for循环
	//找一个临时变量记录strtok函数记录的地址
	char* a = NULL;
	for (a = strtok(arr, sep); a != NULL;a=strtok(NULL,sep))
	{
		printf("%s\n", a);
	}

	//while循环
	char* b = NULL;
	b = strtok(arr, sep);
	while (b != NULL)
	{
		printf("%s\n", b);
		b = strtok(NULL, sep);
	}

	return 0;
}

 


10.报错字符串——strerror

strerror函数介绍:

 

当我们写出来的程序有错误时,他就会返回一个错误码。有了这个错误码,我们就可以利用strerror函数把错误码对应的错误信息给打印在屏幕上。

 

strerror函数演示:

#include <stdio.h>
#include <string.h>
#include <errno.h>//必须包含的头文件

int main()
{
	FILE* pFile;
	pFile = fopen("unexist.ent", "r");
	if (pFile == NULL)
		printf("Error opening file unexist.ent: %s\n", strerror(errno));

	return 0;
}

 


有什么问题希望大家在评论区指出来。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值