C语言字符函数和字符串函数
前言
今天这篇博客咱们一起来认识一些特殊的函数,在编程的过程中,我们经常要处理字符和字符串,为了方便字符和字符串,C语言提供了一些库函数,让我们一起看看这些函数都有什么功能吧!!!
个人主页:小张同学zkf
若有问题 评论区见
感兴趣就关注一下吧
目录
1. 字符分类函数
2. 字符转换函数
3. strlen的使用和模拟实现
4. strcpy的使用和模拟实现
5. strcat的使用和模拟实现
6. strcmp的使用和模拟实现
7. strncpy,strncat, strncmp函数的使用
8. strstr的使用和模拟实现
9. strtok函数的使用
10.strerror函数的使用
1. 字符分类函数
C语言中有一系列的函数是专门做字符分类的,也就是一个字符是属于什么类型的字符的。
这些函数的使用都需要包含一个头文件是 <ctype.h>
以上函数使用方法非常类似,我们随便列举一个,结构都非常相似
int islower ( int c );
islower 是能够判断参数部分的 c 是否是小写字母的。
通过返回值来说明是否是小写字母,如果是小写字母就返回非0的整数,如果不是小写字母,则返回0。其他分类函数跟这个一样,满足对应条件返回非0整数,不满足条件,返回0,记住非0的整数不一定是1!!!
2. 字符转换函数
C语言提供了2个字符转换函数:
int tolower ( int c ); //将参数传进去的大写字母转小写
int toupper ( int c ); //将参数传进去的小写字母转大写
这两个函数的功能相当于对应字符ASC码值加减32来转换大小写嘛
从这个函数开始以下所有的函数以str开头的都是字符串函数,头文件<string.h>
3. strlen的使用和模拟实现
格式
size_t strlen ( const char * str );
这个已经很熟悉,之前博客无数次提到,它就是字符串函数其中之一strlen函数
注意几个事项:
• 字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包
含 '\0' )。
• 参数指向的字符串必须要以 '\0' 结束。
• 注意函数的返回值为size_t,是无符号的( 易错 )
• strlen的使用需要包含头文件
我们来再看看strlen用法
看以下代码:
#include <stdio.h>
#include <string.h>
int main()
{
const char* str1 = "abcdef";
const char* str2 = "bbb";
if(strlen(str2)-strlen(str1)>0)
{
printf("str2>str1\n");
}
else
{
printf("srt1>str2\n");
}
return 0;
}
通俗的说,strlen就是计算字符串中‘\0’之前字符个数
我们既然知道这个函数的功能,那怎么样模仿它实现呢
方法一:
我们分析一下,我们可以创建一个计数变量count,只要传过去的指针解引用满足不为‘\0’字符,那么count就++
以下是我创建的函数来模拟strlen的实现
//计数器方式
int my_strlen(const char * str)
{
int count = 0;
assert(str);//防止传来的函数指针是野指针,可以断言一下
while(*str)
{
count++;
str++;
}
return count;
}
方法二:
假如规定我们不创建临时变量,我们该怎么做哪,我们不如用函数递归的思想看可行不可行
用函数递归的方法,将它大事化小,一个字符一个字符的分离加上去,就像橘子那样一片一片的往外剥
看一下代码
//不能创建临时变量计数器
int my_strlen(const char * str)
{
assert(str);
if(*str == '\0')
return 0;
else
return 1+my_strlen(str+1);
}
方法三:
我们还可以用指针运算来模仿strlen函数,指针-指针求得偏移量就是字符个数
看下代码
//指针-指针的方式
int my_strlen(char *s)
{
assert(str);
char *p = s;
while(*p != ‘\0’ )
p++;
return p-s;
}
4. strcpy的使用和模拟实现
char* strcpy(char * destination, const char * source );
这个strcpy函数功能是将第二个参数字符串拷贝一份到第一个参数,使第一个参数字符串与第二个参数字符串相同
注意:• 源字符串必须以 '\0' 结束。
• 会将源字符串中的 '\0' 拷贝到目标空间。
• 目标空间必须足够大,以确保能存放源字符串。
• 目标空间必须可修改。
我们来模拟实现一下这个函数
我们分析一下,简单来说,它不就是将第二个参数字符串中的字符挨个给第一个参数字符串中的字符赋值嘛,那我可以把他们分别解引用,赋完值地址再加加再解引用……循环下去直到把‘\0’也赋值过去停止
以下是模拟这个函数的代码
char* my_strcpy(char *dest, const char*src)
{
char *ret = dest;
assert(dest != NULL);
assert(src != NULL);
while((*dest++ = *src++))
{
;
}
return ret;
}
5. strcat的使用和模拟实现
char* strcat(char * destination, const char * source );
strcat这个函数就是追加的意思,将第二个参数的字符串追加到第一个参数的字符串的后面。
注意:
• 源字符串必须以 '\0' 结束。
• 目标字符串中也得有 \0 ,否则没办法知道追加从哪里开始。
• 目标空间必须有足够的大,能容纳下源字符串的内容。
• 目标空间必须可修改
接下来模拟一下这个函数
我们仔细想,可以把它拆成两部分先将目标字符串的指针指向‘\0’,再将要追加的函数从这里进行拷贝
以下是模拟实现这个函数的代码
char *my_strcat(char *dest, const char*src)
{
char *ret = dest;
assert(dest != NULL);
assert(src != NULL);
while(*dest)
{
dest++;
}\\找'\0'
while((*dest++ = *src++))\\开始拷贝
{
;
}
return ret;
}
我们假想一下,一个字符串能自己追加自己吗
字符串要是自己追加自己,它原函数的“\0”被覆盖了,你追加函数是它本身,也没“\0”了,所以没"\0"它会死循环追加下去!!!
6. strcmp的使用和模拟实现
int strcmp (const char * str1, const char * str2)
看这个函数的格式,我们要知道它的返回值是整形
这个函数就是让字符串进行比较,若第一个参数的字符串大于第二个参数的字符串,返回大于零的数,若第一个参数的字符串小于第二个参数的字符串,返回小于零的数,若相等,返回零,比较的话这两个指针指向的字符串不能变,所以都得用const修饰
那俩字符串具体怎么比较那
就是将他们所有字符asc码值一个一个字符对应比较,直到比较出结果不再比较,‘\0’asc码值比任何字符都小
我们来模拟实现一下这个函数
这个函数简单来说就是每个字符比较呗,那我就分别解引用比较若相等,再地址加加,循环下去,若字符一直相同直到‘\0’还相同,那就返回零代表俩字符相等,若加加过程中,突然字符不相等,那就跳出这个循环,直接返回现在所指的字符之差的数。
int my_strcmp (const char * str1, const char * str2)
{
int ret = 0 ;
assert(str1 != NULL);
assert(str2 != NULL);
while(*str1 == *str2)
{
if(*str1 == '\0')
return 0;
str1++;
str2++;
}
return *str1-*str2;
}
7. strncpy,strncat,strncmp函数的使用
这三个跟上面的比肉眼可见多了个n,其实就是有个数限制了
怎么说那
就拿这个strncpy来说
char * strncpy ( char * destination, const char * source, size_t num );
发现多了个参数num,这个num的意思就是我要拷贝几个字符过去,就是这意思,拷贝几个就是几个,不带‘\0’拷贝过去,除非它将字符串全拷贝过去带上‘\0’
那strncat,strncmp也是这个意思,我要追加几个,比较几个
注意的是strncat不管追加几个都会自动再追加个‘\0‘,毕竟追加过后的字符串末尾也得有‘\0’呀
8. strstr的使用和模拟实现
char * strstr ( const char * str1, const char * str2);
这个就是在str1中找到str2的字符串,返回的是字符串str2在字符串str1中第⼀次出现的位置
strstr模拟实现:
这个我们先想如果我们找到了对应的第一个字符相同那我们是不是先用一个指针记录下来,假如后面也都相同那不就找到这个函数的位置了嘛,那返回是不是返回位置相同的起始位置,那就是需要记录起始位置的指针,接下来我们再想想找到了第一个相同的字符,接下来肯定需要指针继续往后指进行判断,若中间字符不相同了,那相同的起始位置的指针向后移找到下一个相同的起始位置,从而形成循环,那我是不是又要需要两个指针那,这两个指针分别从相同的起始位置往后移进行比较,所以我们需要创建三个指针,还要记住比较过程中,若中间有一个字符串指向‘\0’,那跳出循环,若是第二个参数字符串先到‘\0’,那就是找到了,返回初始相同位置的指针,若第一个参数字符串都指向‘\0’,而第二个字符串还没有指向‘\0’,那就是没找到。
char * strstr (const char * str1, const char * str2)
{
char *cp = (char *) str1;
char *s1, *s2;
if ( !*str2 )
return((char *)str1);
while (*cp)
{
s1 = cp;
s2 = (char *) str2;
while ( *s1 && *s2 && !(*s1-*s2) )
s1++, s2++;
if (!*s2)
return(cp);
cp++;
}
return(NULL);
}
9. strtok函数的使用
char * strtok ( char * str, const char * sep);
这个函数就是分隔符将字符串分割起来,返回的指针就是这个分隔符标记的指针
哈哈什么意思那
分隔符就是一些特殊符号比如@……这个第二个参数里面存储的字符串就是第一个参数的字符串里特殊符号的集合,就是分隔符的集合
注意:
• sep参数指向一个字符串,定义了用作分隔符的字符集合
• 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标
记。
• strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:
strtok函数会改变被操作的字符串,所以在使⽤strtok函数切分的字符串⼀般都是临时拷贝的内容
并且可修改。)
• strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串
中的位置。
• strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标
记。
• 如果字符串中不存在更多的标记,则返回 NULL 指针。
我们来看一个奇妙的代码加深理解
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "192.168.6.111";
char* sep = ".";
char* str = NULL;
for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
{
printf("%s\n", str);
}
return 0;
}
大家看看这个for循环,初始值就是第一个标记之前的字符串,然后保存这个标记的位置,然后从这个标记的位置开始找到下一个标记,打印这个保存的标记到下一个标记之间的字符串,然后保存下一个标记……直到一个标记为空指针,循环结束
10.strerror函数的使用
char * strerror ( int errnum );
strerror函数可以把参数部分错误码对应的错误信息的字符串地址返回来。
在不同的系统和C语言标准库的实现中都规定了一些错误码,一般是放在 errno.h 这个头文件中说明的,C语言程序启动的时候就会使用一个全局的变量errno来记录程序的当前错误码,只不过程序启动的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码,存放在errno中,而一个错误码的数字是整数很难理解是什么意思,所以每一个错误码都是有对应的错误信息的。strerror函数就可以将错误对应的错误信息字符串的地址返回。
#include <errno.h>
#include <string.h>
#include <stdio.h>
//我们打印⼀下0~10这些错误码对应的信息
int main()
{
int i = 0;
for (i = 0; i <= 10; i++) {
printf("%s\n", strerror(i));
}
return 0;
}
结果
也可以了解一下perror函数,可以直接将错误信息打印出来。perror函数打印完参数部分的字符串后,再打印一个冒号和一个空格,再打印错误信息。
举个例子
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{
FILE * pFile;
pFile = fopen ("unexist.ent","r");
if (pFile == NULL)
perror("Error opening file unexist.ent");
return 0;
}
输出
Error opening file unexist.ent: No such file or directory
OK字符串函数与字符函数总结结束,下篇总结一些内存函数
相关文章:

