C语言之字符串,内存操作函数详解(一)

news2025/1/17 23:12:36

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:C语言学习分享⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习更多C语言知识
  🔝🔝


在这里插入图片描述


字符串函数

  • 1. 前言🚩
  • 2. strlen函数🚩
    • 2.1 strlen函数的自我实现🏁
  • 3. strcpy函数🚩
    • 3.1 strcpy函数的自我实现🏁
  • 4. strcat函数🚩
    • 4.1 strcat函数的自我实现🏁
    • 4.2 函数的返回值🏁
  • 5. strcmp函数🚩
    • 5.1 strcmp函数的自我实现🏁
  • 6. 长度受限的字符串函数🚩
    • 6.1 strncpy函数的注意事项🏁
    • 6.2 strncat函数和strncmp的注意事项🏁
  • 7. 字符串查找基础🚩
    • 7.1 查找一个字符🏁
    • 7.2 查找任意几个字符🏁
    • 7.3 查找一个字串🏁
  • 8. 总结🚩


1. 前言🚩

C语言的标准库为我们提供了丰富的字符串操作函数与内存操作函数,有我们熟悉的 strlen ,strcpy ,也有我们不熟悉的 strchr , strstr 等.这里我们将一一为大家讲解.初阶的字符串函数我们会讨论自我实现,后面的高阶函数我们只给大家做介绍,希望我的文章能够帮到你.

我们这里学习字符串函数和内存操作函数都在cplusplus上查看定义Cplusplus网站


2. strlen函数🚩

先来看定义:

在这里插入图片描述
这个函数很明了,就是求字符串长度的函数,并且字符串的结束标志: '\0’不算在内

注意strlen返回一个类型为size_t 的值。这个类型是在头文件stddef.h中定义的,它是一个无符号整数类型。在表达式中使用无符号数可能导致不可预料的结果。例如,下面两个表达式看上去是相等的:

char x[]="abcdef";
char y[]="xyz";
if(strlen(x)>=strlen(y))//式子1
{
	...
}
if(strlen(x)-strlen(y)>=0)//式子2
{
	...
}

式子2是不能用于判断字符串x和字符串y谁的长度大的,因为strlen函数的返回值是无符号整型,两个无符号整型的数相减的结果也一定是无符号整型,所以不管是字符串x长度小于字符串y还是大于字符串y,式子2都是恒为真!

如果把strlen的返回值强制类型转换为 int 就可以消除这个问题.


2.1 strlen函数的自我实现🏁

size_t my_strlen(const char* p)//加上const表示我们不应该修改这个字符串
{
	unsigned int count = 0;
	int i = 0;
	while (p[i] != '\0')
	{
		count++;
		i++;
	}
	return count;
}

因为这个函数比较容易理解,所以不做过多解释


3. strcpy函数🚩

它的原型如下:

在这里插入图片描述

这个函数把参数src字符串复制到dst参数。如果参数src和dst在内存中出现重叠,其结果是未定义的。由于dst参数将进行修改,所以它必须是个字符数组或者是一个指向动态分配内存的数组的指针,不能使用字符串常量。

目标参数的以前内容将被覆盖并丢失。即使新的字符串比dst原先的内存更短,由于新字符串是以NUL字节结尾,所以老字符串最后剩余的几个字符也会被有效地删除。

警告: 程序员必须保证目标字符数组的空间足以容纳需要复制的字符串。如果字符串比数组长,多余的字符仍被复制,它们将覆盖原先存储于数组后面的内存空间的值。strcpy无法解决这个问题,因为它无法判断目标字符数组的长度。


3.1 strcpy函数的自我实现🏁

char* my_strcpy(char *dst,const char *src)
{
	assert(dst != NULL);
	assert(src != NULL);
	char *ret = dst;
	while((* dst++ = * src++) != '\0') 
		;
	return ret;
}

这里需要注意的是,我们把src里面的内容拷贝到dst中,所以我们是不希望src的内容发生改变的,所以我们加上const,并且strcpy函数的返回值是目标字符串的起始位置的地址,所以这里我们用char*


4. strcat函数🚩

先看函数原型:

在这里插入图片描述

strcat函数要求dst参数原先已经包含了一个字符串(可以是空字符串)。它找到这个字符串的末尾,并把src字符串的一份拷贝添加到这个位置。如果src和dst的位置发生重叠,其结果是未定义的。

