字符串函数介绍及其模拟实现


字符串函数介绍及其模拟实现


前言

C语言中对字符和字符串的处理是很频繁的,但是C语言中并没有字符串类型的,字符串通常放在 常量字符串 中或者 字符数组 中。
字符串常量适用于那些对它不做修改的字符串函数。

编译环境:vs2013


一、字符串函数

1.求字符串长度

⚪strlen

strlen文档

size_t strlen ( const char* str );

作用:求字符串长度。

函数返回值:返回str指向字符串的长度。

  • 字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
  • 注意:函数的返回值为size_t,是无符号的。

strlen模拟实现及函数测试:

//1.my_strlen 求字符串长度
//方式一:计数器方式
int my_strlen1(const char* str)
{
	int count = 0;
	while (*str)
	{
		count++;
		str++;
	}
	return count;
}
//方式二:不创建临时变量计数器
int my_strlen2(const char* str)
{
	if (*str == '\0')
		return 0;
	else
		return my_strlen2(str + 1) + 1;
}
//方式三:指针-指针方式
int my_strlen3(char* str)
{
	char* p = str;
	while (*p != '\0')
	{
		p++;
	}
	return p - str;
}
//my_strlen测试函数
void test_my_strlen()
{
	char* str1 = "hello world";
	char* str2 = "abcd";
	char* str3 = "abcdef";
	int len1 = my_strlen1(str1);
	int len2 = my_strlen2(str2);
	int len3 = my_strlen3(str3);
	printf("str1=%d\n", len1);
	printf("str2=%d\n", len2);
	printf("str3=%d\n", len3);
}

在这里插入图片描述

2.长度不受限制的字符串函数

⚪strcpy

strcpy文档

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

作用:将source指向的 C 字符串复制到destination指向的数组中,包括终止的 ‘\0’ 字符(并在该点停止)。

函数返回值:返回目标字符串。

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

strcpy模拟实现及函数测试:

//2.my_strcpy 复制字符串src到字符数组dest中去
char* my_strcpy(char* dest, char* src)
{
	char* ret = dest;
	//断言:dest和src不为空,为空的话则报错返回
	assert(dest != NULL);
	assert(src != NULL);
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}
//my_strcpy测试函数
void test_my_strcpy()
{
	char str1[] = "abc";
	char str[10] = { 0 };
	char* ret = my_strcpy(str, str1);
	printf("%s\n", ret);
}

在这里插入图片描述
在这里插入图片描述

⚪strcat

strcat文档

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

作用:将源字符串的副本追加到目标字符串。目标字符串中的终止字符 ‘\0’ 被源字符串的第一个字符覆盖,并且在目标字符串中由两者串联形成的新字符串的末尾包含一个 ‘\0’ 。

函数返回值:返回追加成功后的目标字符串。

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

strcat模拟实现及函数测试:

//3.my_strcat 将src字符串追加到dest字符串后面去
char* my_strcat(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest != NULL);
	assert(src != NULL);
	while (*dest)
	{
		dest++;
	}
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}
//my_strcat测试函数
void test_my_strcat()
{
	char str[10] = "ab";
	char str1[]= "+abcd";
	//在str后面追加str1
	char* ret = my_strcat(str, str1);
	printf("%s\n", ret);
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

⚪strcmp

strcmp文档

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

作用:将 C 字符串 str1 与 C 字符串 str2 进行比较。
从两个字符串的第一个字符开始比较,如果相等,则比较第二个字符,依次进行下去,直到有字符不同或达到终止空字符。

函数返回值:

  • str1>str2,则返回大于0的数字
  • str1=str2,则返回0
  • str1<str2,则返回小于0的数字

字符串大小的比较规则:字符串大小的比较是以ASCII码表上的顺序来决定,此顺序即为字符的值。
strcmp模拟实现及函数测试:

//4.my_strcmp 比较两字符串大小
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 != NULL);
	assert(str2 != NULL);
	while (*str1 == *str2)
	{
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
	}
	if (*str1 > *str2)
		return 1;
	else if (*str1 < *str2)
		return -1;
}
//my_strcmp测试函数
void test_my_strcmp()
{
	char str1[10] = "abc";
	char str2[10] = "abcd";
	int ret = my_strcmp(str1, str2);
	if (ret == 0)
		printf("str1==str2\n");
	else if (ret>0)
		printf("str1>str2\n");
	else
		printf("str1<str2\n");
}

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3.长度受限制的字符串函数

