【落羽的落羽 C语言篇】一些常见的字符函数、字符串函数、内存函数

在这里插入图片描述

文章目录

  • 一、字符函数
    • 1. 字符分类函数
    • 2. 字符转换函数
  • 二、字符串函数
    • 1. strlen的使用和模拟实现
      • 使用
      • 模拟实现
    • 2. strcpy的使用和模拟实现
      • 使用
      • 模拟实现
    • 3. strcat的使用和模拟实现
      • 使用
      • 模拟实现
    • 4. strcmp的使用和模拟实现
      • 使用
      • 模拟实现
    • 5. strncpy的使用
    • 6. strncat的使用
    • 7. strncmp的使用
    • 8. strstr的使用和模拟实现
      • 使用
      • 模拟实现
    • 9. strchr的使用
    • 10. strrchr的使用
    • 11. strtok的使用
    • 12. strerror的使用
  • 三、内存函数
    • 1. memcpy的使用和模拟实现
      • 使用
      • 模拟实现
    • 2. memmove的使用和模拟实现
      • 使用
      • 模拟实现
    • 3. memset的使用
    • 4. memcmp的使用

一、字符函数

1. 字符分类函数

C语言中有一些库函数是专门用来分类字符的,这些函数的使用都需要包含头文件ctype.h

函数检测类型
iscntrl任何控制字符
isspace空白字符:包括空格’ ‘,回车’\r’,换行’\n’等
isdigit十进制数字:0到9
isxdigit十六进制数字:0到9,a到f,A到F
islower小写字母:a到z
isupper大写字母:A到Z
isalpha字母:a到z,A到Z
isalnum字符或数字:a到z,A到Z,0到9
ispunct标点符号:不属于字符和数字的可打印图形字符
isgraph所有图形字符
isprint所有可打印字符,包括图形字符和空白字符

注意:这些函数的传参实际上都是字符的ASCII值,参数是int类型
这些函数的使用方法几乎相同,我们就以isdigit为例讲解,它的定义是:

int isdigit(int c)

在使用时,如果isdigit的参数是一个十进制数,那么函数的返回值就是非0的整数;如果不是十进制数,返回值就是0。
上面其他的函数都是这个道理,如果参数是是它们对应的检测类型,函数的返回值是非0的整数(真),反之则是0(假)。

举个栗子吧,利用函数islower,将一个字符串中的小写字母转换成大写字母:

#include<stdio.h>
#include<ctype.h>
int main()
{
char s[10] = {'\0'};
gets(s);
for(int i=0 ; s[i]!='\0' ; i++){if(islower(s[i]))s[i]-=32;}
puts(s);
return 0;
}

在这里插入图片描述
非常好理解!

2. 字符转换函数

在ctype.h头文件中,还有两个函数tolower、toupper,用于转换字符。
函数tolower能把参数的大写字母转换成小写字母并返回,函数toupper能把参数的小写字母转换成大写字母并返回。(它们的参数和返回值都是ASCII的形式,也就是int类型)
如果toupper的参数不是小写字母,tolower的参数不是大写字母,那么返回值还是原来的字符(的ASCII值)

还是上面的例子,将一个字符串中的小写字母转换成大写字母。刚才我们先用islower判断小写字母再减32。但这时,我们就可以直接用toupper达到这个效果:

#include<stdio.h>
#include<ctype.h>
int main()
{
char s[10] = {'\0'};
gets(s);
for(int i=0 ; s[i]!='\0' ; i++)s[i] = toupper(s[i]);
puts(s);
return 0;
}

结果也是正确的
在这里插入图片描述

二、字符串函数

我们在编程或做题时经常与字符串打交道,因此掌握一些字符串相关的库函数是必不可少的。以下这些函数,都包含在头文件string.h中。对于一些重要的函数,很多企业在笔试时都会考察它们的模拟实现(关于模拟实现是什么,请见《指针·之其五》),所以我们也应该掌握。

1. strlen的使用和模拟实现

使用

