字符函数与字符串函数

目录

 一.字符分类函数

二.字符转化函数 

三.strlen函数 

函数的介绍

strlen函数的模拟实现

1.计算器法

2.递归 

三.指针-指针的方式 

 四.strcpy函数

 函数介绍

strcmp的模拟实现

五.strcat函数 

函数介绍

strcat的模拟实现

六.strcmp函数

函数介绍 

返回值

strcmp函数的模仿实现

七.strncpy,strncat,strncmp函数 

(1)strncpy 

(2)strncat

(3)strncmp函数

注意事项

八.strstr函数

函数的介绍

返回值

strstr函数的模拟实现

九.strtok函数

 十.strerror函数

错误码

perror函数


 

 一.字符分类函数

C语言中有一系列函数是专门做字符分类的,也就是一个字符是属于什么类型的字符的。

这些函数的使用都需要包含一个头文件是ctype.h

函数作用
isalnum检查一个字符是否是字母或数字
isalpha检查一个字符是否是字母
islower检查一个字符是否是小写字母
isupper检查一个字符是否是大写字母
isdigit检查字符是否为数字
isxdigit检查一个字符是否是十六进制的字符
iscntrl检查一个字符是否是控制字符
isgraph

检查一个字符是否是图形字符

isspace检查一个字符是否是空白字符
isblank检查一个字符是否是空格字符
isprint检查一个字符是否是可打印字符
ispunct检查一个字符是否是标点字符

参考网址: 空终止字节字符串 - cppreference.comicon-default.png?t=N7T8https://zh.cppreference.com/w/c/string/byte

#include<ctype.h>
#include<stdio.h>
int main()
{int ret = isalnum('a');printf("%d",ret);return 0;
}

 这些函数的的参数都是是int类型的,即使我们传过去的是字符,但是其实是根据它的ASCII值进行计算的。返回类型是int,如果是就会返回一个非零的数字,比如上述代码返回值就是2.(这可能有所差异),但一定是非零值,如果不是上述的所有函数都会返回0.

练习:写一个代码将字符串中的小写转化为大写,其他字符不变。

int main()
{char str[] = { "Hello World!" };int i = 0;char c;while (str[i]) {c = str[i];if (islower(c)) {c -= 32;}i++;putchar(c);}
}

 这里-32的原因是因为ASCII值中a的值是97,A的值是65,也就是所小写字母减32就是大写字母。通过这一点我们就可以知道如何进行大小写的转化。

二.字符转化函数 

ctype:<cctype> (ctype.h) - C++ Reference

 字符转化函数只有两种;

函数功能
toupper将小写字符转化为大写的
tolower将大写字符转化为小写的

这两个函数的参数也是int 返回值也是int,返回值返回的就应该是该字符对应ASCII值。

如果这个字符无法转化,就只会返回原字符。

所以上述的题目就可以改写为: 

int main()
{char str[] = { "Hello World!" };int i = 0;char c;while (str[i]) {c = str[i];if (islower(c)) {c = toupper(c);}i++;putchar(c);}
}

注意传递的参数只能是一个字符,而不能是字符串 

三.strlen函数 

函数的介绍

 函数原型:

size_t strlen(const char* str);

函数功能是返回字符串的长度。字符串的长度是有'\0'字符决定,它之前的字符个数就是字符串的长度。C字符串的长度等于字符串开头和'\0'字符之间的字符数.

注:字符串长度是不包括'\0'的

 注意字符串的长度是与包含字符串的数组的大小不一样的。

int main()
{char str[] = "abcdef";return 0;
}

通过调试,我们可以发现,这个数组的类型是char[7]说明这个数组大小是7,但是字符串的长度是6。

所有我们如果给【】中加上值,这个值的大小至少要是7,不能比7小不如就存不下这个字符串。

那么多余的值就会被初始化为'\0'.

字符串以'\0'作为结束的标志,strlen返回的是'\0'之前的字符个数,不包含'\0'.