警告: 和前面一样,程序员必须保证目标字符数组剩余的空间足以保存整个源字符串。但这次并不是简单地把源字符串的长度和目标字符数组的长度进行比较,你必须考虑目标数组中原先存在的字符串。


4.1 strcat函数的自我实现🏁

char* my_strcat(char* dest, const char* src)
{
	char* begin = dest;
	//第一步、寻找目标字符串中的'\0'
	while (*dest)
	{
		dest++;
	}
	//第二步、追加源字符串并包含\0
	while (*dest++ = *src++)
	{
		;
	}
	return begin;
}

4.2 函数的返回值🏁

strcpy和strcat都返回它们第1个参数的一份拷贝,就是一个指向目标字符数组的指针。由于它们返回这种类型的值,所以你可以嵌套地调用这些函数,如下面的例子所示:

char dst = ...;
char a = ...;
char b = ...;
strcat(strcpy(dst,a),b);


5. strcmp函数🚩

先看函数原型:

在这里插入图片描述

比较两个字符串涉及对两个字符串对应的字符逐个进行比较,直到发现不匹配为止。那个最先不匹配的字符中较“小”(也就是说,在字符集中的序数较小)的那个字符所在的字符串被认为“小于”另外一个字符串。如果其中一个字符串是另外一个字符串的前面一部分,那么它也被认为“小于”另外一个字符串,因为它的NUL结尾字节出现得更早。这种比较被称为“词典比较”,对于只包含大写字母或只包含小写字母的字符串比较,这种比较过程所给出的结果总是和我们日常所用的字母顺序的比较相同。

int strcmp(char const* s1,char const* s2)

如果s1小于s2,strcmp函数返回一个小于零的值。如果s1大于s2,函数返回一个大于零的值。如果两个字符串相等,函数就返回零。

警告:

  • 注意标准并没有规定用于提示不相等的具体值。它只是说如果第1个字符串大于第2个字符串就返回一个大于零的值,如果第1个字符串小于第2个字符串就返回一个小于零的值。一个常见的错误是以为返回值是1和-1,分别代表大于和小于。但这个假设并不总是正确的。
  • 由于strcmp并不修改它的任何一个参数,所以不存在溢出字符数组的危险。但是,和其他不受限制的字符串函数一样,strcmp函数的字符串参数也必须以一个NUL字节结尾。如果并非如此,strcmp就可能对参数后面的字节进行比较,这个比较结果将不会有什么意义.

5.1 strcmp函数的自我实现🏁

int Strcmp(char* str1, char* str2)//strcmp函数具体实现。
{
    while ((*str1 != '\0') && (*str1 == *str2))//判断字符串是否结束。
    {
        str1++;
        str2++;//
    }
    return *str1 - *str2;
}

C语言并没有规定strcmp的返回值是-1或者1,只要是大于0,或者小于0,直接返回即可


6. 长度受限的字符串函数🚩

标准库还包含了一些函数,它们以一种不同的方式处理字符串。这些函数接受一个显式的长度参数,用于限定进行复制或比较的字符数。这些函数提供了一种方便的机制,可以防止难以预料的长字符串从它们的目标数组溢出。这些函数的原型如下:

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

很明显,在以上函数中加一个n就是限制长度的意思,strcpy加上n就是只能拷贝num个字符串,以此类推
如果源参数和目标参数的地址发生重叠,strncpy和strncat的结果都是未定义的(危险的)


6.1 strncpy函数的注意事项🏁

和strcpy一样,strncpy把源字符串的字符复制到目标数组。然而,它总是正好向dst写入len个字符。如果strlen( src )的值小于len,dst数组就用额外的NUL字节填充到len长度。如果strlen( src )的值大于或等于len,那么只有len个字符被复制到dst中。注意!它的结果将不会以NUL字节结尾

警告的总结:

  • strncpy调用的结果可能不是一个字符串,因此字符串必须以NUL字节结尾。如果在一个需要字符串的地方(例如strlen函数的参数)使用了一个不是以NUL字节结尾的字符序列,会发生什么情况呢?strlen函数将无法知道NUL字节是没有的,所以它将继续进行查找,一个字符接一个字符,直到它发现一个NUL字节为止。或许它找了几百个字符才找到,而strlen函数的这个返回值从本质上说是一个随机数。或者,如果函数试图访问系统分配给这个程序以外的内存范围,程序就会崩溃。
  • 这个问题只有当你使用strncpy函数创建字符串,然后或者对它们使用str开头的库函数,或者在printf中使用%s格式码打印它们时才会发生。在使用不受限制的函数之前,你首先必须确定字符串实际上是以NUL字节结尾的。