在这里插入图片描述strlen的返回值是字符串str的长度(字符个数),它从指针str开始计数,以\0为字符串的结束标志。注意:strlen的返回类型size_t是无符号的,如果有表达式strlen(s1) - strlen(s2),不论s1和s2谁长谁短,结果都是无符号数(非负数)

模拟实现

  • 思路1:最简单的遍历计数
int Mine_strlen(const char* str)
{int count=0;assert(str);//防止str是空指针while(*str!='\0'){count++;str++;}return count;
}
  • 思路2:利用递归的思想计数
int Mine_strlen(const char* str)
{assert(str);if(*str=='\0')return 0;elsereturn 1+Mine_strlen(str+1);
}
  • 思路3:利用“指针 - 指针 = 两者间元素个数”的原理计数
int Mine_strlen(const char* str)
{assert(str);char* str1 = str;while(*str1!='\0')str1++;return str1-str;
}

2. strcpy的使用和模拟实现

使用

在这里插入图片描述

strcpy的功能是“拷贝字符串”,它能将source指向的字符串(包括其结尾的\0)拷贝到destination指向的内容。也就是说,这个函数修改的是destination指向的字符串的内容。它的使用要点是源字符串必须以\0结尾,目标空间必须可修改,而且要有足够大以确保能容纳的下源字符串。
举个栗子:

#include<stdio.h>
#include<string.h>
int main()
{char s1[] = "xxxxxxx";char s2[] = "abc";strcpy(s1,s2);printf("%s\n",s1);//这两句也可以直接写成printf("%s\n",strcpy(s1,s2));(链式访问)return 0;
}

s2中的“a”、“b”、“c”、“\0”都会被拷贝到s1中,替换掉s1的前四个字符,s1的内容变成了“abc\0xxx\0”,而s2的内容是不变的。%s打印s1,结果是abc
在这里插入图片描述

模拟实现

思路:遍历source字符串,一个一个赋值

char* Mine_strcpy(char* destination,const char* source)
{assert(destination&&source);char* ret = destination;while(*(destination++) = *(source++));return ret;
}

3. strcat的使用和模拟实现

使用

在这里插入图片描述strcat的功能是“连接字符串”,它会将source字符串连接到destination字符串之后,本质上是用源字符串的内容替换目标字符串结尾的\0。也就是说,这个函数修改的是destination字符串的内容。它的使用要点是:目标空间中必须有\0,目标空间必须足够大能容纳的下源字符串的内容,目标空间必须可修改。
举个栗子:

#include<stdio.h>
#include<string.h>
int main()
{char s1[20] = "Genshin";char s2[] = " Impact";strcat(s1,s2);printf("%s\n",s1);return 0;
}

在这里插入图片描述

模拟实现

思路:先找到目标字符串的结尾,再一个一个赋值

char* Mine_strcat(char* destination,const char* source)
{assert(destination&&source);char* ret = destination;while(*destination!='\0')destination++;while(*(destination++) = *(source++));return ret;
}

4. strcmp的使用和模拟实现

使用

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

strcmp能比较两个字符串:str1大于str2,则返回大于0的数字;str1等于str2,则返回0;str1小于str2,则返回小于0的数字。
那么如何比较两个字符串的大小呢?不是根据字符串的长度,而是依次比较相应位置上字符的ASCII值。例如,str1是abcdef,str2是abq,比较第一个字符,ASCII值相同;比较第二个字符,ASCII值相同;比较第三个字符,str2的q比str1的c的ASCII值大。所以str2就比str1大。

模拟实现

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

在这里插入图片描述

strcpy、strcat、strcmp、strncpy、strncat、strncmp在VS中使用时,可能会不安全而报错,在函数名之后加上_s就行。
刚才我们学习的strcpy、strcat、strcmp函数,都是针对长度不受限制的字符串使用的,可能不太安全。所以有时候,我们不会操作整个字符串,而要限制字符数。对此就要使用以下三个函数strncpy、strncat、strncmp。

5. strncpy的使用

在这里插入图片描述

