字符串函数-C语言

介绍

字符串函数,简单说,就是处理字符串的函数,头文件是string.h,以下是今天的讲解中会讲到的一系列字符串函数

  • 头文件:#include<string.h>
  • strlen:求字符串长度
  • strcpy:拷贝字符串
  • strcat:追加字符串
  • strcmp:比对字符串
  • strstr:一个字符串中找一个字符串
  • strncpy:拷贝字符串(拷贝指定字符串个数)
  • strncmp:比对字符串(比较指定个数字符个数)
  • strncat:追加字符串(追加指定个数个字符)
  • strtok:提取被分隔字符分隔字符串
  • strerror:可将参数部分错误码对应的错误信息返回

strlen

函数声明:size_t strlen(const char* str); 

功能:求字符串长度

使用条件:字符串以'\0'结尾

//函数自实现
#include <assert.h>
int my_strlen(const char* str)
{assert(str);int count = 0;while (*str != '\0') {count++;str++;}return count;
}

在库函数实现strlen时,是以'\0'为结尾判断标识的,如果在字符串中间混入了'\0',那么字符串长度的计算就会提前结束,计算的结果也会随之错误;反之,如果字符串结尾没有遇到'\0'那么在计时函数会一直顺着地址找下去,直到找到'\0'为止,这时候strlen返回的结果就是不可预测的了。

此处注明一下sizeof和strlen的区别,首先,sizeof是一个操作符,不是函数,其返回的值是数据类型所占内存大小,可处理的不只是字符串。而strlen恰相反,其只能用来处理字符串并计算其长度。

同时,也要注意到,strlen函数的返回值为size_t:无符号整型。

下面我举一个关于size_t易错的题

//问以下代码的输出结果
#include<stdio.h>
#include<string.h>
int main()
{if(strlen("abc") - strlen("abcd") > 0)printf("大于\n");else printf("小于\n");return 0;
}

大家的第一反应是什么呢?我猜应该是输出小于。但仔细想一想,size_t作为无符号整型,相减会产生负数吗?不会的,所以最后的结果是打印大于。

//函数使用样例
#include<stdio.h>
#inlcude<string.h>
int main()
{char arr[] = "abcdef";int la = strlen(arr);printf("%s\n", la);//打印6return 0;
}

strcpy

函数声明:char* strcpy(char* destination, const char* source); 

功能:将参数source字符串拷贝至参数destination所指的地址

返回值:字符串destination起始地址

使用条件:源字符串必须以'\0',结尾

                目标空间必须大于等于拷贝过去字符所占的空间:包括'\0'

//自实现
#include<assert.h>
char* my_strcpy(char* str1, const char* str2)
{assert(str1 && str2);char* ret = str1;while (*str1++ = *str2++);*str1 = *str2;return ret;
}
//使用样例
#include<stdio.h>
#include<string.h>
int main() {char arr1[20] = "abcdef";char arr2[20] = { 0 };char* p1 = strcpy(arr2, arr1);printf("%s\n", arr2);//打印abcdefreturn 0;
}

strcat

函数声明:char* strcat(char* destination,const char* source);

功能:将source字符串追加到destination字符串末尾

返回值:destination字符串起始地址 

使用条件:两字符串均以'\0'结尾

                目标空间可被修改

                destination末尾'\0'会被覆盖

                目标空间足够大

注(追加位置):destination字符串'\0'及其后面

//自实现
char* my_strcat(char* dest, const char* src)
{char* ret = dest;while (*dest) dest++;while (*dest++ = *src++);return ret;
}
//样例使用
#inlude<stdio.h>
#inclue<string.h>
int main() {char arr1[20] = "abcdef";char arr2[] = "cd";printf("%s\n",strcat(arr1, arr2));//打印abcdefcdreturn 0;
}

 strcmp

函数声明:int strcmp(const char* str1,const char* str2);

功能:比较字符串

返回值:两字符串相同返回0

               前一个字符串在字典排序靠前返回负数

               后一个字符串在字典排序靠前返回正数

注:区分大小写比较,如果不希望区分可参考stricmp

//自实现
int my_strcmp(const char* s1, const char* s2)
{while (*s1 == *s2) {if (*s1 == '\0')return 0;s1++;s2++;}if (*s1 > *s2)return 1;else return -1;
}
//代码使用样例
#include<stdio.h>
#include<string.h>
int main() {char arr1[] = "abcdef";char arr2[] = "cd";printf("%d\n", strcmp(arr1, arr2));//打印一个负数return 0;
}

strstr

函数声明:char* strstr(const char* str1,const char* str2);

功能:检索str2在str1中第一次出现的位置

