C语言--字符串函数1

news2024/11/26 17:51:51

目录

  • 前言
  • strlen
    • strlen的模拟实现
  • strcpy
  • strcat
    • strcat的模拟实现
  • strcmp
    • strcmp的模拟实现
  • strncpy
  • strncat
  • strncmp
  • strstr
  • strchr和strrchr
    • strstr的模拟实现

前言

本章我们将重点介绍处理字符和字符串的库函数的使用和注意事项。

strlen

我们先来看一个我们最熟悉的求字符串长度的库函数–strlen

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

int main()
{
	int len = strlen("abcdef");
	printf("%d", len);

	return 0;
}

运行结果如图1
图1
这里有几点是值得我们注意的:

  1. 字符串已 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数不包含 ‘\0’ ).
  2. 参数指向的字符串必须要以‘\0’结束。
  3. 注意函数的返回值是size_t,是无符号的

strlen的模拟实现

模拟实现strlen的方法有很多种,例如计数器方法,递归方法,指针减去指针的方法,我们以指针减指针为例。

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

int my_strlen(const char* str)
{
	int count = 0;
	assert(str);
	while (*str != '\0')
	{
		count++;
		str++;
	}

	return count;
}

int main()
{
	char arr[100] = "abcdef";
	int ret = my_strlen(arr);
	printf("%d", ret);
	return 0;
}

strcpy

库函数strcpy在之前的博客中有十分详细的讲解,这里就不做过多赘述了
模拟实现库函数–strcpy

这里我们只需要注意以下几点即可

  1. 源字符串必须以 ‘\0’ 结束。

  2. 目标空间必须足够大,以确保能存放源字符串.
    如图2就是错误示范
    图2

  3. 目标空间必须可变
    如图3就是错误示范
    图3

strcat

stract函数的作用是将一段字符串追加到另一端字符串的末尾。
代码实现如下