strncpy也是用来拷贝字符串的,它的使用要求几乎和strcpy相同。但它不像strcpy只能将source字符串整个拷贝过去,它可以规定拷贝的字符个数,也就是参数部分的size_t num。当然,如果num超过了str2本身的长度,str2的全部内容都会拷贝过去。
举个栗子:

#include<string.h>
#include<stdio.h>
int main()
{char str1[] = "xxxxxxx";char str2[] = "abcdef";strncpy(str1,str2,3);printf("%s\n",str1);return 0;
}

在这里插入图片描述

6. strncat的使用

在这里插入图片描述

这也很好理解了,strncat的使用和strcat几乎相同,都是连接字符串的,但strncat还可以规定把str2的几个字符连接过去。当然,如果num超过了str2本身的长度,str2的全部内容都会连接过去。
举个栗子:

#include<string.h>
#include<stdio.h>
int main()
{char str1[20] = "honkai ";char str2[20] = "railstarxxxxxxx";strncat(str1,str2,8);printf("%s\n",str1);return 0;
}

在这里插入图片描述

7. strncmp的使用

在这里插入图片描述

同样地,相较于strcmp,strncmp可以规定比较前几个字符。从第一个开始比较,如果相同就继续往后比较,最多比较num个字符。如果都想等,就返回0。
在这里插入图片描述

8. strstr的使用和模拟实现

使用

在这里插入图片描述

strstr能够找到str2在str1中第一次出现的位置,字符串的比较匹配不包含\0字符,以\0字符作为结束标志。如果能够在str1中找到str2,就返回str2第一次出现的位置(地址);如果找不到,就返回空指针NULL。
举个栗子:

#include<string.h>
#include<stdio.h>
int main()
{char str1[] = "honkai railstar";char str2[] = "kai";char* p = strstr(str1,str2);printf("%d\n", p-str1);return 0;
}

在这里插入图片描述

模拟实现

char* Mine_strstr(char* str1, const char* str2)
{assert(str1&&str2);const char* cur = str1;//开始匹配的位置const char* s1 = NULL;//遍历str1const char* s2 = NULL;//遍历str2while(*cur!='\0'){s1 = cur;s2 = str2;while((*s1!='\0')&&(*s2!='\0')&&(*s1==*s2))//依次比较str2和str1中的字符{s1++;s2++;}if(*s2=='\0')//如果str2的每个字符都匹配成功,就是在str1中找到了str2return cur;cur++;}return NULL;
}

9. strchr的使用

在这里插入图片描述

strchr很简单,它能找到一个字符在一个字符串中第一次出现的位置并返回,如果找不到就返回空指针NULL。
举个栗子:

#include<string.h>
#include<stdio.h>
int main()
{char str1[] = "honkai railstar";char* p = strchr(str1,'k');printf("%d\n", p-str1);return 0;
}

在这里插入图片描述

10. strrchr的使用

在这里插入图片描述
strrchr也是查找一个字符串中的特定字符,但它返回的是这个字符在字符串中最后一次出现的位置,如果找不到就返回空指针NULL。值得注意的是,指定字符的参数是int类型。
举个例子:

#include<string.h>
#include<stdio.h>
int main()
{char str1[] = "abcda";char* p = strrchr(str1,'a');printf("%d\n", p-str1);return 0;
}

在这里插入图片描述

11. strtok的使用

strtok函数的使用较为特殊
在这里插入图片描述

简单来说,strtok的作用是分割字符串,它的使用形式是char* strtok(char* str, char* sep);。其中str是待分割的字符串,而sep是当做分隔符的字符的数组。在使用时,函数会从左向右读取字符串str,遇到第一个分隔符时,会把它变成\0,然后返回str的起始位置。所以这个函数会改变str的内容,在实际使用时我们常常将原字符串复制一份再分割。
比如我们假设:

char str[] = "abcxdef.ghi@jkl";
char sep[] = "@x.";
char* p = strtok(str,sep);

此时%s打印p,结果是abc,因为str的x变成了\0。

但倘若我们再用一次strtok,但第一个参数设成NULL,则函数会从上一次分隔符的出现的地方开始读取,再寻找分隔符,也就是从d开始读取,直到找到了“.”,设置成\0返回d的地址。而如果函数往后读取到结束都找不到分隔符了,就返回空指针NULL。