6.2 strncat函数和strncmp的注意事项🏁

  • 尽管strncat也是一个长度受限的函数,但它和strncpy存在不同之外。它从src中最多复制len个字符到目标数组的后面。但是,strncat总是在结果字符串后面添加一个NUL字节,而且它不会像strncpy那样对目标数组用NUL字节进行填充。注意目标数组中原先的字符串并没有算在strncat的长度中。strncat最多向目标数组复制len个字符(再加一个结尾的NUL字节),它才不管目标参数除去原先存在的字符串之后留下的空间够不够。
  • 最后,strncmp也用于比较两个字符串,但它最多比较len个字节。如果两个字符串在第len个字符之前存在不相等的字符,这个函数就像strcmp一样停止比较,返回结果。如果两个字符串的前len个字符相等,函数就返回零。


7. 字符串查找基础🚩

标准库中存在许多函数,它们用各种不同的方法查找字符串。这些各种各样的工具给了C程序员很大的灵活性!
下面我就给大家介绍几个字符串函数的用法:


7.1 查找一个字符🏁

在一个字符串中查找一个特定字符最容易的方法是使用 strchr和strrchr函数,它们的原型如下所示:

在这里插入图片描述


在这里插入图片描述

注意它们的第2个参数虽然是一个整型值。但是C语言中字符其实就是一个小整型,所以可以用整型来存储字符值。strchr在字符串str中查找字符ch第1次出现的位置,找到后函数返回一个指向该位置的指针。如果该字符并不存在于字符串中,函数就返回一个NULL指针。strrchr的功能和strchr基本一致,只是它所返回的是一个指向字符串中该字符最后一次出现的位置(最右边那个)。


7.2 查找任意几个字符🏁

strpbrk是个更为常见的函数。它并不是查找某个特定字符,而是查找任何一组字符第1次在字符串中出现的位置。它的原型如下:

在这里插入图片描述

这个函数返回一个指向str中第1个匹配group中任何一个字符的字符位置。如果未找到匹配,函数返回一个NULL指针。如果你不理解它的意思,我们这里写一段代码来理解一下:

#include <stdio.h>
#include <string.h>
int main()
{
    char str[] = "This is a sample string";
    char key[] = "aeiou";
    char* pch;
    printf("Vowels in '%s': ", str);
    printf("\n");
    pch = strpbrk(str, key);
    while (pch != NULL)
    {
        printf("%c ", *pch);
        pch = strpbrk(pch + 1, key);
        printf("\n");
    }
    printf("\n");
    return 0;
}

这里字符串str中出现的字符串key中的第一个字符是 “This” 中的 ‘i’ ,第二个字符是 “is” 里面的 ‘i’ .第三次出现的是字符 ‘a’,以此类推,那么我们设计的代码会将key字符串中在str字符串出现过的字符按顺序打印,注意这里不是先找key字符串中的第一个字符 ‘a’,而是从str字符串中找 key字符串中能匹配的所有字符的第一个那么代码会打印出:

在这里插入图片描述


7.3 查找一个字串🏁

为了在字符串中查找一个字串,我们可以使用strstr函数,它的原型如下:

在这里插入图片描述

这个函数在s1中查找整个s2第1次出现的起始位置,并返回一个指向该位置的指针。如果s2并没有完整地出现在s1的任何地方,函数将返回一个NULL指针。如果第2个参数是一个空字符串,函数就返回s1。

标准库中并不存在strrstr或strrpbrk函数。不过,如果你需要它们,它们是很容易实现的。下面的程序显示了一种实现strrstr的方法。这个技巧同样也可以用于实现strrpbrk。


// 在字符串s1中查找字符串s2最右出现的位置,并返回一个指向该位置的指针。
#include <string.h>

char*
my_strrstr( char const *s1, char const *s2 )
{
    register char*last;
    register char*current;    
     //把指针初始化为我们已经找到的前一次匹配位置。    
    last = NULL;
    //只在第2个字符串不为空时才进行查找,如果S2为空,返回NULL。    
    if( *s2 != '\0' ){      
      // 查找s2在s1中第1次出现的位置。
      current = strstr( s1, s2 );
    // 我们每次找到字符串时,让指针指向它的起始位置。然后查找该字符串下一个匹配位置。
    
          while( current != NULL ){
            last = current;
            current = strstr( last + 1, s2 );
          }
      }
      //返回指向我们找到的最后一次匹配的起始位置的指针。
      return last;
}

