【C语言】字符串函数分析及模拟实现(万字详解!)


前言

在以前的学习我们掌握了基础的字符函数类型,知道了一些字符串函数如何使用,但不知道具体函数是如何实现的。本篇文章将系统介绍讲解C语言中的字符串函数。通过简洁高效的代码,为友友提供一个清晰明了的讲解,让我们开始吧!


前提!!在使用字符串函数前都要引用头文件#include<string.h>!!!

1.求字符串长度的字符函数

1.1strlen

strlen函数介绍

先看看C语言编译库是如何定义strlen函数的。

在这里插入图片描述
(不知道如何查询C语言编译库可以看我的这期博客,里面有提到 : qsort函数

根据定义我们知道是将目标字符串的首元素地址传给strlen来进行测量。

使用时需要注意以下几点:

  • 字符串以 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包 含 ‘\0’ )
  • 参数指向的字符串必须要以 ‘\0’ 结束。
  • 注意函数的返回值为size_t,是无符号的,所以返回值一定大于等于0

strlen函数简单应用

现在尝试运用一下strlen函数,代码如下:

#define  _CRT_SECURE_NO_WARNINGS 1 

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "1234567890";
	size_t ret = strlen(arr);
	printf("%zd\n", ret);
	return 0;
}

结果如下:
在这里插入图片描述

strlen函数模拟实现

通过上面的分析我们知道strlen函数的基本逻辑就是找到字符串的首地址然后一直计数直到遇到’\0‘就返回。那么根据这个逻辑我们试试模拟实现strlen函数,代码如下:

#define  _CRT_SECURE_NO_WARNINGS 1 
#include<stdio.h>
#include<assert.h>
//方法1:计数
size_t my_strlen1(const char* arr)
{
	assert(arr);//检验arr是否为空指针
	int count = 0;
	while (*arr != '\0')
	{
		count++;
		arr++;
	}
	return count;
}

//方法2:指针-指针
size_t my_strlen2(const char* arr)
{
	assert(arr);
	const char* arr1 = arr;
	while (*arr != '\0')
	{
		arr++;
	}
	return arr - arr1;
}

//方法3:递归
size_t my_strlen3(const char * str)
{
 	if(*str == '\0')
 	return 0;
 	else
 	return 1+my_strlen(str+1);
}

int main()
{
	char arr[] = "1234567890";
	size_t ret1 = my_strlen1(arr);
	printf("%zd\n", ret1);

	size_t ret2 = my_strlen2(arr);
	printf("%zd\n", ret2);

	size_t ret3 = my_strlen3(arr);
	printf("%zd\n", ret3);
	return 0;
}

结果如下:
在这里插入图片描述


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

2.1strcpy

strcpy函数介绍

在这里插入图片描述
strcpy函数有复制字符串的作用,将source(源字符串)复制到destination(目标空间)。

使用时需要注意以下几点:

  • 源字符串必须以 ‘\0’ 结束。
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可更改(不是常量字符串也没有const修饰),否则报错。

strcpy函数简单应用

现在尝试运用一下strcpy函数,代码如下:

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

int main()
{
	char arr1[20] = "xxxxxxxxxxx";
	char arr2[] = "abcdef";
	char* ret = strcpy(arr1, arr2);
	printf("%s\n", ret);
	return 0;
}

结果如下:
在这里插入图片描述

同时我们可以看看arr1数组内部的变化:

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

strcpy函数模拟实现

知道了strcpy函数的逻辑,我们来试试模拟实现,代码如下:

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

char* my_strcpy(char* str1, const char* str2)
{
	assert(str1 && str2);
	char* ret = str1;
	while (*str1++ = *str2++)
	{
		;
	}
	return ret;
}

int main()
{
	char arr1[20] = "xxxxxxxxxxx";
	char arr2[] = "abcdef";
	//char* ret = strcpy(arr1, arr2);
	char* ret = my_strcpy(arr1, arr2);
	printf("%s\n", ret);
	return 0;
}

结果如下:
在这里插入图片描述


2.2strcat

