【C字符串函数】——对C语言中有关字符串库函数的实现及模拟

news/2024/5/17 17:28:05 标签: c语言, c++, 后端, gitee

在这里插入图片描述

关于C语言的知识放在专栏:C
小菜坤日常上传gitee代码:https://gitee.com/qi-dunyan
❤❤❤
个人简介:双一流非科班的一名小白,期待与各位大佬一起努力!
推荐网站:cplusplus.com

目录

  • 字符串函数
    • 前言
      • 1.0 strlen的实现及模拟(求字符串长度)
      • 1.1 strcmp的实现及模拟 (字符串比较)
        • strncmp的实现及模拟
      • 1.2 strcpy的实现及模拟(字符串拷贝)
        • strncpy的使用及模拟实现
      • 1.3 strcat的实现及模拟(字符串追加)
        • strncat的使用及模拟实现
      • 1.4 strstr的实现及模拟(字符串查找)
      • 1.5 strtok函数(在字符串中定义用作分隔符的集合)
      • 1.6 strerror函数 (错误码转换错误信息)

字符串函数

前言

我们已经了解了C语言中很多数据类型,比如int(整数类型)、char(字符类型)、以及浮点型的double(双精度)、float(单精度),但是有一点就是我们发现这里并没有提到我们常见的有关字符串的类型。其实在C语言中,字符串通常是放在 常量字符串 中或者 字符数组 中的。(常量字符串是不可被修改的)

1.0 strlen的实现及模拟(求字符串长度)

字符串是双引号" "引起来的,以 ‘\0’ 作为结束标志,strlen是专门用来求字符串长度的,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。并且返回值必须是正数,因为字符个数不存在负数情况!

在这里插入图片描述

使用以及模拟实现

#include<stdio.h>//printf头文件
#include<string.h>//strlen头文件
#include<assert.h>//assert头文件

//返回值为无符号类型(正数)
//模拟实现,这里尽量做到还原原函数的形式
size_t my_strlen(const char* str)
{
	assert(str);//断言,如果str是NULL,编译器报错
	const char* start = str;//首字符地址赋给start以及end
	const char* end = str;
	while (*end != '\0')//当end指向'\0'时结束
	{
		end++;
	}
	return end - start;//指针相减得到两者之间元素个数
}
int main()
{
	char arr[] = "abcdef";
	printf("%d\n", strlen(arr));//arr是数组名,表示数组首元素地址,即a的地址,返回值为\0之前的字符个数,即6
	int len=my_strlen(arr);
	printf("%d\n", len);//6
	return 0;
}

这里我是采用指针-指针=两指针之间元素个数的方式,还有很多方式都可以模拟实现,比如创建一个变量计数的方式等,如下:

size_t my_strlen(const char * str)
{
 assert(str);//断言
 size_t count = 0;//无符号
 while(*str)
 {
  count++;//指针从起始位置开始往前走,每走一次count++一次
  str++;
 }
 return count;//最后返回count
}

1.1 strcmp的实现及模拟 (字符串比较)

strcmp是用来比较两个字符串的。两个字符串比较的其实是各字符所对应的ASCII码值,如下:

在这里插入图片描述

使用以及模拟实现

#include<string.h>//strcpy头文件包含
#include<stdio.h>//printf头文件包含
#include<assert.h>//断言
int my_strcmp(const char* s1, const char* s2)
{
	assert(s1 && s2);//断言
	while (*s1 == *s2)//如果两个字符串中对应的字符相等,则继续往后找
	{
		if (*s1 == '\0')//当s1到\0时,说明s2也是\0,字符串直到结束,两者都相等
			return 0;//返回0
		//如果没到\0,继续往后走,进行下一个字符比较	
		s1++;
		s2++;
	}
	//当跳出循环时,说明s1与s2指向的字符不相等,直接返回两者之差即可
	return *s1 - *s2;
	//*s1 -*s2>0  即 *s1>*s2,即字符数组arr1中的字符串>arr2中的
	              //反之则小于
}

int main()
{
    //字符串存放在字符数组
	char arr1[] = "abcdeaf";
	char arr2[] = "abcdef";
	//模拟实现
	int len=my_strcmp(arr1, arr2);
    //strcmp两个参数,arr1,arr2数组名,即首元素地址,即字符串首字符地址
	printf("%d\n", strcmp(arr1, arr2));//-5
	printf("%d\n", len);//-5         a对应ASCII:97  f:102
	                                  //   97-102 ==-5
	return 0;
}

strncmp的实现及模拟

strncmp与strcmp很类似,也是用来比较两个字符串的,唯一的区别就是strcmp是比较整个字符串,而strncmp可以指定比较的第多少个字符,比如说比较abcdef与abcdfg两个字符串的前三个字符,结果返回值就是0。因为仅仅比较的是前三个字符,即abc。
在这里插入图片描述
模拟实现