8. 总结🚩

字符串操作函数和内存操作函数的内容十分多且冗杂,我们把高阶字符串查找和字符查找,内存操作函数放在下一章来讲解,希望我的内容能帮助到你

🔎 下期预告: 高阶字符串函数与内存操作函数 🔍
\

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

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

相关文章

电池管理系统 (BMS)

现今的电子设备&#xff0c;小至TWS耳机和可穿戴设备&#xff0c;大至电动汽车&#xff0c;都离不开锂离子或聚合物电池的供电。依据电子设备所需电力的大小&#xff0c;电池组可能由多个电池单元(电芯)排列而成。电池组的充电和放电、输入/输出电压和电流等状态都需要精密监控…

2023年6月DAMA-CDGP数据治理专家认证,你考了吗?

DAMA认证为数据管理专业人士提供职业目标晋升规划&#xff0c;彰显了职业发展里程碑及发展阶梯定义&#xff0c;帮助数据管理从业人士获得企业数字化转型战略下的必备职业能力&#xff0c;促进开展工作实践应用及实际问题解决&#xff0c;形成企业所需的新数字经济下的核心职业…

小白系统地学习it技术--python的心得体会

我对我所学习的IT技术的理解 一、it技术介绍——python二、我学习python前的准备工作三、学习时的具体操作1. 在pycharm练习python&#xff0c;唯手熟尔&#xff01;&#xff01;2. 在bilibili看python学习视频3. 报错了&#xff0c;CSDN是你的不二选择&#xff01;4.找代码&am…

【开发日志】2023.05 ZENO----PrimitiveCurvature----曲率分析工具(几何体、图像、点云)

Screen Space Ambient Occlusion - TDA362/DIT223 - Computer Graphics Labs (chalmers.se)https://www.cse.chalmers.se/edu/course/TDA362/tutorials/ssao.html GAMES102在线课程-刘利刚 (ustc.edu.cn)http://staff.ustc.edu.cn/~lgliu/Courses/GAMES102_2020/default.html …

我给自己搭建的前端导航网站,你们都别用

欢迎关注我&#x1f970;&#x1f970;&#x1f970; 主页传送门&#xff0c;持续产出有思考的文档&#xff5e; &#x1f4a5; 想法来源 前段时间在工作的时候&#xff0c;因为遇到了一些之前没了解过的知识&#xff0c;所以化身百度cv工程师&#xff0c;上网冲浪寻找灵感&am…

第六十一天学习记录:C语言进阶:C语言预处理1

程序的翻译环境和执行环境 在ANSI C的任何一种实现中&#xff0c;存在两个不同的环境。 第一种是翻译环境&#xff0c;在这个环境中源代码被转换为可执行的机器指令。第2种是执行环境&#xff0c;它用于实际执行代码。 详解编译链接 翻译环境 ![在这里插入图片描述](https:/…

实战:单点登录的两种实现方式,附源码

最近工作有点忙&#xff0c;好久没更新文章了&#xff0c;正好这两天在整理单点登陆相关的文档&#xff0c;今天趁着小孩睡着了&#x1f92b;&#xff0c;赶紧码一篇实战文交差。 概念 单点登录&#xff08;Single Sign-On&#xff0c;SSO&#xff09;是一种身份验证服务&…

机器学习常识 13: PCA

摘要: 主成分分析 (principal component analysis, PCA) 是一种有理论依据的无监督特征提取的线性方法. 1. 特征选择与特征提取 特征选择是指从已有的特征里面选择出一个子集. 例如: 身高、体重、性别、年龄、体温、血相等等, 如果要一个人是否患流感&#xff0c;身高、体重等…

OpenMMLab-AI实战营第二期——1. 计算机视觉与OpenMMLab概述

文章目录 1. 课程内容概述1.1 Openmmlab框架1.2 课程其他说明 2. mmcv安装2.1 正确步骤2.2 debug2.3 错误探索 1. 课程内容概述 个人更关注语义分割和3D方面的内容&#xff0c;所以这里重点记录这两点相关的。 1.1 Openmmlab框架 具体的模块&#xff0c;详见&#xff1a;http…

wy的leetcode刷题记录_Day67

