字符函数和字符串函数

1.strlen函数

  • size_t strlen ( const char * str );

函数功能:

  • 获取字符串的长度,即返回一个字符串到中到\0'字符之前的的字符个数
//int main()
//{
//	char* arr = "abcdef";
//	size_t len = strlen(arr);
//	printf("%d\n", len);//6
//
//	return 0;
//}int main()
{char* arr = "abc\0def";size_t len = strlen(arr);printf("%d\n", len);//3return 0;
}

注意:strlen的返回值是size_t类型,是无符号的

int main()
{char str1[] = "abcdef";char str2[] = "bbb";if (strlen(str2) - strlen(str1) > 0){printf("str2>str1\n");}else{printf("srt1>str2\n");}return 0;
}

代码解读:

  • 因为strlen的返回值是size_t类型的,两个size_t类型的值相减,结果仍然是size_t类型
    3-6结果是-3,因为是size_t类型,会被编译器当成一个很大的正数,因此打印str2>str1

1.1strlen的模拟实现

方法1:计数器

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

方法2:递归

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

方法三:指针-指针

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

2.strcpy函数

  • char * strcpy ( char * destination, const char * source );

函数功能:

  • 将source处的内容拷贝到destination指向的空间,包括'\0'

注意事项:

  • source中的内容要有'\0'
  • 会将'\0'一起拷贝
  • destination指向的空间要足够大

2.1strcpy的模拟实现

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

3.strcat函数

  • char * strcat ( char * destination, const char * source );

函数功能:

  • 在destination末尾追加字符串source

注意事项:

  • 先找到destination字符串中的'\0',在'\0'处开始拷贝
  • 会将source字符串中的'\0'一起拷贝
  • destination字符串必须要有'\0';source字符串也必须要有'\0'
  • destination的空间必须足够大

3.1strcat的模拟实现

char* my_strcat(char* destination, const char* source)
{assert(destination && source);char* ret = destination;//找到'\0'while (*destination++){;}//拷贝while (*destination++ = *source++){;}return ret;
}

问:能不能自己给自己追加?

答:我们自己写的模拟实现代码是不能追加给自己追加的,程序会陷入死循环;库函数中的strcat更加完善,能够完成自己追加自己,但还是不建议这样做


4.strcmp函数

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

函数功能:

  • 比较两个字符串

注意事项:

  • str1>str2,返回正数
  • str1==str2,返回0
  • str1<str2,返回负数
int main()
{char arr1[] = "abcdef";char arr2[] = "abcdeg";int ret = strcmp(arr1, arr2);if (ret > 0)printf("str1 > str2\n");else if (ret == 0)printf("str1 == str2\n");elseprintf("str1 < str2\n");return 0;
}//输出:str1 < str2

4.1strcmp的模拟实现

int my_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都是长度不受限制的字符串函数,与它们相对应的是长度受限制的字符串函数


5.strncpy函数

  • char * strncpy ( char * destination, const char * source, size_t num );

函数功能:

  • 相较于strcpy,strncpy函数多了一个num参数,该参数表示要拷贝的字节个数
    也就是我们可以指定拷贝的字符个数

注意事项:

  •  destination指向的空间必须足够大
  • 如果source中的字符串个数小于num,则拷贝完source的字符串后自动补'\0'
  • 如果source中的字符串个数大于num,则仅拷贝num个字符,不会加上'\0'
int main()
{char arr1[20] = "xxxxxxxxx";char arr2[] = "abcde";strncpy(arr1, arr2, 3);printf("%s\n", arr1);return 0;
}//输出:abcxxxxxx

5.1strncpy的模拟实现

char* my_strncpy(char* destination, const char* source, int num)
{assert(destination && source);char* ret = destination;while (num--){if (*source == '\0')*destination++ = '\0';else*destination++ = *source++;}return ret;
}

6.strncat函数

  • char * strncat ( char * destination, const char * source, size_t num );

函数功能:

  • 从source中追加num个字符到destination中