注意函数的返回值是size_t类型的是无符号的。

strlen的使用需要包含头文件<string.h>

strlen函数的模拟实现

1.计算器法

#include<assert.h>
#include<stdio.h>
size_t my_strlen(const char* str)
{int count = 0;assert(str);while (*str) {count++;str++;}return (size_t)count;
}

2.递归 

size_t my_strlen(const char* str)
{assert(str);if (*str == '\0')return 0;elsereturn 1 + my_strlen(str++);
}

递归相比其他的方法是没有创建临时变量。 

三.指针-指针的方式 

回顾:指针减指针得到的是指针之间的元素个数+1,比如第五个字符的地址-第一个字符的地址就是4(中间有三个元素+1);

size_t my_strlen(const char* str) {assert(str);char* start = str;while (*str != '\0') {str++;}return str - start;
}

注意这里必须是高地址减低地址,不然就是负数了。 

 四.strcpy函数

 函数介绍

strcpy是用于字符串拷贝的,第一个参数destination是目的地的地址,而第二个参数是源头的地址。

#include<stdio.h>
#include<string.h>
int main()
{char dest[10] = "abc";char* source = "abcdef";strcpy(dest,source);printf("%s",dest);return 0;
}

这样我们就把source所指向的字符串成功复制到了dest字符数组中。

注意事项:

  1. 字符串在拷贝的过程中是包含字符'\0'的,而且会在这个字符停止拷贝。也就是所源字符串必须以'\0'结尾。
  2. 为了避免溢出,目标空间必须足够大,要确保能完整存放源字符串。
  3. 目标空间必须能够修改。
  4. 目标空间在内存上不能与源字符串相互重叠。

返回值是目标空间的地址。 

strcmp的模拟实现

#include<stdio.h>
#include<string.h>char* my_strcpy(char* destination,const char* source)
{char* ret = destination;while (*source){*destination++ = *source++;}*destination = *source;//最后将'\0'复制return ret;
}
int main()
{char dest[10] = "abcxxxxxxx";char* source = "abcdef";my_strcpy(dest,source);printf("%s",dest);return 0;
}

简化一下:

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

五.strcat函数 

函数介绍

strcat这个函数是用于字符串附加的,将source所指向的字符串附加到destination的末尾。

int main()
{char dest[20] = "hello ";char* source = "world!";strcat(dest,source);printf("%s",dest);return 0;
}

也就是将source的字符串链接在dest的后面。我们知道字符串的末尾是有一个隐藏的'\0'的,但是这里还是打印出了world!,说明在使用strcat进行附加的时候,末尾的'\0'是已经被覆盖了的。

注意事项:

  1. destination所指向的字符串最后的'\0'字符被source所指向的字符串的第一个字符覆盖了。
  2. 这个新的字符串末尾是含有'\0'的。
  3. 目标空间必须足够大,要能容纳新的字符串。
  4. destination和source所指向的空间在内存上不能重叠,否则运行结果是未知的。

返回值的是destination的起始地址。

strcat的模拟实现

 首先我们需要先找到目标字符末尾的'\0'字符,然后进行拷贝。

#include<stdio.h>
#include<string.h>
char* my_strcat(char* destination,const char* source)
{char* ret = destination;while (*destination)destination++;while (*destination++ = *source++);return ret;
}
int main()
{char dest[20] = "hello ";char* source = "world!";my_strcat(dest,source);printf("%s",dest);return 0;
}

六.strcmp函数

参考网址:strcmp - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/cstring/strcmp/?kw=strcmp

函数介绍 

int strcmp(const char* str1, const char* str2);

This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ or until a terminating null-character is reached.This function performs a binary comparison of the characters.

这个函数是用于比较两个字符串的。这个函数首先会比较两个字符串的首字符,如果相同,这个函数就会继续比较下一对字符,直到遇到不同的字符或者'\0'.这个函数的执行的是二进制的比较。