⚪strncpy
char* strncpy ( char* destination, const char* source, size_t num );

作用:拷贝num个字符从源字符串到目标空间。

函数返回值:返回追加完字符后的目标字符串。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加 0,直到达到num个字符。

strncpy模拟实现及函数测试:

//5.my_strncpy 从src中复制num个字符到dest中
char* my_strncpy(char* dest, const char* src, int num)
{
	char* temp = dest;
	assert(dest != NULL);
	assert(src != NULL);
	while (num && *src)
	{
		*dest++ = *src++;
		num--;
	}
	//当num大于字符串的长度时,用\0来进行填充
	while (num--)
	{
		*dest++ = '\0';
	}
	return temp;
}
//my_strncpy测试函数
void test_my_strncpy()
{
	char str1[10] = { 0 };
	char* str2 = "abcd";
	char* ret1 = my_strncpy(str1, str2, 2);
	printf("ret1=%s\n", ret1);
	char* ret2 = my_strncpy(str1, str2, 6);
	printf("ret2=%s\n", ret2);
}

在这里插入图片描述

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

作用:从源字符串的开头拷贝num个字符到目标字符串的尾部,若num大于源字符串的长度,那么仅将源字符串追加到目标的尾部。

函数返回值:返回追加字符串后的目标字符串。

  • 目标空间得足够容纳下要拷贝的字符串。
  • 追加的时候源字符串后将目标最后的 ‘\0’ 覆盖掉,追加完成后,会追加上 ‘\0’ 作为追加后字符串的结束标志。

strncat模拟实现及函数测试:

//6. my_strncat 从src开头拷贝num个字符追加到dest尾部
char* my_strncat(char* dest, const char* src, size_t num)
{
	char* temp = dest;
	assert(dest != NULL);
	assert(src != NULL);
	while (*dest)
	{
		dest++;
	}
	while(num--)
	{
		*dest++ = *src++;
	}
	*dest = '\0';
	return temp;
}
//my_strncat测试函数
void test_my_strncat()
{
	char str1[10] = "ab";
	char *str2 = "cdef";
	char* ret1 = my_strncat(str1, str2, 1);
	printf("ret1=%s\n", ret1);
	char* ret2 = my_strncat(str1, str2, strlen(str2));
	printf("ret2=%s\n", ret2);
}

在这里插入图片描述
在这里插入图片描述

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

作用:比较str1和str2,只比较两字符串的前num个字符。

函数返回值:

  • str1>str2,则返回大于0的数字
  • str1=str2,则返回0
  • str1<str2,则返回小于0的数字

strncmp模拟实现及函数测试:

//7.strncmp 比较两字符串的前num个字符
int my_strncmp(const char* str1, const char* str2, int num)
{
	assert(str1 != NULL);
	assert(str2 != NULL);
	//当两字符串中字符不相等或num为0时跳出循环
	while (*str1 == *str2 && num)
	{
		if (*str1 == '\0')
			return 0;
		str1++;
		str2++;
		num--;
	}
	if (*str1 > *str2)
		return 1;
	else if (*str1 < *str2)
		return -1;
}
//my_strncmp测试函数
void test_my_strncmp()
{
	char* st1 = "ab";
	char* st2 = "abc";
	int ret = strncmp(st1, st2, 2);
	printf("%d\n", ret);
}

在这里插入图片描述
函数只比较两字符串的前两个字符,例子中两字符都相等,故函数返回0。

4.字符串查找

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