注意事项:

  • destination的空间必须足够大
  • 如果source字符串个数小于num,则相当于追加source字符串
  • 如果source字符串个数大于num,则追加完num个字符后,自动补上'\0'

6.1strncat的模拟实现

char* my_strncat(char* destination, const char* source, int num)
{assert(destination && source);char* ret = destination;//找'\0'while (*destination != '\0'){destination++;}while (num--){if (num < 0 || *source == '\0')break;*destination++ = *source++;}*destination = '\0';return ret;
}

7.strncmp函数

  • int strncmp ( const char * str1, const char * str2, size_t num );

函数功能:

  • 比较str1和str2中前num个字符构成的字符串的大小
int main()
{char arr1[] = "abcdef";char arr2[] = "abcdef";int ret = strncmp(arr1, arr2, 3);if (ret > 0)printf("str1>str2\n");else if (ret == 0)printf("str1==str2\n");elseprintf("str1<str2\n");return 0;
}
//输出:str1 == str2

8.strstr函数

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

函数功能:

  • 在字符串str1中查找字符串str2
  • 如果找到了,返回str2第一个字符在str1中的地址;如果找不到,返回NULL
int main()
{char arr1[] = "abcdef";char arr2[] = "cde";char* ret = strstr(arr1, arr2);if (ret)printf("%s\n", ret);elseprintf("找不到\n");return 0;
}
//输出:cdef

8.1strstr的模拟实现

char* my_strstr(const char* str1, const char* str2)
{assert(str1 && str2);if (*str2 == '\0')return str1;int i = 0;//str1的下标int j = 0;//str2的下标while (str1[i]){while (str1 && str2 && str1[i] == str2[j]){i++;j++;}if (str2[j] == '\0')return str1 + i - j;i = i - j + 1;j = 0;}return NULL;
}

9.strtok

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

函数功能:

  • 根据delimiters中的字符分割str字符串中的内容
int main()
{char arr1[] = "baiyahua@qq.com";char arr2[] = "@.";char* ret = strtok(arr1, arr2);printf("%s\n", ret);return 0;
}
//输出:baiyahua

注意事项:

  • delimiters中是自己定义的分隔符的集合
  • str中包含delimiters中的分隔符
  • 如果strtok的第一个参数不为空,会将str中的第一个分隔符替换成'\0',并记录该位置,返回起始位置的地址
  • 如果strtok的第一个参数为空,从上次记录的位置开始寻找分隔符
  • 如果没有找到分隔符,返回NULL

由于strtok会改变字符串的内容,所以我们一般先拷贝一份原来的字符串,对拷贝的字符串进行操作

int main()
{char arr1[] = "baiyahua@qq.com";char* p = "@.";char copyArr1[50] = { 0 };strcpy(copyArr1, arr1);char* s = strtok(copyArr1, p);while (s != NULL){printf("%s\n", s);s = strtok(NULL, p);}return 0;
}
//输出:
//baiyahua
//qq
//com

10.strerror

  • char * strerror ( int errnum );

函数功能:

  • 翻译错误码对应的错误信息,并返回错误信息的起始地址

在C语言中,使用库函数发生错误时,会将错误码存放在一个叫errno的全局变量中;strerror的作用就是返回errnum中的值所对应的错误信息,然后返回错误信息的起始地址

int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){printf("打开文件失败,原因是:%s\n", strerror(errno));return 0;}else{printf("打开文件成功\n");}fclose(pf);pf = NULL;return 0;
}
//输出:打开文件失败,原因是: No such file or directory

10.1perror

  • void perror ( const char * str );

函数功能:

  • 直接将错误码翻译成错误信息,并打印出来

perror相当于strerror+printf;在使用库函数出错时,它首先会打印str字符串,再将错误码对应的错误信息打印

int main()
{FILE* pf = fopen("data.txt", "r");if (pf == NULL){perror("打开文件失败,原因是");return 0;}else{printf("打开文件成功\n");}fclose(pf);pf = NULL;return 0;
}
//输出:打开文件失败,原因是: No such file or directory