返回值

情况1: 

"abc"//str1
"abf"//str2

这两个字符串的前两个字符相同,而第三个字符不同,c的ASCII值小于f的ASCII值。所以strcmp会返回一个小于0的整形。

 情况2:

"abc"//str1
"abc"//str2

这两个字符串一模一样,这样就会strcmp就会返回一个0。

情况3:

"abc"//str1
"abb"//str2

这两个字符串的前两个字符相同,而第三个字符不同,c的ASCII值大于b的ASCII值。所以strcmp会返回一个大于0的整形。 

情况4:

"abc"//str1
"aaz"//str2

 这两个字符串的第一个字符相同,而第二个字符str1大于str2,这时候返回一个大于0的整形。第三个字符就不会进行比较了。

strcmp函数的模仿实现

#define _CRT_SECURE_NO_WARNINGS 
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);int ret = 0;while (*str1 == *str2){if (*str1 == '\0'){return 0;}str1++;str2++;}return *str1 - *str2;
}
int main()
{char* str1 = "abc";char* str2 = "aaz";printf("%d",my_strcmp(str1,str2));return 0;
}

七.strncpy,strncat,strncmp函数 

这三个函数与上面所讲的三个函数非常的相似,从函数民上我们发现只多了一个n字母。

那么实际上他们有什么区别呢?

char* strncpy(char* destination, const char* source, size_t num);
char* strncat(char* destination, const char* source, size_t num);
int strncmp(const char* str1, const char* str2, size_t num);

从他们的参数上来看,我们发现只多了一个size_t类型的参数num,也就是函数名中多的n。

那么这个num到底有什么用呢?

(1)strncpy 

对于strncpy来说,这个num就是用于指定字数的字符串拷贝。

int main()
{char dest[20] = "xxxxxxxxxxhello ";char* source = "world!";strncpy(dest,source,5);printf("%s",dest);return 0;
}

打印结果:

仔细观察发现source中的感叹号并没有复制到dest字符中。也就是只复制了source的前五个字符。所以这个num就是给我们来控制想复制的字符个数的。

如果num的值大于source所指向的字符串的长度 。会在拷贝完字符串后,在'\0'的后面一直追加0,直到满足num个字符。

模拟实现

#include<stdio.h>
char* my_strncpy(char* destination, const char* source, size_t num)
{char* ret = destination;for (int i = num; i > 0; i--){if (*source) {*destination = *source;}else {*destination = '\0';}destination++;source++;}return ret;
}
int main()
{char str1[20] = "xxxxx world!!!";char* str2 = "hello";printf("%s\n", str1);my_strncpy(str1,str2,7);printf("%s",str1);return 0;
}

(2)strncat

这个函数同理,num也是用于控制附加的个数的。

int main()
{char dest[20] = "hello ";char* source = "world!";strncat(dest,source,5);printf("%s",dest);return 0;
}

 虽然我们只附加了五个字符,这个是并没有包含'\0'的,所以这个函数会自动在新字符串的末尾补上斜杠零。

strcat的模拟实现

char* my_strncat(char* destination, const char* source, size_t num)
{char* ret = destination;while (*destination){destination++;}for (int i = 0; i < num; i++){if (*source) {*destination = *source;}else{*destination = '\0';}destination++;source++;}return ret;
}
int main()
{char str1[20] = "hello ";char* str2 = "world!!!";printf("%s\n", str1);my_strncat(str1, str2, 7);printf("%s", str1);return 0;
}

(3)strncmp函数

这个函数也是,num控制比较的个数。只比较前num个字符,其他均与strcmp一样

注意事项

这六个函数的目标字符串和源字符串都不能在内存上有任何重叠,不然运行结果是未知的,可能复合要求,也可能不符合,这与编译器有关。

八.strstr函数

函数的介绍

参考网址:strstr - C++ Reference

char * strstr (const char * str1, const char * str2 );

 这个函数是用于在一个字符串中查找是否具有另一个字符串。