在这里插入图片描述

12. strerror的使用

在这里插入图片描述

在不同的系统和C语言标准库中,都规定了一些错误码,一般放在了errno.h这个头文件说明,C语言程序启动时会使用一个全局的变量errno来记录程序当前的错误码。程序启动时errno是0,表示没有错误。每一个错误码都对应一种运行错误,当我们在使用标准库中的函数时发生了某种错误,就会将对应的错误码数储存在中errno中。strerrno的参数部分就是错误码,他可以将对应的错误信息字符串地址返回。
比如我们在Windows11的VS2022环境下看一看1到10对应的错误信息都是什么?

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{for(int i=1 ; i<=10 ; i++)printf("%s\n",strerror(i));return 0;
}

在这里插入图片描述

除此之外,在stdio.h头文件中还有一个函数perror,也可以了解一下
在这里插入图片描述perror函数相当于结合了printf和strerror函数,它先打印出它的参数指向的字符串,再打印一个“:”,再打印出变量errno储存的错误码对应的错误信息字符串。
例如:

#include<stdio.h>
#include<errno.h>
int main()
{//这个程序没有错误,errno是0,对应的错误信息是“No error”perror("Is there an error");return 0;
}

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

三、内存函数

C语言的指针是其精髓之一,而指针和内存千丝万缕。所以我们也应该掌握一些与内存相关的函数。以下函数也包含在string.h头文件中。

1. memcpy的使用和模拟实现

使用

在这里插入图片描述
函数memcpy会从source的位置开始向后拷贝num个字节的数据到destination指向的内存位置,这个函数在遇到\0前不会停止拷贝。如果source和destination有内存重叠的部分,那么函数是无法保证运行结果的,比如

int a[5]={1,2,3,4,5};
memcpy(a+2, a, 3*sizeof(int));

我们不知道3是先拷贝到a[4]的位置再变成了1,或是3先变成了1再拷贝到a[4]的位置。运行后a中可能变成1,2,1,2,3,也可能变成1,2,1,2,1。所以我们就不要用memcpy处理内存有重叠的两块区域了,而可以用memmove来实现。

模拟实现

思路:一个字节一个字节地拷贝

void* Mine_memcpy(void* destination, const void* source, size_t num)
{assert(destination&&source);void* ret = destination;while(num--){*(char*)destination = *(char*)source;destination=(char*)destination+1;source=(char*)source+1;}return ret;
}

2. memmove的使用和模拟实现

使用

在这里插入图片描述memmove和memcpy的作用完全相同,差别就是memmove函数处理的源空间和目标空间可以重叠。使用memmove就可以将被拷贝数据完整地拷贝过去,不会出现某些数据被拷贝前就被修改的情况了。

int a[5]={1,2,3,4,5};
memmove(a+2, a, 3*sizeof(int));

这样,a中一定是1,2,1,2,3

int a[5]={1,2,3,4,5};
memmove(a, a+2, 3*sizeof(int));

这样,a中一定是3,4,5,4,5

模拟实现

思路:为了防止被拷贝数据被覆盖,分成两种情况,从后向前依次拷贝,或是从前向后依次复制

void* Mine_memmove(void* destination, const void* source, size_t num)
{assert(destination&&source);void* ret = destination;if(destination<source){while(num--){*(char*)destination = *(char*)source;destination = (char*)destination+1;source = (char*)source+1;}}else{while(num--)*((char*)destination+num) = *((char*)source+num);}return ret;
}

3. memset的使用

在这里插入图片描述
memset是用来设置内存的,可以将内存中的值以字节为单位设置成想要的内容。它可以把ptr指向的内存的前num个字节设置成给定的value值。
举个栗子:

#include<stdio.h>
#include<string.h>
int main()
{char str[] = "abcde";memset(str, 'x', 3);printf("%s\n",str);return 0;
}

在这里插入图片描述

4. memcmp的使用

在这里插入图片描述
memcmp能比较ptr1和ptr2指针指向的位置开始向后的num个字节,返回值的规则和strcmp类似
在这里插入图片描述