返回值: 返回子串str2在str1中第一次出现的位置,找不到返回空指针

//自实现
char* my_strstr(const char* str1,const char* str2)
{const char* cur = str1;const char* s1 = NULL;const char* s2 = NULL;if (!*str2)return (char*)str1;while (*cur) {s1 = cur;s2 = str2;while (*s1 == *s2) {s1++;s2++;}if (*s2 == '\0')return (char*)cur;cur++;}return NULL;
}

以上自实现代码是一份暴力查找版,算法和时间复杂度并不像库函数中那样是最优的,如果想了解真正的内部实现可以去了解KMP算法,此代码只是想让读者更容易了解此函数的功能。

//使用样例
#include<stdio.h>
#include<string.h>
int main() {char arr1[20] = "abcdef";char arr2[] = "cd";printf("%s\n",strstr(arr1, arr2));//打印cdefreturn 0;
}

strncpy 

 函数声明:char* strncpy(char* destination,const char* source,size_t mun);

功能:与strcpy很相似,只是多累个参数,拷贝指定个数的字符串

返回值:字符串destination起始地址

使用条件:源字符串必须以'\0',结尾

                目标空间必须大于等于拷贝过去字符所占的空间:包括'\0'

注:在拷贝完指定个数字符后,不会在串的末尾再拷贝'\0'

//自实现
#include<assert.h>
char* my_strcpy(char* str1, const char* str2,size_t num)
{assert(str1 && str2);char* ret = str1;while ((*str1++ = *str2++)&&num!=0) num--;*str1 = *str2;return ret;
}

strncmp

函数声明:int strcmp(const char* str1,const char* str2,size_t num);

功能:和strcmp很相似,但是多了个参数,比较的是指定个数的字符

返回值:两字符串相同返回0

               前一个字符串在字典排序靠前返回负数

               后一个字符串在字典排序靠前返回正数

注:返回值描述的字符串比较的比较是用num个数截掉后的字符串,具体可参考自实现

//自实现
#include<assert.h>
int my_strncmp(const char* arr1, const char* arr2, size_t num)
{assert(arr1 && arr2);for (int i = 0; i < num; i++) {if (*(arr1 + i) == *(arr2 + i));else if (*(arr1 + i) > *(arr2 + i)) return 1;else return -1;}return 0;
}
//使用样例
#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = "abcdefg";char arr2[] = "abcdfea";int ret =strncmp(arr1, arr2, 4);printf("%d\n", ret);//打印0ret = strncmp(arr1, arr2, 5);printf("%d\n", ret);//打印一个负数return 0;
}

strncat

函数声明: char* strcat(char* destination,const char* source,size_t num);

功能:与strcat功能相似,将source指定个数的字符串追加到destination字符串末尾

返回值:destination字符串起始地址 

使用条件:两字符串均以'\0'结尾

                目标空间可被修改

                destination末尾'\0'会被覆盖

                目标空间足够大

注:destination字符串'\0'及其后面

        追加num个字符后会自动添加'\0'        

//自实现
#include<assert.h>
char* my_strncat(char* arr1, const char* arr2, size_t num)
{assert(arr1 && arr2);char* ret = arr1;while (*arr1)arr1++;for (int i = 0; i < num; i++) {*(arr1 + i) = *(arr2 + i);}*(arr1 + num) = '\0';return ret;
}
//使用样例
#include<stdio.h>
#include<string.h>
#include<assert.h>
int main()
{char arr1[20] = "abcdefg";char arr2[20] = "rhmotyi";char* pc = strncat(arr1, arr2, strlen(arr2));printf("%s\n", pc);    //打印abcdefgrhmotyipc = strncat(arr1, arr2, strlen(arr2) - 2);printf("%s\n", pc);    //打印abcdefgrhmotyirhmotreturn 0;
}

strtok

函数声明:char* strtok(char* str, const char* sep);

功能:提取被分隔字符分隔字符串

           其中:sep里面放的是分隔符;str里面放的是带分隔符的字符串

           调用一次,将最首先找到的分隔符变成'\0',并标记下一个位置

返回值:上一次标记位置(如第一次调用则返回str首元素地址)

               如果字符串中不存在更多标记,则返回NULL

注:strtok第一个参数不为NULL时,函数找到str中第一个标记,保存在其字符串中的位置

       strtok第一个参数为NULL时,函数将从被保存的位置开始,寻找下一个标记

       strtok内部其实存在静态变量,运行结束后上一次运行数据会有存留(也就是标记地址)

//使用样例
#include <stdio.h>
#include <string.h>
int main()
{const char* p = "@.";char arr[] = "zhangsan@1623.com";char* s = strtok(arr, p);printf("%s\n", s);//zhangsans = strtok(NULL, p);printf("%s\n", s);//1623s = strtok(NULL, p);printf("%s\n", s);//comreturn 0;
}