返回值

这个函数的返回值是str1中具有str2字符串的首字符的地址。

比如:"abcdef"和"cdef".返回值就是“abcdef”中字符C的地址。

如果没有找到,就会返回NULL.

strstr函数的模拟实现

#include<stdio.h>
#include<string.h>
char* my_strstr(const char *str1,const char*str2)
{if (!*str2)return (char*)str1;char* s1 = NULL;char* s2 = NULL;char* cur = (char*)str1;while (*cur){s1 = cur;s2 = (char*)str2;while (*s1 == *s2 && *s1 && *s2){s1++;s2++;}if (!*s2)return cur;cur++;}return NULL;
}
int main()
{char* str1 = "this is a string";char* str2 = "str";char * ret = my_strstr(str1,str2);printf("%s\n",ret);return 0;
}

九.strtok函数

char* strtok(char* str, const char* delimiters);

这个函数是用于字符串的分隔的。

str指针所指向的是一个需要分隔的字符串。

delimiters所指向的是分隔符的合集。

#include<stdio.h>
#include<string.h>
int main()
{char str[20] = "abc.hello_world/no";char* del = "._/";//第一次分隔char* first =  strtok(str,del);printf("%s\n",first);//第二次分隔char*second = strtok(NULL,del);printf("%s\n",second);//第三分隔char* third = strtok(NULL,del);printf("%s\n",third);return 0;
}

打印结果 

最终我们发现str这个字符数组被分割了,而这个del就是分隔符的合集。这个函数会根据分隔符合集中的每一个字符分割这个字符串,并在新的字符串结尾加上'\0',以免读取时造成溢出的问题。 

每一次调用这个函数只会分隔一次,并且返回初始地址,下一次调用的时候(如果还能进行分隔)只需要传NULL和分隔符。如果读取到了str中的‘\0’就会停止分隔了。并且后续如果继续调用,只会返回NULL.

我们也可以使用for循环的方式对分隔后的字符串进行打印。

#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;
}

 十.strerror函数

char* strerror(int errnum);

strerror函数可把参数部分错误码所对应的错误信息所对应的字符串的地址返回。

错误码

在不同的系统和C语言标准库中都规定了一些错误码,一般是放在<errno.h> 头文件中的,C语言程序的启动时候,就会使用一个全面的变量errno来记录程序的当前的错误码,只不过程序启动的时候errno是0,表示没有错误,当我们在使用标准库中的函数的时候发生了某种错误,就会将对应的错误码放在errno中,而一个错误码的数字是整数,这是比较难以理解的,所以每一个错误码都是由对应的错误信息的,strerror这个函数就是用于将错误码对应的错误信息对应的字符串地址返回。

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

 通过上面的代码我们就可以依次打印出错误信息了。

在Windows11和VS2022的环境下输出结果是:

举例:

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{FILE* pFile;pFile = fopen("unexist.ent", "r");if (pFile == NULL)printf("Error opening file unexist.ent: %s\n", strerror(errno));return 0;
}

 这个fopen就是用于打开文件的,后续我们会继续了解。

但是我们运行这串代码会发现给出的错误信息是:

这个错误信息的意思是:没有这样的文件或者文件夹,也就是我们打开文件失败了。

perror函数

#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{FILE* pFile;pFile = fopen("unexist.ent", "r");if (pFile == NULL)//printf("Error opening file unexist.ent: %s\n", strerror(errno));perror("Error opening file unexist.ent");return 0;
}

 我们也可以使用perror这个函数,这个函数会先打印这个参数部分的字符串,然后就是一个冒号和空格,最后是错误信息。

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

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

相关文章

每日一练:LeeCode-242、有效的字母异位词【数组+字符串】

给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 注意&#xff1a;若 s 和 t 中每个字符出现的次数都相同&#xff0c;则称 s 和 t 互为字母异位词。 示例 1: 输入: s "anagram", t "nagaram" 输出: true示例 2: 输…