strerror和perror

  • 如果只想要错误码对应的错误信息,用strerror
  • 如果还想打印出错误信息,用perror更方便

11.字符函数

11.1字符分类函数

常见的字符分类函数:

函数符合下面的条件返回真
iscntrl任何控制字符
isspace空白字符,空格' ',换页'\f',换行'\n',回车'\r',制表符'\t',垂直制表符'\v'
isdigit数字0~9
isxdigit十六进制数字,0~9,a~f或A~F
islower小写字母,a~z
isupper大写字母,A~Z
isalpha字母,a~z,A~Z
isalnum字母或数字,0~9,a~z,A~Z
ispunct标点符号,任何不属于数字或字母的可打印字符
isgraph任何图形字符
isprint任何可打印字符

我们就拿其中一个函数举例,其他函数同理

isdigit函数

  • int isdigit ( int c );

函数功能:

  • 判断c是否是一个数字字符,如果是数字返回非0;如果不是,返回0
int main()
{int ch = '1';if (isdigit(ch))printf("是数字字符\n");elseprintf("不是数字字符\n");return 0;
}
//输出:是数字字符

11.2字符转换函数

  • int toupper ( int c );
  • int tolower ( int c );

函数功能:

  • toupper:如果c是小写字母,则返回c的大写字母;否则就直接返回c
  • tolower:如果c是大写字母,则返回c的小写字母;否则就直接返回c
int main()
{char arr[] = "Test String.\n";char* p = arr;while (*p){if (isupper(*p))*p = tolower(*p);p++;}printf("%s\n", arr);return 0;
}
//输出:test string.

12.内存函数

12.1memcpy函数

  • void * memcpy ( void * destination, const void * source, size_t num );

函数功能:

  • 从source指向的内存拷贝num个字节到destination中,返回destination首元素的地址

前面的strcpy是只能对字符串进行拷贝的函数,而memcpy能对任意类型的数据进行拷贝

int main()
{int arr1[20] = { 0 };int arr2[] = { 1,2,3,4,5,6,7 };memcpy(arr1, arr2, 20);for (int i = 0; i < 5; i++){printf("%d ", arr1[i]);}printf("\n");return 0;
}
//输出1 2 3 4 5

12.1.1memcpy的模拟实现

void* my_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 destination;
}

如果我们想要对重叠的内存进行拷贝,my_memcpy是完成不了的;库函数中的memcpy虽然可以进行重叠内存的拷贝,但我们规定好:

  • 两段不重叠的内存拷贝用memcpy
  • 两段有重叠的内存拷贝用memmove

12.2memmove函数

  • void * memmove ( void * destination, const void * source, size_t num );

函数功能:

  • 从source指向的内存拷贝num个字节到destination中,返回destination首元素的地址

同样是拷贝内存,用法也与memcpy一样,只不过对于重叠内存的拷贝我们一般选择memmove

12.2.1memmove的模拟实现

void* my_memmove(void* destination, const void* source, size_t num)
{assert(destination && source);void* ret = destination;if (source < destination){//从后往前拷贝while (num--){*((char*)destination + num) = *((char*)source + num);}}else{//从前往后拷贝while (num--){*(char*)destination = *(char*)source;destination = (char*)destination + 1;source = (char*)source + 1;}}return ret;
}


12.3memset函数

  • void * memset ( void * ptr, int value, size_t num );

函数功能:

  • 设置ptr指向内存的内容改为value;以字节为单位,一共该num个字节
int main()
{char arr[] = "Welcome to my world.\n";memset(arr + 14, 'x', 3);printf("%s", arr);return 0;
}
//输出:Welcome to my xxxld.

注意事项:

  • 该函数是以字节为单位进行修改的,每次只会修改一个字节

12.4memcmp函数

  • int memcmp ( const void * ptr1, const void * ptr2, size_t num );

函数功能:

  • 以字节为单位比较两块内存
  • ptr1>ptr2,返回正数;
  • ptr1==ptr2,返回0
  • ptr1<ptr2,返回负数
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8 };int arr2[] = { 1,2,3,4,0x11111105 };int ret = memcmp(arr1, arr2, 17);printf("%d\n", ret);return 0;
}
//输出0,前16字节都是相等
//arr1和arr2的第十七字节数据都是05,所以相等