但是上面的代码似乎有点冗杂,你完全可以写在循环中,见代码

//使用样例(循环版)
#include <stdio.h>
#include <string.h>
int main()
{const char* p = "@.";char arr[] = "zhangsan@1623.com";//char* s = strtok(arr, p);//printf("%s\n", s);//zhangsan//s = strtok(NULL, p);//printf("%s\n", s);//1623//s = strtok(NULL, p);//printf("%s\n", s);//comfor (char* s = strtok(arr, p); s != NULL; s = strtok(NULL, p))printf("%s\n", s);return 0;
}

这两份代码打印出来的结果是相同的

strerror

函数声明:char* strerror(int errnum);

功能:可以将参数部分错误码对应的错误信息字符串返回 

 C语言规定了一些错误码,放在errno.h这个头文件中说明

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

下面是输出结果

 结语

那么本篇博客到这里就要结束了,我们介绍了大部分在平时coding中可能运用到的字符串函数,以及一些函数的自实现,大家可以看看,更利于对函数的了解。如果觉得这篇博客对你有帮助的话,还请点个小赞收藏一下再走啊,如果本篇博客有任何错误也欢迎在评论区讨论或者私我哦--比心♥

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

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

相关文章

使用自动化测试获取手机短信验证码

目前在职测试开发,,写一些脚本,个人认为这职业不科学不应该有的职业,测试就是测试,开发就是开发,运维还是老鸟,这行业总能折腾些莫名其妙的东西出来,刚做这行时学的第一门语言是bash shell, 去新去单位上班直接写了个一键搭建测试环境的测试脚本,本来不想干测试了,好好做微信小…

C++ Primer Plus第十一章笔记

目录 运算符重载 概述 1.2 重载限制 友元简介 创建友元 常用的友元&#xff1a;重载 << 运算符 重载运算符&#xff1a;作为成员函数还是非成员函数 类的自动转换和强制类型转换 两种类型转换 转换函数 运算符重载 操作符重载&#xff08;Operator Overloadi…

夜莺项目发布 v6.4.0 版本,新增全局宏变量功能

大家好&#xff0c;夜莺项目发布 v6.4.0 版本&#xff0c;新增全局宏变量功能&#xff0c;本文为大家简要介绍一下相关更新内容。 全局宏变量功能 像 SMTP 的配置中密码类型的信息&#xff0c;之前都是以明文的方式在页面展示&#xff0c;夜莺支持全局宏变量之后&#xff0c;可…

android11-隐藏状态栏和导航栏

隐藏导航栏 /android11/frameworks/base/packages/SystemUI/res/layout/navigation_bar.xml diff --git a/frameworks/base/packages/SystemUI/res/layout/navigation_bar.xml b/frameworks/base/packages/SystemUI/res/layout/navigation_bar.xml index ba6b6956f1..6db2348…

在Linux中如何检查网络问题

ping命令&#xff1a; ping example.com示例输出&#xff1a; PING example.com (93.184.216.34) 56(84) bytes of data. 64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq1 ttl55 time10.3 ms 64 bytes from 93.184.216.34 (93.184.216.34): icmp_seq2 ttl55 time9.…

从 JSON 转 Java 实体的多种方法详解

将 JSON 数据转换为 Java 对象是现代应用程序开发中常见的任务。在 Java 中&#xff0c;有多种方法可以实现这一目标。本文将详细介绍几种常见的方法&#xff0c;以及它们的优缺点。 1. 手动映射&#xff08;Manual Mapping&#xff09; 手动映射是最基础的方法之一&#xff…

kibana安装

kibana安装下载注意事项 地址&#xff1a;curl -O https://artifacts.elastic.co/downloads/kibana/kibana-7.16.3-linux-x86_64.tar.gz 下载后直接解压启动即可 1. 但需要使用非root用户启动 &#xff0c;root用户启动会报错 2. kibana需要和elasticsearch版本一致 不然…

力扣labuladong一刷day21天滑动哈希算法共2题

力扣labuladong一刷day21天滑动哈希算法共2题 文章目录 力扣labuladong一刷day21天滑动哈希算法共2题一、187. 重复的DNA序列二、28. 找出字符串中第一个匹配项的下标 一、187. 重复的DNA序列 题目链接&#xff1a;https://leetcode.cn/problems/repeated-dna-sequences/descr…

管理Android12系统的WLAN热点

