常用操作符函数的模拟实现详解(strlen,strcmp,strcpy,strncpy,strcat,strncat)

前言

试着去模拟实现一些库函数,可以帮助我们更好的理解编程思想,巩固我们的知识。有不少朋友可能和我一样,刚开始尝试,会遇到很多问题,但是没关系,迈过这一步,你的能力就会有质的提升。

推荐一个网站查库函数的使用,里面是简洁的中文介绍,附带例子,对英语不友好的朋友佷方便。

C 标准库 - <stdio.h>

strncat函数介绍

strncat 是我最开始尝试实现的一个字符操作函数,其实并不难,就是用到了一些指针的知识,完全理解后就可以触类旁通的去实现其他函数了。

描述

把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止。

声明

下面是 strncat() 函数的声明。

char *strncat(char *dest, const char *src, size_t n)

参数

  • dest – 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串,包括额外的空字符。
  • src – 要追加的字符串。
  • n – 要追加的最大字符数。

返回值

该函数返回一个指向最终的目标字符串 dest 的指针。

strncat函数模拟实现

一个函数的实现主要看实现的功能、返回值、传递的参数,库函数已经把这些内容都描述的很清楚了,我就不再赘述。

函数返回一个指向目标的指针,需要传递的有要追加的字符串地址、目标字符串地址、传递的字符数三个形式参数,我们不妨照猫画虎声明一个自己写的函数:

char *my_strncat(char *dest, const char *src, size_t n)

接下来就可以根据函数功能的描述去实现函数体了。要往目标字符串后添加内容,需要先对 ‘\0’ 有一个明确的认识。

  1. ’\0’ 是判定字符数组结束的标识,表示这串字符到结尾了;
  2. 在字符数组中 ’\0’ 是占一个位置的!
  3. ’\0’在数组中占有空间却不被我们看到;

有了这个理解,我们自然思路就清晰了,从目标数组的停止标志位 ’\0’ 开始,依次替换成需要添加的字符串,并循环n次,并最终返回最初目标字符串的地址即可达成目的。需要注意的是,目标字符串的空间要足够大,以保证接受完添加的字符后不会越界。接下来用函数实现上述思路:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>

char* my_strncat(char* dest, const char* src, size_t n)
//src不涉及修改,可以用const修饰成常量
{
    
    
	assert(dest != NULL);
	assert(src != NULL);//先断言,确保两个字符串地址不是空指针
	char* start = dest; //先保存dest起始地址,因为后面地址会改变
	
	while (*dest)
	{
    
    
		dest++;
	}
	while (n--)
	{
    
    
		*dest++ = *src++;
	}
	return start;
}
int main()
{
    
    
	char arr1[10] = "hello ";
	char arr2[10] = "world";
	my_strncat(arr1, arr2, 3);//数组名就是首元素地址
	printf("%s\n", arr1);
	return 0;
}

输出结果;
在这里插入图片描述
有两个while循环虽然看起来很简单,但信息量极大,对于小白来说可能读起来略微吃力,我需要解释一下:

	while (*dest)
	{
    
    
		dest++;
	}

先理解一些小细节

  • *dest++和dest++两种操作都会使指针后移
  • *(dest+i)相当于dest[i],可以遍历字符串(数组)

这个while循环的意思就是遍历dest每个字符,遍历到’\0’时循环结束,此时dest指向’\0’。

	while (*dest++)
	{
    
    
		;
	}

可能会有人想到用这个方法,找到’ \0 ’ ,其实是错误的,涉及到后置++的用法(先使用,后+1),当dest=’ \0 '时循环确实停止了,但是dest还会+1指向下一个元素 ,因为while判断条件算做使用一次。这样做的后果就是dest的停止标志位还在,往后添加任何字符,最终都看不到。

	while (n--)
	{
    
    
		*dest++ = *src++;
	}

避免错误后,我们继续,到第二个循环时,dest指针指向 ‘\0’ ,接下来依次将src的字符传递给dest。
第一次循环时:
因为后置++是先使用再+1的操作,所以可以分解成以下几步

*dest = '\0';
*src = 'w';
*dest = *src = 'w';
*src = *src+1;
*dest = *dest + 1;

后面循环依次类推,共循环n次,也就是在dest后面添加了n个字符。因为返回的是一开始保存的dest数组的首元素地址,所以通过地址就可以找到修改后的字符串啦。