字符函数和字符串函数的内容就到这!

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

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

相关文章

4.9【共享源】流的多生产者和消费者

当一个系统中存在多个生产者和消费者时&#xff0c;情况可能会变得复杂。 了解生产者和消费者流之间支持的基数非常重要。 本质上&#xff0c;一个生产者流可以与多个消费者流连接&#xff0c;但一个消费者流只能连接到一个生产者流。请注意&#xff0c;基数关系仅限于单个流&…

免费内网穿透pve

概要 因为前一段时间买了一个n3150的itx主板&#xff0c;装pve系统&#xff0c;用来all in one&#xff0c;但是因为资金有限&#xff0c;没有足够的经济实力去申请公网IP&#xff0c;所以只能采用内网穿透的方式来远程访问了。 工具选择【目前免费】 官方链接地址&#xff1…

【python】Ubuntu下安装spyder及matplotlib中文显示

一、查看Ubuntu版本 $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.3 LTS Release: 22.04 Codename: jammy尝试用cat /etc/debian_version命令&#xff0c;竟然可以显示出来Debian的版本。 $ cat /etc/debian_version …

ceph块存储学习

目录 ceph的组件和功能 ceph的数据读写流程 ceph存储池学习 ceph的组件和功能 Ceph OSD&#xff1a;功能是存储数据&#xff0c;处理数据的复制、恢复、平衡数据分布&#xff0c;并将一些相关数据提供给Ceph Monitor,。 Ceph Monitor: 功能是维护整个集群健康状态&…

十八、本地配置Hive

1、配置MYSQL mysql> alter user rootlocalhost identified by Yang3135989009; Query OK, 0 rows affected (0.00 sec)mysql> grant all on *.* to root%; Query OK, 0 rows affected (0.00 sec)mysql> flush privileges; Query OK, 0 rows affected (0.01 sec)2、…

从Maven初级到高级

一.Maven简介 Maven 是 Apache 软件基金会组织维护的一款专门为 Java 项目提供构建和依赖管理支持的工具。 一个 Maven 工程有约定的目录结构&#xff0c;约定的目录结构对于 Maven 实现自动化构建而言是必不可少的一环&#xff0c;就拿自动编译来说&#xff0c;Maven 必须 能…

【内存泄漏】内存泄漏及常见的内存泄漏检测工具介绍

内存泄漏介绍 什么是内存泄漏 内存泄漏是指程序分配了一块内存&#xff08;通常是动态分配的堆内存&#xff09;&#xff0c;但在不再需要这块内存的情况下未将其释放。内存泄漏会导致程序浪费系统内存资源&#xff0c;持续的内存泄漏还导致系统内存的逐渐耗尽&#xff0c;最…

财务数据智能化:用AI工具高效制作财务分析PPT报告

Step1: 文章内容提取 WPS AI 直接打开文件&#xff0c;在AI对话框里输入下面指令&#xff1a; 假设你是财务总监&#xff0c;公司考虑与茅台进行业务合作、投资或收购&#xff0c;请整合下面茅台2021年和2022年的财务报告信息。整理有关茅台财务状况和潜在投资回报的信息&…

React 路由跳转

1. push 与 replace 模式 默认情况下&#xff0c;开启的是 push 模式&#xff0c;也就是说&#xff0c;每次点击跳转&#xff0c;都会向栈中压入一个新的地址&#xff0c;在点击返回时&#xff0c;可以返回到上一个打开的地址&#xff0c; 就像上图一样&#xff0c;我们每次返…

ssh工具 向指定的ssh服务器配置公钥