作用:判断str2是否是str1的子串。如果是,函数返回str1字符串从str2第一次出现的位置开始到str1结束的字符串,不是则返回NULL。

strstr模拟实现及函数测试:

//8.my_strstr判断str2是否为str1的子串
const char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 != NULL);
	assert(str2 != NULL);
	char* temp1 =(char*) str1;
	char* temp2 =(char*) str2;
	char* s = NULL;

	if (*str2 == '\0')
		return NULL;
	while (*temp1)
	{
		s = temp1;
		temp2 = str2;
		while (*s && *temp2 && (*s == *temp2))
		{
			s++;
			temp2++;
		}
		if (*temp2 == '\0')
			return temp1;
		temp1++;
	}
}
//my_strstr测试函数
void test_my_strstr()
{
	char* str2 = "cdef";
	char* str1 = "abcdefg";
	char* ret = my_strstr(str1, str2);
	if (ret!=NULL)
		printf("str2是str1 的子串\n");
	else
		printf("str2不是str1 的子串\n");
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

作用:返回分隔符之前的字符串的首地址,将含有特殊字符的字符串进行分割。
返回值:成功返回被分割出的片段的指针,没有可被分割的字符串的话返回NULL。

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

注意:在外面以sep中字符对str进行切割时,调用一次strtok只能找到一个标记,若被分割字符串中有多个分割字符,则需要调用多次strtok函数。

strtok模拟实现及函数测试:

//9.my_strtok将含有特殊字符的字符串进行分割
char* my_strtok(char* str, const char* sep)
{
	//使用静态成员temp记录每次切割的起始位置
	static char* temp = NULL;
	if (str != NULL)
		temp = str;
	if (temp == NULL)
		return NULL;
	if (sep == NULL)
		return temp;

	//将分隔符字符串中字符进行保存到一数组中
	char table[256] = { 0 };
	while(*sep != '\0')
	{
		table[*sep++] = 1;
	}
	//在temp中找第一个没在table数组中的元素
	while (*temp != '\0' && table[*temp] == 1)
	{
		temp++;
	}
	//找到了,但循环跳出可能为temp走到结束标志\0的位置,故判断一下
	char* ret = *temp != '\0' ? temp : NULL;
	while (*temp != '\0' && table[*temp] == 0)
	{
		temp++;
	}
	if (*temp != '\0')
		*temp++ = '\0';
	return ret;
}
//my_strtok测试函数
void test_my_strtok()
{
	char str1[] = "ab@cde&a%gh*tu";
	char* str2;
	printf("Splitting string \"%s\" into tokens:\n", str1);
	str2 = my_strtok(str1, "@&%*");
	while (str2 != NULL)
	{
		printf("%s\n", str2);
		str2 = my_strtok(NULL, "@&%*");
	}
}

在这里插入图片描述
在这里插入图片描述
当然字符替换过程并非一次性全部将特殊字符处全部替换为\0,调用一次函数只能找出一个特殊字符,即只可以切割出一个字符串,切割完整个字符串的切割过程为一个循环进行切割的过程。
5.错误信息报告

⚪strerror
char* strerror ( int errnum );

作用:通过标准错误的标号,获得错误的描述字符串,将单纯的错误标号转为字符串描述,方便用户查找错误。

  • errnum:调用库函数失败,返回的错误码。
  • 函数返回:指向错误码所对应的错误信息的首地址。

对于strerror函数,我们就不进行模拟实现了,感兴趣的可以自己下去实现一下。

//10.strerror 通过错误信息标号获得错误的描述字符串
void test_strerror()
{
	FILE* p = fopen("m.txt", "r");
	if (p == NULL)
	{
		printf("Error opening file m.txt: %s\n", strerror(errno));
	}
}

在这里插入图片描述
其中,errno为一个全局变量的错误码,类型为整型,当系统调用出错的时候都会设置一个错误码,这是因为C语言没有异常处理机制,故要依靠错误码来进行异常情况的处理。


二、总结

以上字符串函数所在头文件为:#include<string.h>里面

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值