strcat函数介绍

在这里插入图片描述
strcat函数功能是追加字符串,即在目标字符串后接上源字符串实现追加。

使用时需要注意以下几点:

  • 源字符串必须以 ‘\0’ 结束。
  • 会将源字符串中的 ‘\0’ 拷贝到目标空间
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可更改(不是常量字符串也没有const修饰),否则报错。

strcat函数简单应用

那么现在尝试运用一下strcpy函数,代码如下:

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "12345678";
	char* ret = strcat(arr1, arr2);
	printf("%s\n", ret);
	return 0;
}

结果如下:
在这里插入图片描述

strcat函数模拟实现

strcat函数是找到目标空间的末尾后开始将源字符串存入空间,同时最后也将’\0‘拷贝。
现在知道了strcat函数的逻辑,我们来试试模拟实现,代码如下:

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* arr1,const char* arr2)
{
	char* ret = arr1;
	assert(arr1 && arr2);
	while (*arr1)
	{
		arr1++;
	}
	while ((*arr1++ = *arr2++))
	{
		;
	}
	return ret;

}

int main()
{
	char arr1[20] = "abcdef";
	char arr2[] = "12345678";
	//char* ret = strcat(arr1, arr2);
	char* ret = my_strcat(arr1, arr2);
	printf("%s\n", ret);
	return 0;
}

结果如下:
在这里插入图片描述


2.3strcmp

strcmp函数介绍

在这里插入图片描述
strcmp函数意思是str compare,字符串比较。可以看到函数返回类型是整型,它通过 依次比较两字符串元素的ASCII值得出结果。那如何通过整型返回值来反映大小关系呢?
我们可以看看C程序编译库中对返回值的解释:
在这里插入图片描述

通过图片我们得知,ptr1是字符串1的地址,ptr2是字符串2的地址,而函数返回值的意思如下:

如果 *ptr1> *ptr2 ,那么就返回大于0的值,str1 > str2。
如果 *ptr1= *ptr2,那么就返回0即可 ’‘’‘’‘’‘ str1 = str2。
如果 *ptr1< *ptr2 ,那么就返回小于0的值,str1 < str2。

strcmp函数简单应用

基本明白之后我们就可以来试着应用一下了,代码如下:

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

void my_judge(int ret)//判断结果函数
{
	if (ret > 0)
	{
		printf(">\n");
	}
	if (ret < 0)
	{
		printf("<\n");
	}
	if (ret == 0)
	{
		printf("=\n");
	}
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abce";//与arr1元素有不同,与arr1比应输出‘<’
	char arr3[] = "abcde";//与arr1长度不同,其他元素相同,与arr1比应输出‘>’
	int ret1 = strcmp(arr1, arr2);
	my_judge(ret1);
	int ret2 = strcmp(arr1, arr3);
	my_judge(ret2);
	return 0;
}

结果如下:

在这里插入图片描述

我们可以发现,字符串并不是越长值就越大,而是在比较过程中谁先有较大的元素,谁就是较大者 😃。

strcmp函数模拟实现

进行了一系列实践,现在我们可以试试来模拟实现strcmp函数,代码如下:

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

void my_judge(int ret)//判断结果函数
{
	if (ret > 0)
	{
		printf(">\n");
	}
	if (ret < 0)
	{
		printf("<\n");
	}
	if (ret == 0)
	{
		printf("=\n");
	}
}

int my_strcmp(const char* ptr1, const char* ptr2)
{
	assert(ptr1 && ptr2);
	while (*ptr1 == *ptr2)
	{
		if (*ptr1 == '\0')
		{
			return 0;
		}
		ptr1++;
		ptr2++;
	}
	if (*ptr1 > *ptr2)
	{
		return 1;
	}
	else
		return -1;
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abce";//与arr1元素有不同,与arr1比应输出‘<’
	char arr3[] = "abcde";//与arr1长度不同,其他元素相同,与arr1比应输出‘>’
	//int ret1 = strcmp(arr1, arr2);
	//my_judge(ret1);
	//int ret2 = strcmp(arr1, arr3);
	//my_judge(ret2);

	int ret1 = my_strcmp(arr1, arr2);
	my_judge(ret1);
	int ret2 = my_strcmp(arr1, arr3);
	my_judge(ret2);
	printf("\n别忘了点赞三连支持欧o(>ω< )o!!!\n");
	printf("(深情)\n");
	return 0;
}