C语言字符函数和字符串函数
前言 今天这篇博客咱们一起来认识一些特殊的函数,在编程的过程中,我们经常要处理字符和字符串,为了方便字符和字符串,C语言提供了一些库函数,让我们一起看看这些函数都有什么功能吧!!࿰…...
Go语言必知必会100问题-22 空切片与nil切片有区别吗?
空切片与nil切片有区别吗? 很多开发人员经常混淆nil切片和空切片,不清楚什么时候使用空切片什么时候使用nil,而有些库函数又对这两者使用进行了区分。下面先来看看它们的定义。 空切片是length为0的切片当切片等于nil时为nil切片 下面是几种不同空切片…...

【C++进阶】C++多态概念详解
C多态概念详解 一,多态概念二,多态的定义2.1 多态构成的条件2.2 什么是虚函数2.3 虚函数的重写2.3.1 虚函数重写的特例2.3.2 override和final 2.4 重载和重写(覆盖)和重定义(隐藏)的区别 三,抽象…...

Python 导入Excel三维坐标数据 生成三维曲面地形图(面) 2、线条平滑曲面但有间隔
环境和包: 环境 python:python-3.12.0-amd64包: matplotlib 3.8.2 pandas 2.1.4 openpyxl 3.1.2 scipy 1.12.0 代码: import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from scipy.interpolate import griddata imp…...