此文分享一个python脚本,用于向指定的ssh服务器配置公钥,以达到免密登录ssh服务器的目的。 效果演示 🔥完整演示效果 👇第一步,显然,我们需要选择功能 👇第二步,确认 or 选择ssh服务器 👇第三步,输入ssh登录密码,以完成公钥配置 👇验证,我们通过ssh登录…

【数据结构】什么是堆?

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 堆的概念及结构 堆的定义如下: n个元素的序列{k1,k2,...,kn}当且仅当满足以下关系时,称之为堆. 或 把这个序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个…

医保购药小程序:智能合约引领医疗数字革新

在医疗领域&#xff0c;医保购药小程序通过引入智能合约技术&#xff0c;为用户提供更为高效、安全的购药体验。本文将通过简单的智能合约代码示例&#xff0c;深入探讨医保购药小程序如何利用区块链技术中的智能合约&#xff0c;实现医保结算、购药监控等功能&#xff0c;为医…

概率中的 50 个具有挑战性的问题 [05/50]:正方形硬币

一、说明 我最近对与概率有关的问题产生了兴趣。我偶然读到了弗雷德里克莫斯特勒&#xff08;Frederick Mosteller&#xff09;的《概率论中的五十个具有挑战性的问题与解决方案》&#xff09;一书。我认为创建一个系列来讨论这些可能作为面试问题出现的迷人问题会很有趣。每篇…

Chrome浏览器http自动跳https问题

现象&#xff1a; Chrome浏览器访问http页面时有时会自动跳转https&#xff0c;导致一些问题。比如&#xff1a; 开发阶段访问dev环境网址跳https&#xff0c;后端还是http&#xff0c;导致接口跨域。 复现&#xff1a; 先访问http网址&#xff0c;再改成https访问&#xf…

如何实现https密钥对登录方式

先安装docker yum install -y yum-utils device-mapper-persistent-data lvm2 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo systemctl start docker.service systemctl enable docker.service yum install -y docker…

C++的面向对象学习(6):运算符的重载

文章目录 前言&#xff1a;什么是运算符重载&#xff1f;针对自定义的类与对象类型。一、加号的运算符重载1.引入背景2.所以运算符重载的作用&#xff1a;3.实现对象间的相加代码&#xff1a;号运算符重载①在类中实现加号运算符重载②设计全局函数实现加号运算符重载③改写函数…

JuiceSSH结合内网穿透实现公网远程访问本地Linux虚拟机

文章目录 1. Linux安装cpolar2. 创建公网SSH连接地址3. JuiceSSH公网远程连接4. 固定连接SSH公网地址5. SSH固定地址连接测试 处于内网的虚拟机如何被外网访问呢?如何手机就能访问虚拟机呢? cpolarJuiceSSH 实现手机端远程连接Linux虚拟机(内网穿透,手机端连接Linux虚拟机) …

释放云服务器ECS实例

目录 云服务器ECS 释放设置 云服务器ECS 当你不想继续使用云服务器ECS&#xff0c;可以直接释放这个实例&#xff0c;但是需要注意的是实例释放后数据无法恢复&#xff0c;免费领取的实例也不能再次领取&#xff0c;一定谨慎进行ECS实例的释放&#xff0c;具体释放限制和建议…

C++ 比 C语言的新增的特性 1

1. C是C的增强 1.1 C是静态类型的语言&#xff0c;具有严格的数据类型检查 1.1.1 c 因为const修饰的变量不允许修改&#xff0c;但是只给了警告&#xff0c;不严谨 const int a10;a20; //报错int *p&a;*p20;//a的值&#xff1f; test1.c:6:9: warning: initialization dis…

【网络安全 | MD5截断比较】PHP、Python脚本利用

前言 在解题中&#xff0c;当遇到类似 substr(md5(a),-6,6) 7788这样的MD5截断比较的题目时&#xff0c;只有求出a的值才能进行接下来的操作。 一个一个去猜是不可能的&#xff0c;通常使用脚本解决&#xff0c;文末给出实战案例。 PHP循环脚本 <?phpfor($i1;$i<9…