这里就不再举例子赘述了(我也累了~)

在这里插入图片描述

本篇完,感谢阅读

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序-基于java+SSM+Vue的微信阅读小程序设计与实现

项目运行 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…

Airborne使用教程

1.安装环境 前提条件&#xff1a;系统已安装Ruby 打开终端输入如下命令 gem install airborne 或者在Gemfile添加 gem airborne 然后运行bundle install 2.编写脚本 在项目中新建api_tests_spec.rb文件 以GET接口"https://www.thunderclient.com/welcome"为…

社区生活超市系统|Java|SSM|JSP|

【技术栈】 1⃣️&#xff1a;架构: B/S、MVC 2⃣️&#xff1a;系统环境&#xff1a;Windowsh/Mac 3⃣️&#xff1a;开发环境&#xff1a;IDEA、JDK1.8、Maven、Mysql5.7 4⃣️&#xff1a;技术栈&#xff1a;Java、Mysql、SSM、Mybatis-Plus、JSP、jquery,html 5⃣️数据库可…

零基础开始学习鸿蒙开发-基础页面的设计

目录 1.样例图 2.逐项分析 2.1 头顶布局分析&#xff1a;首先我们要把第一行的图标绘制出来&#xff0c;一个左一个右&#xff0c;很明显&#xff0c;需要放在一个Row容器中&#xff0c;具体代码如下&#xff1a; 2.2 和头像同一行的布局&#xff0c;需要注意的是&#xff0c…

211-基于FMC的1路1.5G ADC 1路 2.5G DAC子卡

一、板卡概述 FMC-1AD-1DA-1SYNC是我司自主研发的一款1路1G AD采集、1路2.5G DA回放的FMC、1路AD同步信号子卡。板卡采用标准FMC子卡架构&#xff0c;可方便地与其他FMC板卡实现高速互联&#xff0c;可广泛用于高频模拟信号采集等领域。 二、功能介绍 2.1 原理框图 2.2 硬件…

HTML综合案例

这是一个HTML CSS的综合练习案例&#xff0c;效果如图所示&#xff1a; HTML代码&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-w…

NPU是什么?电脑NPU和CPU、GPU区别介绍

随着人工智能技术的飞速发展&#xff0c;计算机硬件架构也在不断演进以适应日益复杂的AI应用场景。其中&#xff0c;NPU&#xff08;Neural Processing Unit&#xff0c;神经网络处理器&#xff09;作为一种专为深度学习和神经网络运算设计的新型处理器&#xff0c;正逐渐崭露头…

【多线程】synchronized使用以及原理详解

1. synchronized关键字的使用 synchronized关键字是对Java中的对象加锁&#xff0c;主要有3种使用形式 修饰实例&#xff08;普通&#xff09;方法 &#xff0c;锁的是当前的实例对象&#xff1b;修饰静态方法&#xff0c;锁的是当前类的Class对象&#xff0c;即使是不同的示…

项目开发实践——基于SpringBoot+Vue3实现的在线考试系统(二)

文章目录 一、登录功能实现1、前端实现1.1 创建登录组件1.2 安装和配置Element Plus1.3 安装axios和调用后端接口2、后端实现2.1 创建数据表和准备数据2.2 配置MYSQL配置信息2.3 登录功能实现2.3.1 创建实体类2.3.2 创建登录服务接口及实现2.3.3 创建Mapper2.3.4 实现登录接口A…

ESP32-S3-devKitC-1 点亮板上的WS2812 RGB LED

ESP32-S3-devKitC-1 板上自带了一个RGB LED&#xff0c;型号为 WS2812。 RGB LED 在板上的位置如下图所示。 为了点亮这个WS2812&#xff0c;需要确定这颗RGB LED连接到哪个GPIO上了。 下面是确定GPIO管脚的过程&#xff1a; 1、根据原理图 2、根据PCB布局图&#xff1a; 程…

汽车电子元件的可靠性保障:AEC-Q102认证