大家好!我是编码小哥,欢迎关注,持续分享更多实用的编程经验和开发技巧,共同进步。 要创建一个APK管理Android 12系统的WLAN热点,你需要遵循以下步骤: 1. 获取必要的权限和API访问权限。在AndroidManifest.xml文件中添加以下权限: ```xml <uses-permission android:…

vue3通过el-dropdown实现动态菜单切换页面

这是效果图 首先是主页index.vue <template><el-row><el-col :span"20"><!-- 顶部菜单 --><div v-if"showTop"><topmenu /></div><!-- 右侧下方区域动态切换的内容 --><div style"flex: 1;&quo…

oracle varchar2 和 nvarchar2的区别

oracle varchar2 和 nvarchar2的区别 VARCHAR2和NVARCHAR2在数据库中都用于存储变长字符数据&#xff0c;但两者在存储方式和字符长度上存在一些不同。以下是VARCHAR2和NVARCHAR2的区别&#xff1a; 存储方式&#xff1a;VARCHAR2是存储以字节为单位的字符串&#xff0c;而NV…

Qt Creator使用Heob检测内存泄漏

转自Qt windows MinGW编译环境下内存泄漏排查工具 heob使用教程-CSDN博客 问题描述 最近开发的一个小项目&#xff0c;正常使用时&#xff0c;占用内存随时间增加越来越大&#xff0c;直至程序崩溃。 内存泄漏排查工具heob 在Qt creator4.6以后&#xff0c;可以使用heob进行内…

css浮动属性学习

在此文&#xff0c; html菜单的基本制作-CSDN博客 已经看到css 浮动属性的效果&#xff1b;下面单独看一下浮动属性&#xff1b; 做4个div&#xff0c;设置不同的背景色&#xff0c;不为div添加float属性&#xff1b;效果如下&#xff1b; 因为div是块级元素&#xff0c;默认…

上海震坤行:水泥行业数字化采购的趋势、策略与实践

上海震坤行&#xff1a;水泥行业数字化采购的趋势、策略与实践 在中国水泥协会发布的《2023年上半年水泥行业经济运行及下半年展望》中提到了水泥行业的发展现状——2023年上半年&#xff0c;在全球经济增长放缓、国内经济延续恢复态势、但市场需求不足的宏观环境下&#xff0…

HarmonyOS开发—Arkts循环渲染(ForEach)深入运用详解【鸿蒙专栏-16】

文章目录 ArkTS ForEach接口详解与应用示例ForEach接口概述介绍接口描述参数说明键值生成规则默认规则组件创建规则首次渲染非首次渲染使用场景高级用法条件渲染逻辑LazyForEach的性能优化渲染结果预期ForEach的错误使用案例与性能降低渲染结果非预期渲染性能降低结语ArkTS For…

试用程序实现不使用缓存字节数组的方法复制C盘根目录下的a,jpg到E盘下的a.jpg

import java.io.*;public class FileCopier {public static void main(String[] args) {String sourcePath "C:\\a.jpg"; // 源文件路径String destinationPath "E:\\a.jpg"; // 目标文件路径copyFile(sourcePath, destinationPath);System.out.printl…

全新MacBook 前端装机流程

1.安装brew 啥也别说&#xff0c;直接用下面这个代码&#xff0c;别问为啥&#xff0c;没有翻墙软件千万别去官网下载&#xff0c;都是血的教训。 /usr/bin/ruby -e "$(curl -fsSL https://cdn.jsdelivr.net/gh/ineo6/homebrew-install/install)"2.安装nvm 又到了…

python使用subprocess.Popen多线程的cmd命令交互

python使用subprocess.Popen多线程的cmd命令交互 我们创建了一个CmdThread类&#xff0c;该类继承自threading.Thread&#xff0c;并重写了run()方法,我们使用subprocess.Popen()执行指定的命令&#xff0c;并通过管道获取命令的输出。然后&#xff0c;我们逐行读取输出&#…

电商API数据接口|拼多多商品订单物流接口的接入

拼多多是一家中国的电商平台&#xff0c;提供了多语言环境下的接口&#xff0c;以便开发者能够在各种语言环境中使用拼多多的功能和服务。以下是拼多多多语言环境下的接口介绍&#xff1a; 1. 用户认证接口&#xff1a;通过该接口&#xff0c;开发者可以实现用户的注册、登录和…

【Windows】解决Windows11错误0x80190001

1. 安装Fiddler网络调试工具 下载链接&#xff1a;Fiddler Classic 注&#xff1a;获取安装包的过程中可能要获取邮箱信息&#xff0c;但不用验证邮箱&#xff0c;大概是给你的邮箱发广告信息&#xff0c;问题不大。 在“开始”界面找到Fiddler Classic&#xff0c;点击运行…