#include<string.h>
#include<stdio.h>
#include<assert.h>
int my_strncmp(const char* str1, const char* str2, size_t num)
{
	assert(str1 && str2);//断言
	//比较前num个字符,两者相等时,进入循环,继续往后比,num限制比较字符数
	while (--num && (*str1) && (*str1 == *str2))
	{
		str1++;
		str2++;
	}
	//跳出循环,说明num比完了,或者有一方遇到\0,或者两字符不相等
	//直接返回两者之差
	return *str1 - *str2;
}

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "abcbefgg";
	int num = 0;
	scanf("%d", &num);
	//比较字符串arr1与arr2的前num个字符
	int len=my_strncmp(arr1, arr2,num);

	//printf("%d\n", strncmp(arr1, arr2,3));//0
	printf("%d\n", len);// num=3,len=0;num=4,len>0
	return 0;
}

1.2 strcpy的实现及模拟(字符串拷贝)

strcpy是用来拷贝字符串的
在这里插入图片描述
注意事项

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

使用及模拟实现

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

char* my_strcpy(char*dest,char*src)
{
	//断言
	assert(dest && src);
	char* ret = dest;//用来记住arr的起始地址
	while (*dest++ = *src++)//不断地赋值,arr不断地被覆盖
	{
		;
	}
	//返回起始地址
	return ret;
}

int main()
{
	char arr[20] = "hello";
	char* p = "abcdef";
	//strcpy(arr, p);
	//模拟实现
	my_strcpy(arr, p);
	printf("%s", arr);//abcdef
	return 0;
}

strncpy的使用及模拟实现

strncpy与strcpy的使用相类似,但是strcpy是拷贝整个字符串,而strncpy是可以指定拷贝,即只拷贝num个字符,如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
在这里插入图片描述

使用及模拟实现

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

char* my_strncpy(char* dest, const char* sor, size_t num)
{
	//断言
	assert(dest && sor);
	char* s = dest;//起始地址记住
	int i = 0;
	for (i = 0; i < (int)num; i++)
	{
		//开始拷贝,num次,每次拷贝一个字符,拷贝完后,两指针往后走,继续拷贝
		*dest++ = *sor++;
	}
	//返回起始地址
	return s;
}
int main()
{
	char arr1[20] = "abcdefghi";
	char arr2[20] = "xxxx";
	size_t n = 0;
	scanf("%d", &n);
	my_strncpy(arr1, arr2, n);
	//从arr2中拷贝n个字符到arr1去
	printf("%s", arr1);//n=4,xxxxefghi\0 ; n=5,xxxx\0fghi\0,但是打印的是xxxx,因为遇到\0字符串停止
	return 0;
}

1.3 strcat的实现及模拟(字符串追加)

strcat是字符串追加函数,顾名思义就是在一个字符串后面再增加另外一个字符串。
注意事项
源字符串必须以 ‘\0’ 结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
不能自己给自己追加

在这里插入图片描述
实现及模拟

#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
	//断言
	assert(dest && src);
	char* sur = dest;//记住起始地址
	while (*sur != '\0')
	{
		sur++;
	}
	//走到这里,sur已经指向了arr1的\0处,从这里开始,把src指向的字符即arr2的字符赋给sur
	while (*sur++ = *src++)
	{
		;
	}
	//最后返回arr1追加后的起始空间地址
	return dest;
}

int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "world";
	//在arr1后面增加arr2
	//strcat(arr1, arr2);
	my_strcat(arr1, arr2);

	printf("%s\n", arr1);//hello world
	return 0;
}

strncat的使用及模拟实现

strncat与strcat很类似,只不过strcat是追加整个字符串,而strncat是追加指定的字符串,比如说可以给arr1追加4个字符
在这里插入图片描述

模拟实现及使用

#include<stdio.h>
#include<assert.h>
char* my_strncat(char* dest, const char* sor, size_t num)
{
	assert(dest && sor);
	char* p = dest;
	while (*p != '\0')
	{
		p++;
	}
	//此时已经指向arr1中的\0
	//把num个字符赋给*p
	while (num--)
	{
		*p++ = *sor++;
	}
	return dest;
}
int main()
{
	char arr1[20] = "hello ";
	char arr2[20] = "world!!!!!";
	size_t n = 0;
	scanf("%d", &n);
	my_strncat(arr1, arr2, n);
	printf("%s", arr1);//n=5,hello world
	return 0;
}

1.4 strstr的实现及模拟(字符串查找)

strstr是实现字符串查找的一个函数,即在一个字符串中查找该字符串是不是含有另一个字符串
在这里插入图片描述
使用及模拟

#include<stdio.h>
#include<string.h>
#include<assert.h>
//char* strstr(const char*str1,const char*str2)
char* my_strstr(const char* str1, const char* str2)
{
	assert(str1 && str2);
	const char* s1 = str1;
	const char* s2 = str2;
	const char* p = str1;
	while (*p)
	{
		s1 = p;
		s2 = str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
			return (char*)p;
		p++;
	}

	return NULL;
}