结果如下:

在这里插入图片描述


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

3.1strncpy

strncpy函数介绍

在这里插入图片描述
strncpy函数和strcpy多了一个参数num,具体作用如下:

拷贝num个字符从源字符串到目标空间。
如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

strncpy简单应用

了解明白新内容现在就来简单应用一下!代码如下:

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

int main()
{
	char str1[] = "To be or not to be";
	char str2[40];
	char str3[40];

	strncpy(str2, str1, sizeof(str2));

	strncpy(str3, str2, 5);
	str3[5] = '\0';  

	puts(str1);
	puts(str2);
	puts(str3);

	return 0;
}

结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


3.2strncat

strncat函数介绍

在这里插入图片描述
和strcat函数很像,不过同样多了个num参数,具体作用如下:

函数将源字符串的前 num 个字符复制到目标字符串,外加一个终止空字符’\0’。
如果源字符串的长度小于 num,则只复制终止空字符之前的内容。

strncat简单应用

了解明白新内容现在就来简单应用一下!代码如下:

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

int main()
{
	char str1[20];
	char str2[20];
	strcpy(str1, "To be ");
	strcpy(str2, "or not to be");
	strncat(str1, str2, 6);
	puts(str1);
	return 0;
}

结果如下:
在这里插入图片描述
可以看到只在str1后接了6个元素,然后停止,不论是否遇到’\0’。


3.3strncmp

strncmp函数介绍

在这里插入图片描述
一样的道理,多了一个num,具体作用如下:

该函数从每个字符串的第一个字符开始比较。如果两个字符串的第一个字符相等,则继续比较下面的字符对,直到两个字符串的字符不同,或者比较到一个终止的空字符’\0’,或者比较到两个字符串中匹配的字符个数,以先发生者为准。

通俗来讲可以理解成:在strcmp函数功能的基础上,由以往的从头比到尾变成了可以控制在一定长度范围内进行比较

strncmp简单应用

都多余了,开始实践!代码如下:

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

int main()
{
    char str[3][5] = { "R2D2" , "C3PO" , "R2A6" };
    int n;
    puts("查找 R2 ...");
    for (n = 0; n < 3; n++)
        if (strncmp(str[n], "R2xx", 2) == 0)
        {
            printf("found %s\n", str[n]);
        }
    return 0;
}

结果如下:
在这里插入图片描述
可以看到,找到的字符串和“R2XX”后两位还是不一样的,但是还是成功找到了R2,成功使用strncmp!!^ ^


4.字符串查找函数

4.1strstr

strstr函数介绍

在这里插入图片描述
strstr函数具体内容如下:

返回 字符串str1 中第一次完整出现 字符串str2 的指针,如果 str2 不是 str1 的一部分,即查找不到,则返回空指针NULL
匹配过程不包括空字符’\0’,但会在此位置时停止。

strstr简单应用

还是得实操一下才能真正理解,代码如下:

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

int main()
{
    char str[] = "This is a simple string";
    char* pch;
    pch = strstr(str, "simple");//pch存放查找到对应字符串的首字母地址
    if (pch != NULL)
        strncpy(pch, "sample", 6);
    puts(str);
    return 0;
}

结果如下:

在这里插入图片描述
也就意味着查找到了地址并用strcpy更改了内容,成功!!


4.2strtok

strtok函数介绍

在这里插入图片描述

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

strtok简单应用

开始冻手!!代码如下:

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

int main()
{
	char arr[] = "tobe@or.not to be";

	char buf[200] = {0};//"tobe@or.not to be"
	strcpy(buf, arr);

	char* p = "@.";
	char* s = strtok(buf, p);
	printf("%s\n", s);

	s = strtok(NULL, p);
	printf("%s\n", s);

	s = strtok(NULL, p);
	printf("%s\n", s);

	return 0;
}