前端精准测试调用链路分析
精准测试在评估需求的测试范围时,需要评估一下代码的影响范围,这个范围有两部分:一是需求直接修改的代码;二是修改代码影响到的功能模块。代码影响到的功能一般是通过调用链路分析来实现的,java和kotlin代码可以由java…...

Objective-C blocks 概要
1.block的使用 1.1什么是block? Blocks是C语言的扩充功能:带有自动变量(局部变量)的匿名函数。 “带有自动变量”在Blocks中表现为“截取自动变量" “匿名函数”就是“不带名称的函数” 块,封装了函数调用及调用…...

Linux操作系统-07-Linux安装应用
一、使用rpm安装应用(不推荐) 先下载到本地,以.rpm文件名结尾,下载完成后,再安装 rpm -qa | grep mysql #查询当前系统是否有下载过mysql包 先上传mysql的rpm安装包到linux的opt目录 安装 rpm -ivh …...
DevOps实战:Docker、Kubernetes与Jenkins的完美融合
DevOps与容器化技术:Docker、Kubernetes和Jenkins 引言 在软件开发领域,DevOps文化和容器化技术已经成为当今最热门的话题之一。DevOps的目标是缩短开发和运维之间的距离,提高软件交付的速度和质量。而容器化技术,如Docker和Kub…...