int main()
{
	char arr1[] = "abbbcdef";
	char arr2[] = "bbpc";
	//char* p = strstr(arr1, arr2);
	char* p = my_strstr(arr1, arr2);
	if (p == NULL)
		printf("不存在");
	else
		printf("%s\n", p);//不包含,输出结果为不存在
	return 0;
}

1.5 strtok函数(在字符串中定义用作分隔符的集合)

在这里插入图片描述

注意事项
1、strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。

2、strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。

3、strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。

4、如果字符串中不存在更多的标记,则返回 NULL 指针。

举例使用

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

int main()
{
	char arr[] = "zinuo@qq.com.qdy";
	char buf[200] = { 0 };
	//p是用作分隔符的字符串首字符地址
	const char* p = "@..";
	//由于strtok函数会改变原字符串的内容,所以一般都会拷贝一个用来使用
	strcpy(buf, arr);
	char* str = NULL;
	for (str=strtok(buf,p); str != NULL; str=strtok(NULL,p) )
	{
		//用来做分隔符的字符都被改成了\0,下一次调用函数时,会从这个\0开始继续往后查找分隔符,再次改为\0,一直到找完所有分隔符,返回NULL
		printf("%s\n", str);//zinuo
		                    //qq
			                //com
			               //qdy
	}
	return 0;
}

1.6 strerror函数 (错误码转换错误信息)

#include<stdio.h>
#include<errno.h>//errno包含头文件
#include<string.h>//strerror包含头文件
int main()
{
	//打开文件操作
	FILE* pf = fopen("test.txt", "r");
	//打开文件失败,返回空指针,strerror可以将错误码转换成让我们看得懂的错误信息
	if (pf == NULL)
	{
		perror("lzn");//相当于printf+strerror  
		//lzn: No such file or directory

		//没有这个文件,错误码转换为错误信息打印出来
		printf("%s\n", strerror(errno));
		//No such file or directory
		return 1;
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

end
生活原本沉闷,但跑起来就会有风!


http://www.niftyadmin.cn/n/3650.html

相关文章

2.Tornado的优势

1.Tornado是一整套的异步编码方案 不仅仅是一整套Web框架&#xff0c;还包含了一整套http协议、websocket协议的库、还有异步库。我们就展开聊聊 2.Tornado不只是Web框架&#xff0c;还是Web服务器 Tornado可以开发Web应用&#xff0c;还可以通过Tornado部署其他的Web应用&a…

工作多年,技术认知不足,个人成长慢,职业发展迷茫,该怎么办?

随着技术的发展&#xff0c;整个行业对测试的要求越来越高。测试开发技术日新月异&#xff0c;随之而来的对测试开发工程师也有了更多的挑战&#xff0c;尤其是在这样的特殊时期&#xff0c;企业降本增效&#xff0c;招聘要求不断加码。 前几天和学员聊天&#xff0c;有同学反…

图的基本介绍

图的定义 1.基本概念 在图中&#xff0c;顶点之间的关系可以是任意的&#xff0c;任意两个元素之间都可能相关顶点的前驱和后继个数无限制 2.定义 图是一种&#xff1a;数据元素间存在多对多关系的数据结构加上一组基本操作构成的抽象数据类型可以表示为&#xff1a;G&…

【电脑使用】iPad or Android快速访问Windows文件

前言 最近突然想实现iPad快速访问电脑上的文件&#xff0c;在网上找了不少教程&#xff0c;最后发现最为简单的竟然还是使用python。 之前写过的一篇博客&#xff0c;是关于两台电脑之间实现文件无线互传的。 参考链接&#xff0c;想尝试的可以试试 三种方法打破电脑-ipad文件…

【FPGA】FPGA实现UART串口通信回环

目录一、UART协议基础二、系统模块划分三、代码实现1、uart顶层设计模块2、uart_rx串口数据接收模块3、control控制模块4、uart_tx串口数据发送模块四、仿真五、上板验证六、踩坑事项一、UART协议基础 关于UART协议的基础理论部分已经在上一篇文章中讲述&#xff0c;不再重复介…

cf #832 Div.2(A-D)

Cf #832 Div.2 文章目录Cf #832 Div.2[A. Two Groups](https://codeforces.com/contest/1747/problem/A)[B. BAN BAN](https://codeforces.com/contest/1747/problem/B)[C. Swap Game](https://codeforces.com/contest/1747/problem/C)[D. Yet Another Problem](https://codefo…

计算机毕业设计(附源码)python职工社保信息管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;我…

system V共享内存

文章目录共享内存的原理共享内存函数简单使用命令行查看共享内存与删除共享内存的原理 共享内存让不同进程看到同一份资源的方式就是&#xff0c;在物理内存当中申请一块内存空间&#xff0c;然后将这块内存空间分别与各个进程各自的页表之间建立映射&#xff0c;再在虚拟地址…