AEC-Q102标准的起源与价值 随着汽车电子系统的日益复杂&#xff0c;电子器件必须能够在极端的温度、湿度、振动和电磁干扰等恶劣条件下保持性能。AEC-Q102标准由汽车电子委员会&#xff08;AEC&#xff09;制定&#xff0c;专门针对LED、激光二极管和光电二极管等光电器件&…

SQL中的联结表

本文介绍什么是联结&#xff0c;为什么使用联结&#xff0c;以及如何编写使用联结的SELECT语句。 1. 联结 SQL最强大的功能之一就是能在数据查询的执行中联结&#xff08;join&#xff09;表。联结是SQL的SELECT能执行的最重要的操作&#xff0c;理解联结及其语法是学习SQL的…

每天40分玩转Django:实操 Todo List应用

实操 Todo List应用 一、今日学习内容概述 学习模块重要程度预计学时主要内容项目初始化⭐⭐⭐⭐0.5小时创建项目、配置环境模型设计⭐⭐⭐⭐⭐1小时Todo模型设计与实现CRUD视图⭐⭐⭐⭐⭐2小时实现增删改查功能模板开发⭐⭐⭐⭐1.5小时页面布局与交互设计功能测试⭐⭐⭐1小时…

Freertos任务切换

一、操作系统进行任务切换的时机&#xff1a; 采用信号量实现任务的互斥&#xff1a; 二、FreeRTOS 任务切换场合 PendSV 中断的时候提到了上下文(任务)切换被触发的场合&#xff1a; ● 可以执行一个系统调用 ● 系统滴答定时器(SysTick)中断。 1、执行系统调用 执行系统…

【Linux】自定义项目-进度条

更多精彩内容..... &#x1f389;❤️播主の主页✨&#x1f618; Stark、-CSDN博客 准备工作&#xff1a;"\r"与"\n"字符 ①&#xff1a;基本含义 在C语言和Linux环境中&#xff0c;\r是回车符&#xff0c;\n是换行符&#xff0c;用于控制文本格式和输出…

【ubuntu24.04】PDFMathTranslate 本地PDF翻译GPU部署

https://huggingface.co/spaces/reycn/PDFMathTranslate-Docker排不上号官方都是要安装包,感觉可以本地试着源码部署一下, http://localhost:7860/官方是这个端口,但是我本地启动是:5000IDEA 里本地 backend启动效果 GUI 是监听7860的

基于卷积神经网络的垃圾分类系统实现(GUI应用)

1.摘要 本文主要实现了一个卷积神经网络模型进行垃圾图像分类&#xff0c;为了提高垃圾分类模型的准确率&#xff0c;使用使用Batch Normalization层、使用早期停止策略来防止过拟合等方法来优化模型&#xff0c;实验结果显示最终优化后的模型准确率较高90%左右。最终&#xf…

Vulnstack红日安全内网域渗透靶场2实战攻略

一&#xff1a;环境搭建 新增的网卡VMnet2&#xff0c;ip调成10段。 PC配置如下&#xff1a; DC在该环境中充当是域控。DC配置如下 &#xff1a; WEB配置&#xff1a;需要两块网卡&#xff0c;相当于网关服务器。 作者把外网网段都写成了192.168.111.1/24&#xff0c;我们可以…

Http协议在网站中的体现

文章目录 1. Http协议简介2. 网站中的体现2.1 访问网站2.2 请求2.3 请求头2.4 请求方式2.5 响应 3. 总结 1. Http协议简介 HTTP&#xff08;超文本传输协议&#xff09; 是一种广泛应用于互联网上的应用层协议&#xff0c;用于在Web浏览器和Web服务器之间传输数据。HTTP协议定…

JavaWeb——前端三剑客

前言&#xff1a;今天开始学习JavaWeb相关内容了&#xff0c;陆续会总结一些前后端分离开发的相关知识&#xff0c;有遗漏和错误的地方欢迎大家指出~ 目录 一、前端三剑客二、HTML2.1 HTML介绍2.2 常用标签 三、 CSS3.1 CSS介绍3.2 CSS引用的三种形式3.3. CSS选择器及其类型3.…