Python面向对象——程序架构
需求 创建图形管理器 -记录多种图形(圆形、矩形.) --提供计算总面积的方法, 要求:增加新图形,不影响图形管理器 测试: 创建图形管理器,存储多个图形对象。 通过图形管理器,调用计算总面积方法 思路 代码 # ------…...
springboot单体项目链路日志跟踪及接口耗时
最近接触一个新的传统项目,在联调过程中,查看日志特别不方便,既无trackId,即无接口耗时,所以写了该博客。话不多说,直接上代码 1、实体类user package com.yk.domain;import lombok.Data;@Data public class User {private Long id;private String username;private St…...

力扣hot---岛屿数量
dfs思路: 首先通过两层for循环遍历每一个点,如果这个点为0或者2(这个2是什么呢?是在遍历该点以及该点连成的这一片区域中,因为通过深度优先搜索,遍历该点就等于遍历这一片区域,遍历这篇区域中的…...

如何在Linux使用docker安装Plik并实现无公网ip上传下载内网存储的文件资源
文章目录 1. Docker部署Plik2. 本地访问Plik3. Linux安装Cpolar4. 配置Plik公网地址5. 远程访问Plik6. 固定Plik公网地址7. 固定地址访问Plik 正文开始前给大家推荐个网站,前些天发现了一个巨牛的 人工智能学习网站, 通俗易懂,风趣幽默&…...
Nginx反向代理详解
1. 什么是反向代理 反向代理是一种服务器代理的方式,它代理了客户端的请求并将请求转发给后端服务器,然后将后端服务器的响应返回给客户端。在这个过程中,客户端并不直接与后端服务器通信,而是通过反向代理服务器来实现请求转发和…...

【Android】 ClassLoader 知识点提炼
1.Java中的 ClassLoader 1.1 、ClassLoader的类型 Java 中的类加载器主要有两种类型,即系统类加载器和自定义类加载器。其中系统类 加载器包括3种,分别是 Bootstrap ClassLoader、Extensions ClassLoader 和 Application ClassLoader。 1.1.1.Bootstra…...

16. C++标准库
C标准库兼容C语言标准函数库,可以在C标准库中直接使用C语言标准函数库文件,同时C标准库增加了自己的源代码文件,新增文件使用C编写,多数代码放在std命名空间中,所以连接C标准库文件后还需要 using namespace std;。 【…...

JVM内存结构介绍
1. 什么是JVM 我们都知道在 Windows 系统上一个软件包装包是 exe 后缀的,而这个软件包在苹果的 Mac OSX 系统上是无法安装的。类似地,Mac OSX 系统上软件安装包则是 dmg 后缀,同样无法在 Windows 系统上安装。 Java 代码为什么可以在 Windows…...

Linux常见指令总结
ls:显示当前目录下文件列表 常用的命令行参数: -l 显示更多的文件属性 -a 显示所有的文件/目录(包括隐藏的) -d 只显示目录 ps:参数可以叠加使用。 例如:ls -la 显示所有文件…...

Day35-Linux网络管理5
Day35-Linux网络管理5 1. 网卡配置2. DNS客户端域名解析配置3. 给网卡配多个IP4. ip地址查看和设置4.1 ifconfig命令4.2 ip命令4.3 ip命令:查看和设置网络配置4.4 ip命令帮助 5. 路由5.1 路由功能分类:5.2 查看路由:5.3 路由表:5.…...

9个神奇免费AI编程助手,实现高效自动代码生成!
在AIGC技术工具快速发展的时代,对高效智能编程工具的需求和关注已达到空前的高度。本文将介绍9款免费且好用的AI编程助手工具。无论你是经验丰富的开发人员还是刚开始编程旅程的新手,这些AI代码软件都能帮助你提高项目开发的生产力、创造力和准确性&…...

Python 导入Excel三维坐标数据 生成三维曲面地形图(体) 5-3、线条平滑曲面且可通过面观察柱体变化(三)
环境和包: 环境 python:python-3.12.0-amd64包: matplotlib 3.8.2 pandas 2.1.4 openpyxl 3.1.2 scipy 1.12.0 代码: import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from scipy.interpolate import griddata fro…...
ES6从入门到精通:前言
ES6简介 ES6(ECMAScript 2015)是JavaScript语言的重大更新,引入了许多新特性,包括语法糖、新数据类型、模块化支持等,显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

Razor编程中@Html的方法使用大全
文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

Windows电脑能装鸿蒙吗_Windows电脑体验鸿蒙电脑操作系统教程
鸿蒙电脑版操作系统来了,很多小伙伴想体验鸿蒙电脑版操作系统,可惜,鸿蒙系统并不支持你正在使用的传统的电脑来安装。不过可以通过可以使用华为官方提供的虚拟机,来体验大家心心念念的鸿蒙系统啦!注意:虚拟…...

【java面试】微服务篇
【java面试】微服务篇 一、总体框架二、Springcloud(一)Springcloud五大组件(二)服务注册和发现1、Eureka2、Nacos (三)负载均衡1、Ribbon负载均衡流程2、Ribbon负载均衡策略3、自定义负载均衡策略4、总结 …...