当前位置: 首页 > article >正文

【C语言】字符串与内存函数(str* /mem* 系列函数)

目录针对字符串的函数strlenstrcpystrcatstrcmpstrncpystrncatstrncmpstrstrstrtokstrerror针对字符的函数字符分类函数字符转换函数针对内存的函数memcpymemmovememcmpmemset针对字符串的函数strlen模拟实现 strlen 的方法方法一int my_strlen(const char* p) { assert(p ! NULL); int count 0; while (*p ! \0) { count; p; } return count; }方法二递归法int my_strlen(const char* p) { assert(p ! NULL); if (*p \0) return 0; else return 1 my_strlen(p 1); }方法三指针减指针int my_strlen(const char* p) { assert(p ! NULL); const char* start p; while (*p) { p; } return p - start; }实际上库函数的 strlen 函数的返回值类型是 size_t 类型size_t 类型其实就是 unsigned int 类型长度不可能为负数typedef unsigned int size_t。unsigned int 类型的数据减去一个 unsigned int 类型的数据结果为 unsigned int 类型的数据strlen“abc”- strlen“abcde”的结果不是负数而是一个很大的正数。所以说返回值的类型到底是 int 还是 size_t 有利有弊。strcpy模拟实现char* my_strcpy(char* dest, const char* src) { assert(dest src); char* ret dest; while (*dest *src) { ; } return ret; }1、源字符串我们不希望改变所以我们将 src 指针用 const 修饰。2、while 循环部分被简化。3、这个函数应该返回目标字符串的首字符地址注意1、源字符串必须以“\0’结束。while 循环部分的结束条件是 src ‘\0。2、会将源字符串中的“\0拷贝到目标空间。while 循环部分当 src 加1 指向 ’\0 后会进行赋值再判断3、目标空间必须足够大 , 以确保能存放源字符串。如果目标空间小于源字符串的长度则 strcpy 函数会对目标空间越界访问比如将 str2[5] abcde 复制到 str1[3] { 0 } ; 则 str1[3] dstr1[4] e , 这是错误的。4、目标空间必须可变。如果 dest 是一个字符常量指针如char *p “abc”p 不能作为 dest 的实参。strcat函数功能拼接src字符串到dest字符串模拟实现char* my_strcat(char* dest, const char* src) { assert(dest src); char* ret dest; //找目标字符串的\0 while (*dest) { dest; } //从\0开始追加 while (*dest *src) { ; } return ret; }1、被追加的字符串末尾要有 \0 strcat 才知道从哪里开始追加。2、追加的字符串末尾也要有 \0strcat 才知道什么时候停止追加。3、这个函数也应该返回目标字符串的首字符地址。字符串自己给自己追加不能使用 strcat 函数。strcmpstrcmp 函数有两个参数分别是两个字符数组名即 strcmparr1arr2strcmp 函数比较arr1 与 arr2 字符串从开始到 ‘\0’ 逐个比较相应位置上的字符只要发现某个位置上的字符的ASCII码值大于或小于对应位置的另一个字符串的字符就返回一个大于 0 的数或小于 0 的数如果每个字符串的字符的ASCII码值都相等即两个字符串一模一样就返回 0。VS环境下大于返回 1小于返回 -1等于返回 0。可以认为在词典中先出现的单词比后出现的单词小。模拟实现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; }注意1、我们只是想要比较两个字符串所以我们可以用 const 修饰 str1 和 str2 。2、有些编译器当 *str1 *str2 时直接返回 *str1 - *str2。3、根据 strcmp 返回值的结果判断两个字符串的大小最好的办法是 ifstrcmpstr1str2 或 或 0)。strncpystrcpy、strcat、strcmp 都是长度不受限制的函数编译器会认为这些函数不安全。后来引进了一些函数如 strncpy、strncat、strncmp 这些函数更加安全因为它们多了一个参数 int n 。模拟实现char* my_strncpy(char* dest, const char* src,int n) { assert(dest src); char* ret dest; int i 1; while ((*dest *src) (i n) (*src)) { i; } i; while (i n) { *dest \0; i; } return ret; }注意strncpy 与 strcpy 的不同之处1、strncpy 可以指定从源字符串中复制几个字符到目标字符串。2、当指定复制的字符数量大于源字符串的长度strcpy 会在目标字符串复制后补 ‘\0’当指定复制的字符数量小于或等于源字符串的长度目标字符串末尾不会补 ’\0‘ 这是 strncpy 的不足之处strncat模拟实现char* my_strncat(char* dest, const char* src,int n) { assert(dest src); char* ret dest; //找目标字符串的\0 while (*dest) { dest; } //从\0开始追加 while ((*dest *src) (n - 1)) { n--; } *dest \0; return ret; }注意strncat 与 strcat 的不同之处1、strncat 可以指定从源字符串中追加几个字符到目标字符串。2、当指定追加的字符数量小于或等于源字符串的长度目标字符串末尾仍然会补 ’\0‘ 。strncmp模拟实现int my_strncmp(const char* str1, const char* str2,int n) { assert(str1 str2); int i 1; while ((*str1 *str2) (i n)) { if(i n) return 0; if (*str1 \0) return 0; str1; str2; i; } if (*str1 *str2) return 1; else return -1; }strstr函数原型const char * strstr ( const char * str1, const char * str2 );函数功能在 str1 字符串中查找是否存在完整连续的 str2 字符串如果有就返回 str1 中存在的与 str2 字符串一模一样的最先出现的字符串的起始地址如果没有就返回 NULL。函数模拟实现char* my_strstr(const char* str1, const char* str2) { assert(str1 str2); if (*str2 \0) { return (char*)str1; } const char* s1 str1; const char* s2 str2; const char* cp str1; while (*cp) { s1 cp; while (*s1 *s2) { s1; s2; if (*s2 \0) return (char*)cp; if (*s1 \0) { return (char*)NULL; } } s2 str2; cp; } return (char*)NULL; }strtok函数原型char * strtok ( char * str, const char * delimiters );函数功能将 elimiters 所指向的常量字符串的每个字符作为分隔符以这些分隔符来分割 str 将 str 中的分隔符变为 ’\0‘所以strtok 函数会改变原字符数组要求原字符数组为可变的如果不想改变原字符数组一般将原字符数组使用 strcpy 函数拷贝到另一个字符数组去并返回分割后的字符串首字符的地址第一次调用 strtok 函数时str 的实参为要分割的字符数组名一次函数调用只分割一次如果要多次分割第二次及以后调用 strtok 函数时str 的实参为 NULLstrtok 会记住上一次分割时分割符下一个字符的地址并从这个地址开始寻找下一个分割符将下一个分隔符变为 \0 。使用技巧如果原字符数组有多个分隔符可以使用 for 循环来快速分割for (ret strtok(buf, p); ret ! NULL; retstrtok(NULL, p)) { printf(%s\n, ret); }strerrorC语言的库函数在运行的时候如果发生错误就会将错误码存在一个变量中这个变量是:errno这是一个全局变量使用它需要包含头文件 include errno.h错误码是一些数字:1 2 3 4 5我们需要讲错误码翻译成错误信息就要使用 strerror 函数函数原型char * strerror ( int errnum );errnum 就是错误码strerror 函数将返回一个指向错误信息的首字符的字符指针。应用举例int main() { FILE* pf fopen(test.exe, r); if (pf NULL) { printf(打开文件失败\n); return 1; } fclose(pf); return 0; }假设 test.exe 这个文件不存在那么程序将输出 “打开文件失败”这会让我们迷惑到底是不存在这个文件还是访问权限的问题还是其他的原因。如果我们使用 strerror 这个函数#include stdio.h #include errno.h #include string.h int main() { FILE* pf fopen(test.exe, r); if (pf NULL) { printf(%s\n, strerror(errno)); return 1; } fclose(pf); return 0; }程序会输出 “ No such file or directory ”这样我们就知道问题出在哪里了。perror相对于 strerror 函数perror 函数更加方便它可以直接打印错误信息。使用 perror 需要包含头文件 include stdio.h函数原型void perror ( const char * str );str 是指向你自定义的信息在打印错误信息之前会打印你自定义的信息应用举例int main() { FILE* pf fopen(test.exe, r); if (pf NULL) { perror(error); return 1; } fclose(pf); return 0; }程序会输出error No such file or directory针对字符的函数字符分类函数需要包含头文件 #include ctype.h函数名参数满足下列条件就反回非零否则返回零iscntrl任何控制字符isspace空白字符:空格’’,换页\f,换行‘\n’,回车\r’,制表符\t或者垂直制表符\visdigit十进制数字字符 0~9isxdigit十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~Fislower小写字母字符a~zisupper大写字母字符A~Zisalpha字母字符a~z或A~Zisalnum字母或者数字字符,a~z,A~Z,0~9ispunct标点符号,任何不属于数字或者字母的图形字符(可打印)isgraph任何图形字符isprint任何可打印字符,包括图形字符和空白字符字符转换函数大小写转换函数需要包含头文件#include ctype.htoupper 函数小写转大写和 tolower 函数大写转小写它们的参数是一个任意的 ASCII 码值不一定是大小写字母函数内部会判断如果不是大小写字母直接返回原字符返回值是转换后的字符的 ASCII 码值。应用举例int main() { char arr[] I Have An Apple.; int i 0; while (arr[i]) { if (isupper(arr[i])) arr[i] tolower(arr[i]); printf(%c, arr[i]); i; } return 0; }针对内存的函数以下函数都要包含头文件 string.hmemcpystrcpy 是拷贝字符串的函数如果我们想拷贝一个整形数组就要使用 memcpy 函数。函数原型void * memcpy ( void * destination, const void * source, size_t num );destination指向目标空间的指针source指向源空间的指针size_t num要拷贝的字节数void*函数返回目标空间的首地址应用举例int main() { int arr1[10] { 0,1,2,3,4,5,6,7,8,9 }; int arr2[10] { 3,4,5,6,7 }; memcpy(arr1, arr2 2, 12); return 0; }模拟实现void* my_memcpy(void* dest, const void* src,size_t num) { assert(dest src); void* ret dest; while (num--) { *(char*)dest *(char*)src; dest (char*)dest 1; src (char*)src 1; } return ret; }不足之处如果源空间与目标空间有重叠的地方用这种方式拷贝有 BUG。比如int main() { int arr1[10] { 0,1,2,3,4,5,6,7,8,9 }; my_memcpy(arr1 2, arr1, 20); return 0; }我想把 01234 拷贝到 23456 的位置上去预期的结果应该是0101234789实际的结果是0101010789解决方法如果我们想从后往前拷贝可以解决这个问题但是如果是将 23456 拷贝到 01234 的位置上去呢这时候又只能从前往后拷贝了所以我们得分情况讨论1、当 dest 在 src 的左边时从前往后拷贝2、当 dest 在 src 的右边时从后往前拷贝这就是 mommove 函数的思路。memmovemommove 函数可以实现有重叠的内存拷贝。运用以上思路模拟实现 mommove 函数evoid* my_memmove(void* dest, const void* src, size_t num) { assert(dest src); void* ret dest; if (dest src) { while (num--) { *(char*)dest *(char*)src; dest (char*)dest 1; src (char*)src 1; } } else { while (num--) { *((char*)dest num) *((char*)src num); } } return ret; }注意1、拷贝时要防止数组越界这不是函数该保证的事情而是程序员该保证的。2、库函数的 memcpy 与 mommove 的其实都能处理有重叠的情况。3、最保险的方式是统一用 mommove。memcmp函数原型int memcmp ( const void * ptr1, const void * ptr2, size_t num );ptr1 和 ptr2 指向要比较的字节num要比较的字节数量返回值只要 *ptr1 *ptr2 返回一个大于 0 的数只要 *ptr1 *ptr2 返回一个小于 0 的数否则返回 0。memset函数原型void * memset ( void * ptr, int value, size_t num );ptr要设置的内存的起始地址。value要设置的数据可以是整形可以是字符的 ASCII 码值也可以是字符如 ‘x’。num要设置的字节数。返回值设置的内存的起始地址。注意memset 函数是一个一个字节设置的将数组中每一个元素都初始化为 1 如果用int arr[10] { 0 };momset(arr , 1 , 40);这种方式初始化数组是不对的数组中每一个元素都被初始化为 0x 01 01 01 01将 int 类型的数组全部初始化为 0 或 -1 可以使用 memset初始化为其他数值不建议

相关文章:

【C语言】字符串与内存函数(str* /mem* 系列函数)

目录 针对字符串的函数 strlen strcpy strcat strcmp strncpy strncat strncmp strstr strtok strerror 针对字符的函数 字符分类函数 字符转换函数 针对内存的函数 memcpy memmove memcmp memset 针对字符串的函数 strlen 模拟实现 strlen 的方法&#xff…...

绿色循环经济下的农业新范式:让每一株蔬菜的“遗骸”化作新生

在山东临沂的兰陵县,一场关于农业废弃物资源化利用的变革正在发生。曾经令人头疼的农业秸秆和牛粪,如今正成为驱动当地蔬菜育苗产业的全新动力。这一变化的起点,是2023年9月正式投产的生升鸿强基质工厂。这家总投资1.1亿元的工厂,…...

C++、C语言和JAVA开发的区别

1。面向对象没有java彻底。由于C++要兼容C的内容,而C是面向过程的,所以C不可避免地出现过程影子,并不算是完全的面向对象的程序设计语言。例如总得要有main或winmain之类的过程吧。2。C的移植能力没有java好。 由于C的…...

maven常用命令大全

参考地址: 1.maven常用命令大全(附详细解释),https://blog.csdn.net/good_good_xiu/article/details/116740333 2.maven常用命令集合(收藏大全),https://zhuanlan.zhihu.com/p/355889432 3.Maven查看插件信息&#…...

终极指南:如何在5分钟内将图片转换为3D打印模型

终极指南:如何在5分钟内将图片转换为3D打印模型 【免费下载链接】ImageToSTL This tool allows you to easily convert any image into a 3D print-ready STL model. The surface of the model will display the image when illuminated from the left side. 项目…...

2026年,还想要入局大模型领域的学习和工作,还来得及吗?红利期还在吗?

AI这个圈子有一个很神奇的特点:就是复利性基本为零。 每次我看到类似「2026年,入行YYY方向还来得及吗?」的问题的时候,我都会想到这个特点。 原因其实很简单,我只从科研上举一些例子。比方说从2023年之后入行做生成的…...

Amulet-Map-Editor完整功能解析:从世界编辑到格式转换

Amulet-Map-Editor完整功能解析:从世界编辑到格式转换 【免费下载链接】Amulet-Map-Editor A Minecraft world editor and converter that supports all versions since Java 1.12 and Bedrock 1.7. 项目地址: https://gitcode.com/gh_mirrors/am/Amulet-Map-Edit…...

axilite + ap_memory约束数组-突破单口RAM限制

一、在不进行任何说明情况下axilite ap_memory约束数组 1.在这种情况下,会将接口数组综合为内部RAM,不再是单纯的接口了,而是实实在在的要消耗资源的 2.只不过这个RAM对外,这里的对外指的是CPU或者ARM,对外的接口是ax…...

(Linux)进程控制

进程创建 在代码中,进程创建用的是fork函数,调用fork函数后,操作系统会为子进程分配内存块和进程控制块(PCB),并将父进程PCB的部分内容拷贝至子进程。接着,将子进程添加到系统进程列表中&#x…...

ARM架构CNTP_CTL_EL0定时器寄存器详解与应用

1. ARM架构定时器控制寄存器概述在ARMv8/v9架构中,定时器系统是处理器时间管理的关键组件。CNTP_CTL_EL0作为物理定时器的控制寄存器,主要负责EL1(操作系统内核级)的物理定时器控制。这个64位寄存器虽然只使用了最低3位,却承载着定时器状态监…...

用Matlab给信号“搬家”:手把手教你将中频采样数据转为IQ格式(附完整代码)

用Matlab给信号“搬家”:手把手教你将中频采样数据转为IQ格式(附完整代码) 在无线通信系统测试和算法验证中,我们常常会遇到这样的场景:从频谱仪或采集卡获取的中频信号数据(如.mat文件)&#x…...

Material Design Lite图片优化:提升网页性能的终极指南

Material Design Lite图片优化:提升网页性能的终极指南 【免费下载链接】material-design-lite Material Design Components in HTML/CSS/JS 项目地址: https://gitcode.com/gh_mirrors/ma/material-design-lite Material Design Lite是一个轻量级的前端框架…...

软件忘了“擦黑板”:一次内核信息泄露事件(CVE-2024-49997)的深度剖析

想象一下,老师在用过的黑板上写字,没擦干净就直接开讲——网络世界里,这个“忘记擦黑板”的疏忽,可能导致整个系统的安全基石被悄然洞穿。 引言:一个不寻常的“内存泄露” 在程序员的世界里,提到“内存泄露…...

无射频芯片实现LoRa通信:LoLRa项目技术解析

1. LoLRa项目概述:无射频芯片的LoRa通信方案在物联网设备开发中,Semtech的LoRa射频芯片一直是实现远距离通信的主流选择。但最近开源的LoLRa项目展示了一种颠覆性思路——仅通过普通MCU的I2S或SPI接口就能生成可被商用LoRa网关识别的信号。这个由CNLohr开…...

3大核心优势解锁纯净音乐体验:MoeKoeMusic开源播放器深度解析

3大核心优势解锁纯净音乐体验:MoeKoeMusic开源播放器深度解析 【免费下载链接】MoeKoeMusic 一款开源简洁高颜值的酷狗第三方客户端 An open-source, concise, and aesthetically pleasing third-party client for KuGou that supports Windows / macOS / Linux / W…...

告别色彩失真:flv.js如何让YUV视频在浏览器绚丽绽放

告别色彩失真:flv.js如何让YUV视频在浏览器绚丽绽放 【免费下载链接】flv.js HTML5 FLV Player 项目地址: https://gitcode.com/gh_mirrors/fl/flv.js 在数字视频播放的世界里,色彩还原度直接影响着观看体验。HTML5 FLV Player(flv.js…...

从零开始打造OS性能监控:基于os-tutorial的计时器与中断完全指南

从零开始打造OS性能监控:基于os-tutorial的计时器与中断完全指南 【免费下载链接】os-tutorial How to create an OS from scratch 项目地址: https://gitcode.com/gh_mirrors/os/os-tutorial os-tutorial是一个从零开始构建操作系统的开源项目,它…...

京东工业与中交二航巴西公司战略合作,推动巴西属地化供应链能力升级

京东工业与中交二航巴西签署超深度合作协议4月21日,京东工业巴西有限公司和中交二航巴西工程有限公司(CHEC - BR)在巴西签署战略合作协议。双方将在渠道、供应链和MRO(维护、维修和运营物资)采购方面开展深度合作&…...

JCSprout事务管理终极指南:声明式与编程式事务对比分析

JCSprout事务管理终极指南:声明式与编程式事务对比分析 【免费下载链接】JCSprout 👨‍🎓 Java Core Sprout : basic, concurrent, algorithm 项目地址: https://gitcode.com/gh_mirrors/jc/JCSprout JCSprout作为Java核心知识的学习…...

如何实现XState状态机日志记录:完整的变更追踪与审计指南

如何实现XState状态机日志记录:完整的变更追踪与审计指南 【免费下载链接】xstate State machines, statecharts, and actors for complex logic 项目地址: https://gitcode.com/gh_mirrors/xs/xstate XState是一个强大的状态管理库,用于构建复杂…...

3步永久保存微信聊天记录的终极解决方案:WeChatMsg完全指南

3步永久保存微信聊天记录的终极解决方案:WeChatMsg完全指南 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/…...

终极指南:使用XState实现灵活高效的权限管理系统

终极指南:使用XState实现灵活高效的权限管理系统 【免费下载链接】xstate State machines, statecharts, and actors for complex logic 项目地址: https://gitcode.com/gh_mirrors/xs/xstate 在现代应用开发中,权限管理是确保系统安全和用户体验…...

别再让AI生成视频糊成马赛克了!手把手教你用Topaz Video AI 4.0无损放大(附Win/Mac预设参数)

从马赛克到4K:用Topaz Video AI拯救AI生成视频的终极指南 当你在Pika或Runway上兴奋地生成了一段创意视频,却发现画面糊得像隔了层毛玻璃——这种失望感我太熟悉了。AI视频生成工具虽然打开了创意新世界,但分辨率问题始终是硬伤。别急着放弃你…...

ViGEmBus终极指南:5分钟搞定Windows游戏手柄模拟难题

ViGEmBus终极指南:5分钟搞定Windows游戏手柄模拟难题 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus 你是否遇到过这样的困扰?手头有…...

如何用AiZynthFinder在3分钟内完成复杂分子的AI逆合成路线设计?

如何用AiZynthFinder在3分钟内完成复杂分子的AI逆合成路线设计? 【免费下载链接】aizynthfinder A tool for retrosynthetic planning 项目地址: https://gitcode.com/gh_mirrors/ai/aizynthfinder 想象一下,你是一位药物研发化学家,面…...

SAP FI实操笔记:中日会计科目对照表,手把手教你配置GL主数据

SAP FI中日会计科目智能配置实战:从对照表到系统落地的全流程解析 当东京证券交易所的上市公司需要合并其在华子公司报表时,财务团队总会在会计科目转换环节遭遇"术语迷阵"。某日企财务总监曾向我展示过他们手工维护的Excel对照表——超过2000…...

Viper配置加密方案:安全存储敏感配置信息的终极指南

Viper配置加密方案:安全存储敏感配置信息的终极指南 【免费下载链接】viper Go configuration with fangs 项目地址: https://gitcode.com/gh_mirrors/vi/viper Viper作为Go语言生态中强大的配置管理工具,不仅提供了灵活的配置读取能力&#xff0…...

从区间锁到行锁:一次高并发写入死锁治理实战

资源账户写入链路长期存在 MySQL 死锁报警,日常量级达到 99。虽然业务层依赖消息总线重试后多数请求可以成功,但从数据库和链路治理角度看,这类问题已经属于稳定存在的并发设计缺陷。 本次治理聚焦一个典型场景:同一 uid 并发发放…...

3步掌握Textractor:游戏文本提取神器,让外语游戏无障碍畅玩

3步掌握Textractor:游戏文本提取神器,让外语游戏无障碍畅玩 【免费下载链接】Textractor Extracts text from video games and visual novels. Highly extensible. 项目地址: https://gitcode.com/gh_mirrors/te/Textractor 还在为看不懂日语RPG的…...

Gramps家谱软件完整指南:如何轻松构建您的家族历史数据库

Gramps家谱软件完整指南:如何轻松构建您的家族历史数据库 【免费下载链接】gramps Source code for Gramps Genealogical program 项目地址: https://gitcode.com/gh_mirrors/gr/gramps 您是否曾为家族历史资料零散而烦恼?是否想系统整理祖辈故事…...