(20)从strlen到strtok:解码C语言字符函数的“生存指南1”

❤个人主页:折枝寄北的博客
❤专栏位置:简单入手C语言专栏
目录
- 前言
- 1. 求字符串长度函数
- 1.1 strlen
- 2. 长度不受限制的字符串函数
- 2.1 strcpy
- 2.2 strcat
- 2.3 strcmp
- 3. 长度受限制的字符串函数
- 3.1 strncpy
- 3.2 strncat
- 3.3 strncmp
- 4. 字符串查找函数
- 4.1 strstr
- 4.2 strtok
- 感谢您的阅读支持,欢迎交流
前言
当你写下strcpy(dest, src)这行看似无害的代码时,是否意识到自己正在操作系统的血管里进行一场没有安全绳的高空走钢丝?在C语言的世界里,字符串从来都不是温顺的数据羔羊,而是戴着可爱面具的"内存刺客"——那些优雅的str开头的函数库,既是程序员最亲密的工具,也是引发段错误(Segmentation Fault)的经典元凶。
1. 求字符串长度函数
1.1 strlen
库中的规范定义形式如下:
size_t strlen ( const char * str );
strlen函数是用来求字符串长度的常用库函数
在使用的时候要注意以下几点:
- 字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )
- 参数指向的字符串必须要以 ‘\0’ 结束。
- 注意函数的返回值为size_t,是无符号的**( 易错 )**
** strlen函数模拟实现**
//版本1
int my_strlen(const char* str)
{assert(str != NULL);//断言int count = 0;while (*str != '\0'){count++;str++;}return count;
}//2递归的方式
int my_strlen(const char* str)
{assert(str != NULL);//断言int count = 0;if (*str != '\0'){return 1 + my_strlen(str + 1);}elsereturn 0;
}//3指针-指针的方式
int my_strlen(const char* str)
{const char* start = str;assert(str != NULL);//断言while (*str){str++;}return str - start;
}int main()
{char arr[] = "abcdef";int len = my_strlen(arr);prinf("%d\n", len);return 0;
}
以上三种方式都是Int类型,但是在库中返回类型是size_t strlen是求字符串长度的,求出的长度是不可能为负数的。
所以返回类型是size_t,也是合情合理的 typedef unsigned int size_t size_t strlen (const char * str );
int main()
{if (strlen("abc") - strlen("abcdef") > 0)// -3<0,应输出<
//注意:按实际情况来说,应该输出小于号,但是我们输出结果为">"
//strlen是size_t类型,都是无符号数,所以计算机认为-3是无符号数,其实是很大的数
//所以使用的时候要注意使用场景printf(">");elseprintf("<");return 0;
}
2. 长度不受限制的字符串函数
2.1 strcpy
库中的规范定义形式如下:
char* strcpy(char* destination, const char* source);
strcpy函数是字符串拷贝函数,在使用时要注意以下几点:
- 必须保证字符串最后有\0,中间有\0也会被拷贝
- 使用时要保证空间足够大
int main()
{char arr1[20] = "x";char* p = "abcdefg";char arr2[] = "hello world";strcpy(arr1, arr2);//strcpy(p, arr2);p是常量字符串,空间不可变,不可作为目的数组return 0;
}
模拟实现strcpy函数
模拟实现strcpy
int my_strcpy(char* dest, char* src)
{char* ret = dest;assert(dest && src);//断言二者不为空,不写也可以,但是这样方便找bugwhile (*dest++=*src++){;}return ret;//返回目标空间起始地址
}
int main()
{char arr1[20] = " ";char arr2[] = "hello world";my_strcpy(arr1, arr2);printf("%s\n", arr1);return 0;
}
2.2 strcat
库中的规范定义形式如下:
char* strcat(char* destination, const char* source);
strcat函数是字符串追加函数,使用时要注意以下几点:
- 源字符串必须以 ‘\0’ 结束。
- 目标空间必须有足够的大,能容纳下源字符串的内容。
- 目标空间必须可修改。
- 字符串自己给自己追加,会失败,不可这样使用
nt main()
{char arr[20] = "hello ";strcat(arr, "world!");printf("%s\n", arr);return 0;
}
//遇到\0就停止追加内容
模拟实现strcat函数
char* my_strcat(char* dest, char* src)
{assert(dest && src);char* ret = dest;//1.找目标空间的\0while (*dest != '\0'){dest++;}//2.追加while (*dest++ = *src++){;}return ret;//
}
int main()
{char arr[20] = "hello ";my_strcat(arr, "world!");printf("%s\n", arr);return 0;
}
2.3 strcmp
库中的规范定义形式如下:
int strcmp ( const char * str1, const char * str2 );
strcmp函数是字符串比较函数,使用时要注意其返回值:
- 第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
int main()
{char arr1[] = "abcdef";char arr2[] = "abq";//在vs环境下://> 1//< -1 //= 0int ret = strcmp(arr1, arr2);//比较的是相同位置的字符大小printf("%d\n", ret);return 0;
}
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;elsereturn -1;*///也可以写为:return *str1 - *str2;
}
int main()
{char arr1[] = "abq";char arr2[] = "abcdef";//在vs环境下://> 1//< -1 //= 0int ret = my_strcmp(arr1, arr2);//比较的是相同位置的字符大小printf("%d\n", ret);return 0;
}
3. 长度受限制的字符串函数
3.1 strncpy
库中的规范定义形式如下:
char* strncpy(char* destination, const char* source, size_t num);
strncpy函数的功能是只拷贝要求数量的字符,使用时要注意以下几点:
- 拷贝num个字符从源字符串到目标空间。
- 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
使用strncpy函数示例
int main()
{char arr1[20] = "xxxxxx" ;strncpy(arr1, "abcedf", 3);//只拷贝3个字符,没有拷贝\0printf("%s\n", arr1);return 0;}
3.2 strncat
库中的规范定义形式如下:
char * strncat ( char * destination, const char * source, size_t num );
strncat函数的功能是加上指定数量的字符,使用与strncpy函数类似
strncat函数使用示例
int main()
{char* p1 = "abcdef";char* p2 = "abcqef";int ret = strncat(p1, p2, 4);printf("%d\n", ret);return 0;
}
3.3 strncmp
库中的规范定义形式如下:
int strncmp ( const char * str1, const char * str2, size_t num );
strncmp函数的功能是只比较要求数量的字符,使用的情况与3.1和3.2类似
strncmp函数使用示例
int main()
{char* p1 = "abcdef";char* p2 = "abcqef";int ret = strncmp(p1, p2, 4);printf("%d\n", ret);return 0;
}
4. 字符串查找函数
4.1 strstr
库中的规范定义形式如下:
const char * strstr ( const char * str1, const char * str2 );
char* strstr(char* str1, const char* str2);
strstr函数的功能是在字符串中寻找子字符串
strstr函数使用示例
int main()
{char arr1[] = "abbbabcdef";char arr2[] = "abc";char* ret = strstr(arr1, arr2);if (ret == NULL){printf("没找到对应字符串\n");}else{printf("找到对应的字符串\n");}return 0;
}
strstr函数简单模拟实现
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;s2 = str2;while (*s1!='\0'&&*s2!='\0'&& * s1 == *s2){s1++;s2++;}if (*s2 == '\0'){return (char*)cp;}cp++;}return NULL;
}int main()
{char arr1[] = "abbbabcdef";char arr2[] = "abdd";char* ret = strstr(arr1, arr2);if (ret == NULL){printf("没找到对应字符串\n");}else{printf("找到对应的字符串\n");}return 0;
}
4.2 strtok
库中的规范定义形式如下:
char * strtok ( char * str, const char * sep );
使用strtok函数时要注意以下几点:
- sep参数是个字符串,定义了用作分隔符的字符集合
- 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
- 函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
- strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
- strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
- 如果字符串中不存在更多的标记,则返回 NULL 指针。
strtok函数使用示例
int main()
{char arr[] = "doffer@vip.qq.com";//分隔符:@ .char* p = "@.";char buf[20] = { 0 };strcpy(buf, arr);char* ret = NULL;/*char* ret= strtok(buf, p);printf("%s\n", ret);*/ret2开始,继续从后面进行截断//char* ret2 = strtok(NULL, p);//printf("%s\n", ret2);////char* ret3 = strtok(NULL, p);//printf("%s\n", ret3);//char* ret4 = strtok(NULL, p);//printf("%s\n", ret4);for (ret = strtok(buf, p); ret != NULL; ret = strtok(NULL, p)){printf("%s\n", ret);}return 0;
}
感谢您的阅读支持,欢迎交流
相关文章:
(20)从strlen到strtok:解码C语言字符函数的“生存指南1”
❤个人主页:折枝寄北的博客 ❤专栏位置:简单入手C语言专栏 目录 前言1. 求字符串长度函数1.1 strlen 2. 长度不受限制的字符串函数2.1 strcpy2.2 strcat2.3 strcmp 3. 长度受限制的字符串函数3.1 strncpy3.2 strncat3.3 strncmp 4. 字符串查找函数4.1 st…...
基于deepseek api和openweather 天气API实现Function Calling技术讲解
以下是一个结合DeepSeek API和OpenWeather API的完整Function Calling示例,包含意图识别、API调用和结果整合: import requests import json import os# 配置API密钥(从环境变量获取) DEEPSEEK_API_KEY os.getenv("DEEPSEE…...
Mongodb数据管理
Mongodb数据管理 1.登录数据库,查看默认的库 [rootdb51~]# mongo> show databases; admin 0.000GB config 0.000GB local 0.000GB> use admin switched to db admin > show tables system.version > admin库:admin 是 MongoDB 的管理…...
从短片到长片:王琦携《Mountain》续作迈向新高度
在王琦(Qi Wang)的带领下,广受关注的短片《Mountain》迎来了成长篇续作《Rite of the Mountain》。这一全新长片不仅是她从短片迈向长篇叙事的重要一步,更是一次大胆的艺术挑战。作为制片人的她,将继续以敏锐的视觉风格和深刻的叙事洞察,拓展《Mountain》所触及的情感深度,并构…...
DeepSeek应用——与PyCharm的配套使用
目录 一、配置方法 二、使用方法 三、注意事项 1、插件市场无continue插件 2、无结果返回,且在本地模型报错 记录自己学习应用DeepSeek的过程,使用的是自己电脑本地部署的私有化蒸馏模型...... (举一反三,这个不单单是可以用…...
c#中“事件-event”的经典示例与理解
在C#编程语言中,事件(Event)是一个非常重要的概念,它提供了一种松耦合的方式,让对象间能够通知彼此,而无需直接联系。事件的使用可以让我们的代码更加灵活、可扩展且易于维护。 事件可以视作委托的实例&…...
如何画产品功能图、结构图
功能图的类型 常见的功能图包括数据流图、用例图、活动图、状态图、类图、组件图、部署图等等,不同的应用场景和目标下,需要确定不同的功能图类型。 数据流图 用例图 状态图 类图 组件图 组件图是由软件系统、组件和组件之间的关系组成的图形…...
标准输入输出流,面向对象,构造函数
标准输入输出流 为什么不直接用printf和scanf? 不能输入/输出C新增的内容 std C的一些标识符,都是定义在std这个名字空间下面cout 是什么? 1.是一个ostream对象 output stream:输出流使用 <<:输出流运算符 作用:将右边…...
Vue2 中使用 UniApp 时,生命周期钩子函数总结
在 Vue2 中使用 UniApp 时,生命周期钩子函数是一个重要的概念。它允许开发者在特定的时间点运行代码,管理组件的生命周期。以下是 Vue2 中 UniApp 常用的生命周期钩子函数总结: 1. beforeCreate 说明: 组件实例刚被创建,此时数据…...
QEMU源码全解析 —— 内存虚拟化(12)
接前一篇文章:QEMU源码全解析 —— 内存虚拟化(11) 本文内容参考: 《趣谈Linux操作系统》 —— 刘超,极客时间 《QEMU/KVM》源码解析与应用 —— 李强,机械工业出版社 QEMU内存管理模型...
如何将ubuntu下的一个目录,保存目录结构为一个git仓库并上传
目录 1. 初始化本地Git仓库 2. 添加文件到仓库 3. 提交更改 4. 创建并关联远程仓库 5. 推送代码到远程仓库 完整流程总结 要将Ubuntu下的一个目录(例如rpc)保存为一个Git仓库并上传到远程仓库,您可以遵循以下步骤: 1. 初始…...
深度学习中通道数的理解
目录 一、通道(Channels)的作用 1. 表示输入数据的多样性 2. 提取多层次特征 3. 信息融合与交互 4. 控制模型的复杂度 5. 支持多任务学习 6. 实际应用中的通道设计 7. 总结 二、案例一 1. 输入图像的通道(RGB) 2. 输出特…...
2025寒假天梯赛训练5
L1-3 敲笨钟 - 2025寒假天梯赛训练5 思路:一般ex的模拟题,主要是找好空格的位置进行修改替换。 #include <bits/stdc.h> using namespace std; #define int long long #define endl "\n" #define sz(x) (int)x.size() #define e empla…...
PowerBI 矩阵 列标题分组显示(两行列标题)
先看效果 数据表如下: 我们在powerbi里新建一个矩阵,然后如图加入字段: 我们就会得到这样的矩阵: 我们在“可视化”->“列”,上双击,输入空格,就能消除左上角的"类别"两字 同理修…...
服务器部署DeepSeek,通过Ollama+open-webui部署
1. 安装ollama 1.1. linux 安装 Ollama是目前常用的AI模式部署的第三方工具,能一键部署deepSeek Ollama官方网址https://ollama.com/ 选择Download下载对应的服务版本 服务器选择Linux,下面是下载代码 curl -fsSL https://ollama.com/install.…...
PVE 磁盘管理详解:从 Windows 到 Linux 的思维转换(文末附资源)
Proxmox VE(PVE)是一款基于 Debian Linux 的虚拟化平台,其文件系统管理与 Windows 差异较大,尤其是磁盘和文件夹的设计逻辑。本文将以通俗易懂的方式,详解 PVE 中磁盘管理的核心操作,并对比 Windows 帮助大…...
Ubuntu 连接 air pods
1. sudo vim /etc/bluetooth/main.conf , 修改蓝牙模式为blder 2.sudo /etc/init.d/bluetooth restart, 重启蓝牙,即可连接成功...
【LeetCode Hot100 矩阵】矩阵置零、螺旋矩阵、旋转图像、搜索二维矩阵II
矩阵 1. 矩阵置零(Set Matrix Zeroes)解题思路步骤: 代码实现 2. 螺旋矩阵(Spiral Matrix)解题思路具体步骤: 代码实现 3. 旋转矩阵 90 度解决思路代码实现 5. 搜索二维矩阵中的目标值解决思路代码实现 1. …...
民用无人驾驶航空器操控员考试
1. 注册 民用无人驾驶航空器综合管理平台 (caac.gov.cn) 2. 选择 操控员资质 3. 安全操控理论培训 -> 在线视频培训 学习完后选择 【在线考试】 共 50道 单项 选择题,每选项3个,80分及格。 4. 查看 我的合格证 证书有效期2年...
TCP可靠传输的ARQ协议
基本知识 ARQ(Automatic Repeat-reQuest)协议主要包含:停等ARQ协议、连续ARQ协议,其中连续ARQ协议是为了解决停等ARQ协议信道利用率低的问题,目前传统的连续ARQ协议有回退N帧ARQ协议、选择性重传ARQ协议。 注意&#…...
秋招春招投递记录——2024
公司链接待办截止日期已完成状态携程集团(上海)https://campus.ctrip.com/campus-recruitment/简历挂微众银行(武汉)https://campus.webank.com/campus-recruitment/webankhr/测评腾讯云智(重庆)https://jo…...
前端与后端的对接事宜、注意事项
前端与后端的对接事宜、注意事项 一、对接核心流程(完整生命周期) #mermaid-svg-6yzij6OD8DKqiMLD {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-6yzij6OD8DKqiMLD .error-icon{fill:#552222;}#mermaid-svg-6yzi…...
002 第一个python程序
编程语言 编程语言可以做的事情: 网站开发、软件 、游戏、APP、 小程序、 爬虫、 数据分析、脚本 第一个python程序 找到IDE图标pycharm 新建项目 选择项目路径 创建目录 新建python文件 输入代码 运行程序查看结果 print 介绍 print : 输出内容…...
频率自适应扩张卷积(FADC)详解及代码复现
背景介绍 在介绍频率自适应扩张卷积(FADC)之前,我们需要了解卷积神经网络(CNN)在处理复杂图像任务时面临的挑战。CNN的成功主要依赖于其多层结构和卷积层的设计,这些设计可以有效地捕捉图像的局部特征。然而,随着网络层数的增加,感受野的大小也随之增加,这可能导致一…...
解锁机器学习核心算法 | 决策树:机器学习中高效分类的利器
引言 前面几篇文章我们学习了机器学习的核心算法线性回归和逻辑回归。这篇文章我们继续学习机器学习的经典算法——决策树(Decision Tree) 一、决策树算法简介 决策树算法是一种典型的分类方法,也是一种逼近离散函数值的方法。它的核心思想…...
数据结构——顺序表与链表
目录 前言 一线性表 二顺序表 1实现 2相关面试题 2.1移除元素 2.2删除有序数组中的重复项 3.3合并两个有序数组 3问题 三链表 1链表的分类 1.1单向或者双向 1.2带头或者不带头 1.3循环或者非循环 2实现 2.1尾插与头插 2.2尾删与头删 2.3pos前插入节点与删除…...
在 Python 中使用 Ollama API
文章目录 一、环境准备二、使用方法1.简单对话2.流式响应3.结构化输出4.自定义客户端4.1 同步客户端4.2 异步客户端4.3 同步 & 异步客户端不同调用次数耗时对比测试 三、常用的ollama API 接口聊天生成本地模型列表显示模型信息创建模型复制模型删除模型拉取模型推送模型生…...
BGP配置华为——RR反射器配置
实验拓扑 与之前实验同理将loop0作为routerID使用,且R1和R2上用loop1接口用于模拟用户其他网段 实验要求 1,在AS100内运行OSPF协议 2.配置路由反射器,使得从R1进入的数据能够反射到全局网络 3.在R1和R2上分别宣告自己的loop1口网段用于观…...
一.AI大模型开发-初识机器学习
机器学习基本概念 前言 本文主要介绍了深度学习基础,包括机器学习、深度学习的概念,机器学习的两种典型任务分类任务和回归任务,机器学习中的基础名词解释以及模型训练的基本流程等。 一.认识机器学习 1.人工智能和机器学习 人工智能&am…...
力扣做题记录 (二叉树)
二叉树 打算先来了解二叉树基础,都是简单题,目的是熟悉代码格式和解题基础思路。 1、二叉树最大深度 二叉树最大深度 方法一、深度搜索 直接用原函数做递归,比较简单 /*** Definition for a binary tree node.* struct TreeNode {* …...