wy的leetcode刷题记录_Day67 声明 本文章的所有题目信息都来源于leetcode 如有侵权请联系我删掉! 时间&#xff1a;2023-6-1 前言 目录 wy的leetcode刷题记录_Day67声明前言1019. 链表中的下一个更大节点题目介绍思路代码收获 1019. 链表中的下一个更大节点 222. 完全二叉树…

UUOffice 工具箱,一款功能强大的 Excel 办公插件,好用推荐 ~

简介 UUOffice 工具箱,是一款功能强大的Office插件&#xff0c;功能强大&#xff0c;有着各种的单元格及文本的处理工具&#xff0c;自定义扩展函数&#xff0c;批注管理&#xff0c;图片导入导出&#xff0c;工作表汇总&#xff0c;联想输入等等超多实用工具&#xff0c;对日…

奇葩算法——猴子排序

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;猴子排序 ✅创作者&#xff1a;林在闪闪发光 ⏰预计时间&#xff1a;30分钟 &#x1f389;个人主页&#xff1a;林在闪闪发光的个人主页 &#x1f341;林在闪闪发光的个人社区&#xff0c;欢迎你的加入: 林在闪闪发光的社区…

Docker下载遇到的报错以及解决记录

目录 一、docker介绍 1. Docker引擎 2. Docker镜像 3. Docker容器 4. Docker仓库 5. Docker网络 二、docker下载 1.首先再官方下载好docker 2.在我打开时出现了下面的错误&#xff1a; 然后我下载了一个wsl 然后就可以正常打开了 &#xff08;2&#xff09;如果自己的电…

「学习IT技术和编写高质量代码的经验和建议」

一、你在编写代码时&#xff0c;会特别注意哪些流程&#xff1f; 在编写代码的过程中&#xff0c;我通常会特别注意以下流程&#xff1a; 输入验证&#xff1a;确保输入的参数满足预期&#xff0c;防止出现非法输入导致的安全问题或异常错误。 异常处理&#xff1a;在代码中添…

迅为全国产ATX3A5000_7A2000主板-龙芯平台安装 开源loongnix系统

Loongnix下载 Loongnix桌面版镜像:有基于mate主题的版本和基于cartoon主题的版本。本章节的安装 步骤以cartoon主题的安装方式为例&#xff0c;mate主题的ISO安装步骤与cartoon主题的安装方式类 似。 1.1 引导和开始安装 主机启动后,BIOS从U盘引导启动系统&#xff0c;出现…

Vue组件化、通过自定义指令子组件向父组件传递、$nextTick

1.如何安装Vue脚手架&#xff1f; 第一步&#xff08;仅第一次执行&#xff09;&#xff1a;全局安装vue/clinpm install -g vue/cli 第二步&#xff1a;切换到你要创建项目的目录&#xff0c;然后使用命令创建项目vue create xxxx 第三步&#xff1a;启动项目npm run serve 2…

chatgpt赋能python:Python中的或且非

Python中的或且非 Python语言中的逻辑运算符包括&#xff1a;或、与、非&#xff0c;分别用 “|”、“&”、"~"符号表示。 或运算符&#xff08;|&#xff09; 当两个操作数中有一个为True时&#xff0c;结果为True。 例如&#xff1a; a 1 b 2 c 3 if a…

Qt概述和项目文件介绍

注意&#xff1a;学习本专栏的内容需要了解C相关知识&#xff0c;会涉及到C基础语法和相关特性&#xff0c;可以参考我的另一个专栏 c从零开始_小梁今天敲代码了吗的博客-CSDN博客 目录 一.什么是Qt 二.Qt的案例 三.项目文件介绍 一.什么是Qt 是一个跨平台的 C 应用程序…

YOLOV5 + PYQT5双目测距(二)

YOLOV5 PYQT5双目测距 1. 测距源码2. 测距原理3. PYQT环境配置4. 实验4.1 下载源码14.2 复制源码2文件夹4.3 创建py文件4.4 实验结果 1. 测距源码 详见文章 YOLOV5 双目测距&#xff08;python&#xff09; 2. 测距原理 如果想了解双目测距原理&#xff0c;请移步该文章 双…

chatgpt赋能python:Python中的行与列:从入门到精通

Python中的行与列&#xff1a;从入门到精通 Python是一种高级编程语言&#xff0c;广泛用于计算机编程领域。在Python中&#xff0c;行和列是编程过程中不可或缺的元素&#xff0c;因为它们代表着代码中最基本的构建块。本文将介绍Python中的行和列&#xff0c;并探讨它们在程…