网络工程师笔记15(OSPF协议-2)

OSPF协议 OSPF是典型的链路状态路由协议&#xff0c;是目前业内使用非常广泛的 IGP 协议之一。 Router-ID(Router ldentifier&#xff0c;路由器标识符)&#xff0c;用于在一个 OSPF 域中唯一地标识一台路由器。Router-ID 的设定可以通过手工配置的方式&#xff0c;或使用系统自…

MySQL 中的索引

MySQL 中的索引 一、索引的创建和删除1.主键会自动添加索引2.unique 约束的字段自动添加索引3.给指定的字段添加索引4.删除指定索引5.查询表上的索引 二、索引的分类三、MySQL索引采用了B树数据结构1.B树的经典面试题 四、其他索引及相关调优1.Hash索引2.聚集索引和非聚集索引3…

罗格朗逸景PLUS IOT智能系统发布,为您提供更智能的生活体验!

罗格朗全新推出的逸景PLUS IOT智能系统现已正式上市,采用纤薄纯平的设计,功能丰富全面,支持灯光/温度/场景控制、背景音乐等多种功能,整合罗格朗IOT2.0系统,集成可视对讲,为用户打造更舒适、安全的智能生活。 罗格朗智能家居 罗格朗是全球电气与智能建筑系统专家,创立于1865年…

苹果电脑不能删除移动硬盘文件 苹果电脑移动硬盘只读模式如何更改 移动硬盘文件或目录损坏且无法读取怎么办

当我们将移动硬盘插入苹果电脑后&#xff0c;发现无法对移动硬盘中的文件进行编辑该怎么办&#xff1f;相信有不少网友遇到过这类情况。苹果电脑不能删除移动硬盘文件&#xff0c;或无法拷贝硬盘里的文件。今天我为大家解决苹果电脑移动硬盘只读模式如何更改的问题&#xff0c;…

ETL的全量和增量模式

在当今信息爆炸的时代&#xff0c;数据管理已经成为各行各业必不可少的一环。而在数据管理中&#xff0c;全量与增量模式作为两种主要的策略&#xff0c;各自具有独特的优势和适用场景&#xff0c;巧妙地灵活运用二者不仅能提升数据处理效率&#xff0c;更能保障数据的准确性。…

政安晨:【深度学习实践】【使用 TensorFlow 和 Keras 为结构化数据构建和训练神经网络】(五)—— Dropout和批归一化

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 政安晨的机器学习笔记 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; Dropout和批归一化是深度学习领域中常用的正则化技术&…

如何使用人工智能和ChatGPT来优化营销转化率

人工智能 &#xff08;AI&#xff09; 和营销的交集正在彻底改变企业与客户互动的方式&#xff0c;最终改变营销转化率。人工智能能够分析大量数据、理解模式和自动执行任务&#xff0c;它不仅是一项创新技术&#xff0c;而且是营销领域的根本性转变。这种转变允许更加个性化、…

OCR研究背景及相关论文分享

光学字符识别&#xff08;Optical Character Recognition&#xff0c;OCR&#xff09;是指使用光学方法将图像中的文字转换为机器可编辑的文本的技术。OCR技术的研究和应用已有数十年的历史&#xff0c;其背景和发展受到多方面因素的影响。 技术需求背景 1.自动化文档处理&am…

SQLiteC/C++接口详细介绍sqlite3_stmt类(十)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;九&#xff09; 下一篇&#xff1a; SQLiteC/C接口详细介绍sqlite3_stmt类&#xff08;十一&#xff09; 38、sqlite3_column_value sqlite3_column_valu…

2023年蓝桥杯省赛——分糖果

目录 题目链接&#xff1a;12.分糖果 - 蓝桥云课 (lanqiao.cn) 思路 DFS解法 实现思路 代码实现 Java C 总结 题目链接&#xff1a;12.分糖果 - 蓝桥云课 (lanqiao.cn) 思路 第一眼是茫然的&#xff0c;第二眼是想枚举的&#xff0c;第三眼是发现要DFS 的&#xff0c;第…