如果你能完全理解这个模拟函数的实现,那么后面几个函数对你来说已经不是什么难题了,你可以试着先查看库函数的使用,然后自己实现看看,如果不会可以接着往下看。

strcat函数介绍

描述

把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。

声明

下面是 strcat() 函数的声明。

char *strcat(char *dest, const char *src)

参数

  • dest – 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串。
  • src – 指向要追加的字符串,该字符串不会覆盖目标字符串。

返回值

该函数返回一个指向最终的目标字符串 dest 的指针。

strcat函数模拟实现

strcat的实现和strncat差不多,只不过是往后添加时的停止判断条件改为遇到src的停止标志位 ’ \0 '时,添加字符结束。

函数声明

char* my_strcat(char* dest, const char* src)

函数实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>

char* my_strcat(char* dest, const char* src)
//src不涉及修改,可以用const修饰成常量
{
    
    
	assert(dest != NULL);
	assert(src != NULL);//先断言,确保两个字符串地址不是空指针
	char* start = dest; //先保存dest起始地址,因为后面地址会改变
	
	while (*dest)
	{
    
    
		dest++;
	}
	while (*dest++ = *src++)
	{
    
    
		;
	}
	return start;
}
int main()
{
    
    
	char arr1[20] = "hello ";
	char arr2[10] = "world";
	my_strcat(arr1, arr2);//数组名就是首元素地址
	printf("%s\n", arr1);
	return 0;
}

输出结果:
在这里插入图片描述

strlen函数介绍

描述

计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。

声明

下面是 strlen() 函数的声明。

size_t strlen(const char *str)

参数

  • str – 要计算长度的字符串。

返回值

该函数返回字符串的长度。

strlen函数模拟实现

strlen的实现也很简单,这里给出两种方法,一种就是利用指针遍历技术,遇到’ \0 '时停止计数,返回最终的计数值即可。另一种方法是用数组的尾地址(指针指向 ’ \0 ’ 的地址)减去起始地址也可以得到字符串长度。能这么做的原因是字符型指针步长正好为1。

函数声明

size_t my_strlen1(char* arr)
size_t my_strlen2(char* arr)

函数实现:

size_t my_strlen1(char* arr)
{
    
    
	assert(arr != NULL);
	size_t len = 0;
	while (*arr++)
	{
    
    
		len++;
	}
	return len;
}
size_t my_strlen2(char* arr)
{
    
    
	assert(arr != NULL);
	char* start = arr;//首地址
	while (*arr)
	{
    
    
		arr++;//循环结束指针指向'\0'
	}
	return arr - start;
}
int main()
{
    
    
	char arr[10] = "hello";
	size_t len1 = my_strlen1(arr);
	size_t len2 = my_strlen2(arr);
	printf("len1 = %d\n", len1);
	printf("len2 = %d\n", len2);
	return 0;
}

输出结果
在这里插入图片描述

strcmp函数介绍

描述

把 str1 所指向的字符串和 str2 所指向的字符串逐个字符的ASCLL码进行比较,出现字符不相等情况,或者遇到’\0’时,立刻返回字符大小(ASCLL码)之差。

声明

下面是 strcmp() 函数的声明。

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

参数

  • str1 – 要进行比较的第一个字符串。
  • str2 – 要进行比较的第二个字符串。

返回值

该函数返回值如下:

  • 如果返回值小于 0,则表示 str1 小于 str2。
  • 如果返回值大于 0,则表示 str1 大于 str2。
  • 如果返回值等于 0,则表示 str1 等于 str2。

strcmp函数模拟实现

strcmp的实现其实也很简单,无非是先找到两个字符串不同的地方,然后进行相减运算,再返回结果就行。有了前面的铺垫,也很容易用代码实现。

函数声明

int my_strcmp(const char *str1, const char *str2)

函数实现:

int my_strcmp(const char* str1, const char* str2)
{
    
    
	assert(str1 != NULL);
	assert(str2 != NULL);
	while (!(*(unsigned char*)str1 - *(unsigned char*)str2) && *str1)
	//只要str1和str2的字符相同并且str1没遇到'\0',就一直循环
	{
    
    
		str1++;
		str2++;
	}
	return *str1 - *str2;
}
int main()
{
    
    
	char arr1[10] = "adcdA";
	char arr2[10] = "abcde";
	int ret = my_strcmp(arr1, arr2);
	if (ret < 0)
	{
    
    
		printf("str1<str2\n");
	}
	else if (ret>0)
	{
    
    
		printf("str1>str2\n");
	}	
	else
	{
    
    
		printf("str1=str2");
	}
}