结果如下:
在这里插入图片描述


5.错误信息报告函数

5.1strerror

strerror函数介绍

在这里插入图片描述

这个函数有些特别,它所返回的是错误码所对应的错误信息的地址

那我就会问了,错误码是什么呢?其实很好理解,我们上网打开网页经常会出现问题,例如“404Not found!!”等等,这些都是错误码。通过strerror函数可以把这些错误码对应的具体问题详细输出,就不仅仅只是个数字在屏幕上了。

strerror简单应用

冻手!冻手!代码如下:

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

int main()
{
    int i = 0;
    for (i = 1; i < 10; i++)
    {
        printf("%d:%s\n", i, strerror(i));
    }
    return 0;
}

结果如下:

在这里插入图片描述
可以看到每个数字对应的错误问题,有意思哦 ^ ^。


6.字符分类函数

在这里插入图片描述


7.内存操作函数

memcpy

memcpy函数介绍

在这里插入图片描述
函数memcpy具体功能实现是从source的位置开始向后复制num个字节的数据到destination的内存位置。这个函数在遇到 ‘\0’ 的时候并不会停下来。

注意!! 如果source和destination有任何的重叠,复制的结果都是未定义的。

memcpy简单应用

那就试试呗,代码如下:

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

void test()
{
	char arr1[] = "abcdef";
	char arr2[5] = { 0 };
	memcpy(arr2, arr1, 3);
	printf("%s", arr2);
}

int main()
{
	test();
	return 0;
}

结果如下:
在这里插入图片描述

memcpy函数模拟实现

在这也试试模拟实现memcpy,代码如下:

#define  _CRT_SECURE_NO_WARNINGS 1 
//模拟实现memcpy
//void* memcpy(void* destination, const void* source, size_t num);
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memcpy(void* dest,const void* str, size_t sz)
{
	void* ret = dest;
	while (sz--)
	{
		*(char*)dest = *(char*)str;
		djieguoest = (char*)dest + 1;
		str = (char*)str + 1;
	}
	return ret;
}

int main()
{
	char arr1[] = "hello world";
	char arr2[] = "abc";
	my_memcpy(arr1, arr2, 3);
	printf("%s\n", arr1);

	printf("\n别忘了点赞三连支持欧o(>ω< )o!!!\n");
	printf("(深情)\n");
	return 0;
}

结果如下:
在这里插入图片描述


memmove

memmove函数介绍

在这里插入图片描述
这个很好理解,它和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。

memmove简单应用

尝试着使用一下,都差不多的了,我就不在这里赘述了,我觉得很彳亍 😃

memmove函数模拟实现

那memmove是如何实现的呢?代码如下:

//memmove模拟实现
//void * memmove ( void * destination, const void * source, size_t num );
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memmove(void* dest,const void* str, size_t num)
{
	assert(dest && str);
	void* ret = dest;
	if (dest < str)
	{
		//从前到后
		while (num--)
		{
			*(char*)dest = *(char*)str;
			dest = (char*)dest + 1;
			str = (char*)str + 1;
		}
	}
	else
		//从后到前
	{
		dest = (char*)dest + num - 1;
		str = (char*)str + num - 1;
		while (num--)
		{


			*(char*)dest = *(char*)str;
			dest = (char*)dest - 1;
			str = (char*)str - 1;
		}
	}
	return ret;
}


int main()
{
	char arr[] = "memmove can be very useful......";
	void* str = my_memmove(arr + 20, arr + 15, 5);
	puts(arr);
	return 0;
}



结语

好了以上就是本篇“【C语言】字符串函数分析及模拟实现”博客的全部内容啦,感谢各位的阅读=v=,如有不足之处欢迎在评论区指出哦!!
觉得可以的话别忘了点赞三连支持一下欧!拜托啦这对我真的很重要o(>ω< )o!!!

请添加图片描述

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值