python的stone音乐播放器的设计与实现flask-django-php-nodejs

该系统利用python语言、MySQL数据库&#xff0c;flask框架&#xff0c;结合目前流行的 B/S架构&#xff0c;将stone音乐播放器的各个方面都集中到数据库中&#xff0c;以便于用户的需要。该系统在确保系统稳定的前提下&#xff0c;能够实现多功能模块的设计和应用。该系统由管理…

ChatGPT无法登录,提示我们检测到可疑的登录行为?如何解决?

OnlyFans 订阅教程移步&#xff1a;【保姆级】2024年最新Onlyfans订阅教程 Midjourney 订阅教程移步&#xff1a; 【一看就会】五分钟完成MidJourney订阅 GPT-4.0 升级教程移步&#xff1a;五分钟开通GPT4.0 如果你需要使用Wildcard开通GPT4、Midjourney或是Onlyfans的话&am…

深度学习基础之《TensorFlow框架(10)—案例:实现线性回归(2)》

增加其他功能 一、增加变量显示 1、目的&#xff1a;在TensorBoard当中观察模型的参数、损失值等变量值的变化 2、收集变量 不同的变量要用不同的方式收集 &#xff08;1&#xff09;tf.summary.scalar(name, tensor) 收集对于损失函数和准确率等单值变量&#xff0c;name为…

macOS下Java应用的打包和安装程序制作

文章目录 macOS应用程序结构Java应用打包JavaAppLauncherjpackage其它相关JDK命令附录JavaAppLauncher源码链接macOS应用程序结构 macOS通常以dmg或pkg作为软件发行包,安装到/Applications下后,结构比较统一。 info.plist里的CFBundleExecutable字段可以指定入口,如果不指定…

Karmada 管理有状态应用 Xline 的早期探索与实践

背景与动机 目前随着云原生技术和云市场的不断成熟&#xff0c;越来越多的 IT 厂商开始投入到跨云多集群的怀抱当中。以下是 flexera 在 2023 年中关于云原生市场对多云多集群管理的接受程度的调查报告&#xff08;http://info.flexera.com&#xff09; 从 flexera 的报告中可…

Flutter Widget:StatefulWidgetStatelessWidgetState

Widget 概念 Widget 将是构建Flutter应用的基石&#xff0c;在Flutter开发中几乎所有的对象都是一个 Widget 。 在Flutter中的widget 不仅表示UI元素&#xff0c;也表示一些功能性的组件&#xff0c;如&#xff1a;手势 、主题Theme 等。而原生开发中的控件通常只是指UI元素。…

Microsoft Edge 中的 Internet Explorer 模式解决ie禁止跳转到edge问题

作为网工&#xff0c;网络中存在很老的设备只能用ie浏览器访问打开&#xff0c;但是win10后打开Internet Explorer 会强制跳转到Edge 浏览器&#xff0c;且有人反馈不会关&#xff0c;为此找到了微软官方的Microsoft Edge 中的 Internet Explorer 模式&#xff0c;可以直接在Mi…

【C语言】自定义类型:结构体

1、结构体类型的声明 struct tag { member - list; //成员 } variable-list; //变量列表 例如描述一本书&#xff1a; struct Book {char name[20];char author[20];float price;char id[13]; }; //分号不能丢 1.1 结构体变量的创建和初始化 #include <stdio.h&…

Orbit 使用指南 08 | 登记注册环境 | Isaac Sim | Omniverse

如是我闻&#xff1a; 在上一个指南中&#xff0c;我们学习了如何创建一个自定义的车杆环境。我们通过导入环境类及其配置类来手动创建了一个环境实例 # create environment configurationenv_cfg CartpoleEnvCfg()env_cfg.scene.num_envs args_cli.num_envs# setup RL envir…