输出结果:
arr1的第二个字符d的ascll码为100,arr2的第二个字符ascll码大小为98,100 - 98 = 2 > 0,所以结果如下
在这里插入图片描述

strncmp函数介绍

描述

把 str1 和 str2 进行比较,最多比较前 n 个字节。

声明

下面是 strncmp() 函数的声明。

int strncmp(const char *str1, const char *str2, size_t n)

参数

  • str1 – 要进行比较的第一个字符串。
  • str2 – 要进行比较的第二个字符串。
  • n – 要比较的最大字符数。

返回值

该函数返回值如下:

  • 如果返回值 < 0,则表示 str1 小于 str2。
  • 如果返回值 > 0,则表示 str2 小于 str1。
  • 如果返回值 = 0,则表示 str1 等于 str2。

strncmp函数模拟实现

和strcmp类似,只不过循环次数要有n的限定。

函数声明

int my_strncmp(const char* str1, const char* str2,size_t n)

函数实现

int my_strncmp(const char* str1, const char* str2,size_t n)
{
    
    
	assert(str1 != NULL);
	assert(str2 != NULL);
	
	while (!(*(unsigned char*)str1 - *(unsigned char*)str2) && *str1 && --n)
		//只要str1和str2的字符相同并且str1没遇到'\0',就一直循环
		//这里只能用--n,而不能用n--,留给读者思考为什么?
	{
    
    
		
		str1++;
		str2++;
	}
	return *str1 - *str2;
}
int main()
{
    
    
	char arr1[10] = "abceA";
	char arr2[10] = "abcde";
	int ret = my_strncmp(arr1, arr2,3);
	if (ret < 0)
	{
    
    
		printf("str1<str2\n");
	}
	else if (ret>0)
	{
    
    
		printf("str1>str2\n");
	}
	else
	{
    
    
		printf("str1=str2\n");
	}
}

输出结果
在这里插入图片描述

strcpy函数介绍

描述

把 src 所指向的字符串复制到 dest。

需要注意的是如果目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况。

声明

下面是 strcpy() 函数的声明。

char *strcpy(char *dest, const char *src)

参数

  • dest – 指向用于存储复制内容的目标数组。
  • src – 要复制的字符串。

返回值

该函数返回一个指向最终的目标字符串 dest 的指针。

strcpy函数模拟实现

把源字符串逐个遍历到目标字符串即可。

函数声明

char *my_strcpy(char *dest, const char *src)

函数实现

char* my_strcpy(char *dest, const char *src)
{
    
    
	assert(dest != NULL);
	assert(src != NULL);//先断言,确保两个字符串地址不是空指针
	char*start = dest;
	while (*dest++ = *src++)
	{
    
    
		;
	}
	return start;
}
int main()
{
    
    
	char arr1[10] = "hellohe";
	char arr2[10] = "world";
	my_strcpy(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

输出结果:
在这里插入图片描述

strncpy函数介绍

描述

把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。

声明

下面是 strncpy() 函数的声明。

char *strncpy(char *dest, const char *src, size_t n)

参数

  • dest – 指向用于存储复制内容的目标数组。
  • src – 要复制的字符串。
  • n – 要从源中复制的字符数。

返回值

该函数返回最终复制的字符串。

strncpy函数模拟实现

函数声明

char *my_strncpy(char *dest, const char *src, size_t n)

函数实现

char* my_strncpy(char *dest, const char *src,size_t n)
{
    
    
	assert(dest != NULL);
	assert(src != NULL);//先断言,确保两个字符串地址不是空指针
	char*start = dest;
	while (n--)
	{
    
    
		*dest++ = *src++;
	}
	return start;
}
int main()
{
    
    
	char arr1[10] = "hellohe";
	char arr2[10] = "world";
	my_strncpy(arr1, arr2,5);
	printf("%s\n", arr1);
	return 0;
}

输出结果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42907822/article/details/114922361
今日推荐