int main()
{
	char arr1[20] = "Hello ";
	char arr2[20] = "World";
	strcat_s(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

其中arr1是被追加对象,而arr2是追加对象。运行结果如图4
图4
我们知道在Hello 的末尾有一个\0,那么在arr2追加的时候有没有将这个\0给覆盖掉呢,我们主动添加一个\0来看效果。

int main()
{
	char arr1[20] = "Hello \0********";
	char arr2[20] = "World";
	strcat_s(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

我们调试一下观察变化,如图5,6
图5
图6

我们发现\0是被覆盖掉了的。所以在追加的时候是从\0开始的。
我们在使用这个函数的时候要注意以下几点

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

strcat的模拟实现

我们先来看代码

char* my_strcat(char* dest, const char* src)
{
	assert(dest && src);
	//将最初的arr1的首元素地址保存起来
	char* ret = dest;
	//找目标空间中的\0
	while (*dest != '\0')
	{
		dest++;

	}
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[20] = "Hello ";
	char arr2[20] = "World";
	my_strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}

我们通过画图来分析一下:
图5

strcat可以自己给自己追加吗?
这需要用到后面优化过后的strncat函数,strcat函数本身是不适合自己追加自己的,这是因为每当覆盖过后,\0会消失,*dest找不到\0了,于是会继续往下找,这样就会陷入一个死循环当中。
图6

strcmp

相信strcmp的作用读者应该也是再熟悉不过了,它的作用就是比较两个字符串大小
举两个简单的例子

arr1 = "abcdef";
arr2 = "bbd";
strcmp(arr1,arr2);
a大于b所以返回一个大于0的数
arr1 = "abcdef";
arr2 = "abad";
strcmp(arr1,arr2)
从第一个元素开始依次比较,前两个元素都相等,到第三个是,由于a的ascll码值比b大,所以arr2大于arr1,返回一个小于0的数

为什么返回的值是大于小于零的数呢?因为标准规定:

  1. 第一个字符串大于第二个字符串,则返回大于0的数字
  2. 第一个字符串等于第二个字符串,则返回0
  3. 第一个字符串小于第二个字符串,则返回小于0的数字

由此可见,strcmp的返回值必须要用有符号类型接收

strcmp的模拟实现

先来看代码

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

}
int main()
{
	char arr1[20] = "abcdef";
	char arr2[20] = "adq";
	int ret = my_strcmp(arr1, arr2);
	printf("%d", ret);
	return 0;
}

以上面代码为例,比较结果如图7
图7
所以arr2是小于arr1的。

前面我们介绍的库函数都是长度不受限制的函数,是不安全的,所以在c语言中还引入了一系列长度受到限制了的字符串函数,下面我们继续来介绍长度受限制的字符串函数。

strncpy

strncpy在传递参数的时候就要比strcpy函数多传递一个数参数,意思是只拷贝这么多个参数。

int main()
{
	char arr1[] = "abcdef";
	char arr2[5] = "xxx";
	strncpy(arr2, arr1, 3);
	printf("%s", arr2);

	return 0;
}

代码运行结果如图8
图8
这样相对来讲就会更安全一些。

strncat

有了刚刚strncpy对于对于参数的理解,这个函数理解也大同小异

int main()
{
	char arr1[20] = "hello ";
	char arr2[] = "abcdef";
	strncat_s(arr1, arr2, 3);
	printf("%s", arr1);
	return 0;
}

追加的结果如图9
图9
通过这个函数,我们就能实现字符串自己对自己追加的效果,因为多了一个长度的限制,所以可以避免死循环导致程序崩溃的情况。

strncmp

在strncmp中的个数代表的是要比较几个元素,看下面这段代码

int main()
{
	char arr1[20] = "abcdef ";
	char arr2[] = "abcqqq";
	int ret = strncmp(arr1, arr2, 3);
	printf("%d", ret);
	return 0;
}

由于只比较了三个元素,所以比较的结果应该是相等的,返回值应该为0,运行结果如图10
图10

strstr

这个函数的作用是在str1中找str2出现第一次的位置。找到了就返回首次出现的地址。没找到就返回空指针
先来看代码

int main()
{
	char arr1[] = "abcdef";
	char arr2[] = "bcd";
	char* p = strstr(arr1, arr2);
	if (p == NULL)
	{
		printf("找不到");

	}
	else
	{
		printf("%s", p);
	}

	return 0;
}

strchr和strrchr

strchr和strstr的效果很类似,是在str1中找一个字符首次出现的位置,而strrchr是找这个字符在str1中最后一次出现的位置

对这两个函数分别举一个例子:

int main()
{
	char arr1[] = "abcdef";
	char a = 'b';
	char* p = strchr(arr1, a);
	if (p == NULL)
	{
		printf("找不到");

	}
	else
	{
		printf("%s", p);
	}

	return 0;
}

打印结果如图11
图11

int main()
{
	char arr1[] = "abcdebf";
	char a = 'b';
	char* p = strrchr(arr1, a);
	if (p == NULL)
	{
		printf("找不到");

	}
	else
	{
		printf("%s", p);
	}

	return 0;
}

打印结果如图12
图12

strstr的模拟实现

代码如下

char* my_strstr(const char* str1, const char* str2)
{
	char* s1 = NULL;
	char* s2 = NULL;
	char* cp = (char*)str1;

	while (*cp)
	{
		s1 = cp;
		s1 = (char*)str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}

		if (*s2 == '\0')
		{
			return cp;
		}
		cp++;
	}
	return NULL;
}

int main()
{
	char arr1[] = "abcdebf";
	char arr2[] = "cde";
	char* p = my_strstr(arr1, arr2);
	if (p == NULL)
	{
		printf("找不到");

	}
	else
	{
		printf("%s", p);
	}

	return 0;
	
}

我们通过图解来分析,如图13
图13

以上就是本章全部内容,如有出入,欢迎大佬们指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/402954.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Echart多场景示例应用】Echarts柱状图、折线图、饼图、雷达图等完整示例。 echarts主标题和副标题的位置、样式等设置(已解决附源码)

**【写在前面】**前端时间做一个echarts的页面调整&#xff0c;临时客户要求加一个参数&#xff08;总容量&#xff09;显示&#xff0c;当时我就想用个默认的副标题吧&#xff0c;哪知客户和我说得紧跟在主标题后面&#xff0c;于是乎我就根据设置做了一个调整&#xff0c;我也…

燕山大学-面向对象程序设计实验 - 实验1 C++基础

CSDN的各位uu们你们好,今天千泽燕山大学-面向对象程序设计实验 - 实验1 C基础 相关内容, 接下来让我们一起进入c的神奇小世界吧,相信看完你也能写出自己的实验报告!实验一 C基础 1.1 实验目的 1&#xff0e;了解并熟悉开发环境&#xff0c;学会调试程序&#xff1b; 2&#xf…

超过10000人学习的Fiddler抓包教程,只需一小时就可以精通!

如果还是有朋友不太明白的话&#xff0c;可以看看这套视频&#xff0c;有实战讲解 零基础玩转Fiddler抓包在测试领域应用实战&#xff01;一、Fiddler与其他抓包工具的区别 1、Firebug虽然可以抓包&#xff0c;但是对于分析http请求的详细信息&#xff0c;不够强大。模拟http请…

【Linux】信号的产生、保存、捕捉处理 (四种信号产生、核心存储、用户态与内核态、信号集及其操作函数)

文章目录1、什么是信号&#xff1f;2、信号的产生2.1 通过键盘产生信号2.2 通过系统调用产生信号2.3 硬件异常产生的信号2.4 由软件条件产生的信号2.5 进程的核心转储3、信号的保存4、信号的捕捉4.1 用户态和内核态4.2 用户态到内核态的切换4.3 信号捕捉过程5、信号集操作函数以…

Spring——Spring整合Mybatis(XML和注解两种方式)

框架整合spring的目的:把该框架常用的工具对象交给spring管理&#xff0c;要用时从IOC容器中取mybatis对象。 在spring中应该管理的对象是sqlsessionfactory对象&#xff0c;工厂只允许被创建一次&#xff0c;所以需要创建一个工具类&#xff0c;把创建工厂的代码放在里面&…

Qt不会操作?Qt原理不知道? | Qt详细讲解

文章目录Qt界面开发必备知识UI界面与控件类型介绍Qt设计器原理控件类型的介绍信号与槽机制处理常用控件创建与设置常见展示型控件创建与设置常见动作型控件创建与设置常见输入型控件创建与设置常见列表控件创建于设置Qt中对象树的介绍项目源码结构刨析.pro.hmain.cpp.cppQt界面…

JVM的几种GC

GC JVM在进行GC时&#xff0c;并不是对这三个区域统一回收。大部分时候&#xff0c;回收都是新生代~ 新生代GC&#xff08;minor GC&#xff09;&#xff1a; 指发生在新生代的垃圾回收动作&#xff0c;因为Java对象大多都具备朝生夕灭的特点&#xff0c;所以minor GC发生得非…

【问题排查】Linux虚拟机无法识别串口与ttyUSB

虚拟机串口连接失败问题 小哥的Linux系统是用虚拟机来装的&#xff0c;最近恰好需要用到串口和Linux进行通信&#xff0c;连接好硬件之后&#xff0c;发现虚拟机上找不到串口。 经查询才发现通过虚拟机启动的系统&#xff0c;正常情况下是无法使用串口进行通信的&#xff0c;需…

Ast2500增加用户自定义功能

备注&#xff1a;这里使用的AMI的开发环境MegaRAC进行AST2500软件开发&#xff0c;并非openlinux版本。1、添加上电后自动执行的任务在PDKAccess.c中列出了系统启动过程中的所有任务&#xff0c;若需要添加功能&#xff0c;在相应的任务中添加自定义线程。一般在两个任务里面添…

隐私计算将改变金融行业的游戏规则?

开放隐私计算 01背景2月底&#xff0c;相关部门印发《数字中国建设整体布局规划》提出&#xff0c;到2025年&#xff0c;基本形成横向打通、纵向贯通、协调有力的一体化推进格局&#xff0c;数字中国建设取得重要进展&#xff1b;到2035年&#xff0c;数字化发展水平进入世界前…

前端安全(自留)

目录XSS——跨站脚本常见解决CSRF ——跨站请求伪造常见解决XSS——跨站脚本 当目标站点在渲染html的过程中&#xff0c;遇到陌生的脚本指令执行。 攻击者通过在网站注入恶意脚本&#xff0c;使之在用户的浏览器上运行&#xff0c;从而盗取用户的信息如 cookie 等。 常见 解…

机械学习 - scikit-learn - 数据预处理 - 2

目录关于 scikit-learn 实现规范化的方法详解一、fit_transform 方法1. 最大最小归一化手动化与自动化代码对比演示 1&#xff1a;2. 均值归一化手动化代码演示&#xff1a;3. 小数定标归一化手动化代码演示&#xff1a;4. 零-均值标准化(均值移除)手动与自动化代码演示&#x…

优秀开源软件的类,都是怎么命名的?

日常编码中&#xff0c;代码的命名是个大的学问。能快速的看懂开源软件的代码结构和意图&#xff0c;也是一项必备的能力。 Java项目的代码结构&#xff0c;能够体现它的设计理念。Java采用长命名的方式来规范类的命名&#xff0c;能够自己表达它的主要意图。配合高级的 IDEA&…

什么是谐波

什么是谐波 目录 1. 问题的提出 2. “谐”字在中英文中的原意 2.1 “谐”字在汉语中的原义 2.2 “谐”字对应的英语词的原义 3.“harmonics(谐波)”概念是谁引入物理学中的&#xff1f; 4.“harmonics(谐波)”的数学解释 1. 问题的提出 “谐波”这个术语用于各种学科&am…

国外SEO升级攻略!一看就懂!

SEO是搜索引擎优化的缩写&#xff0c;它是指通过优化网站内容和结构&#xff0c;提升网站在搜索引擎中的排名&#xff0c;从而获得更多的有价值的流量。 而关键词研究和选择是SEO优化中最基础也是最关键的环节&#xff0c;它决定了网站将面向哪些用户、哪些关键词和词组将被优…

SWF (Simple Workflow Service)简介

Amazon Simple Workflow Service (Amazon SWF) 提供了给应用程序异步、分布式处理的流程工具。 SWF可以用在媒体处理、网站应用程序后端、商业流程、数据分析和一系列定义好的任务上。 举个例子&#xff0c;下图表明了一个电商网站的工作流程&#xff0c;其中涉及了程序执行的…

C#【汇总篇】语法糖汇总

文章目录0、语法糖简介1、自动属性2、参数默认值和命名参数3、类型实例化4、集合4.1 初始化List集合的值4.2 取List中的值5、隐式类型&#xff08;var&#xff09;6、扩展方法【更换测试实例】7、匿名类型&#xff08;Anonymous type&#xff09;【待补充】8、匿名方法&#xf…

使用 Microsoft Dataverse 简化的连接快速入门

重复昨天本地部署dynamics实例将其所有的包删除之后&#xff0c;再次重新下载回来。运行填写跟之前登陆插件一样的信息点击login 然后查看控制台&#xff0c;出现这样就说明第一个小示例就完成了。查看你的dy365平台下的 “我的活动”就可以看到刚刚通过后台代码创建的东西了。…

MyBatis学习笔记(十三) —— 分页插件

13、分页插件 SQL语句中添加 limit index,pageSize pageSize: 每页显示的条数 pageNum: 当前页的页码 index: 当前页的起始索引, index (pageNum 1) * pageSize count: 总记录数 totalPage: 总页数 totalPagecount/pageSize; if(count % pageSize !0 ){ totalPage 1; } page…

java多线程(二六)ReentrantReadWriteLock读写锁详解(2)

3、读写状态的设计 同步状态在重入锁的实现中是表示被同一个线程重复获取的次数&#xff0c;即一个整形变量来维护&#xff0c;但是之前的那个表示仅仅表示是否锁定&#xff0c;而不用区分是读锁还是写锁。而读写锁需要在同步状态&#xff08;一个整形变量&#xff09;上维护多…