当前位置: 首页 > news >正文

【C语言】string.h——主要函数总结

string.h主要定义了字符串处理函数和内存操作函数。

字符串处理函数

strlen()

功能:strlen()函数返回字符串的字节长度,不包括末尾的空字符\0

函数原型:size_t strlen(const char* s);

返回值:返回的是size_t类型的无符号整数(%zd),除非是极长的字符串,一般情况下当作int类型处理即可(%d)。

参数:字符串指针

注意:

  1. 区分字符串长度strlen()与字符串变量长度sizeof()

    char s[50] = "hello";
    printf("%d\n", strlen(s));  // 5
    printf("%d\n", sizeof(s));  // 50
    
  • my_strlen

    int my_strlen(const char *s){int count = 0;while (*s++) // 终止条件 '\0'count++;return count;
    }
    

strcpy()

功能:用于将源字符串的内容复制到目标字符串,相当于字符串赋值,两者地址均未改变。

函数原型:char *strcpy(char dest[], const char source[])

参数:

  • 第一个参数是目标字符串数组
  • 第二个参数是源字符串(const说明符,表示strcpy函数不会修改第二个字符串)

返回值:返回一个字符串指针(即char*),指向第一个参数

注意:

  1. 复制字符串之前,必须要保证第一个参数的长度大于等于第二个参数的长度,否则虽然不会报错,但会溢出第一个字符串变量的边界,发生难以预料的结果。容易发生缓冲区溢出!
  2. 复制时会将字符串中的 ’\0’ 也一同复制进去

strcpy()也可以用于字符数组的赋值。

char str[10];
strcpy(str, “abcd”);

strcpy()返回值的用途,连续为多个字符数组赋值。

strcpy(str1, strcpy(str2, “abcd”));

strcpy()的第一个参数最好是一个已经声明且初始化的数组。目标字符串若没有进行初始化,指向的是一个随机的位置,因此字符串可能被复制到任意地方。(初始化是指手动为指针开辟空间,而不是使用字符串赋值初始化)

char* str; // char *str = “ERROR”; 字符串赋值初始化
strcpy(str, “hello world”); // 错误

  • my_strcpy

    char* my_strcpy(char* dest, const char* source) {char* ptr = dest;while (*dest++ = *source++); // 不是 ==return ptr;
    }int main(void) {char str[25];strcpy(str, "hello world");printf("%s\n", str);return 0;
    }
    

strncpy()

功能:strncpy()strcpy()的用法完全一样,只是多了第3个参数,用来指定复制的最大字符数,防止溢出目标字符串变量的边界。

函数原型:char* strncpy(char *dest, char *src, **size_t n)**;

参数:第三个参数n定义了复制的最大字符数。如果达到最大字符数以后,源字符串仍然没有复制完,就会停止复制,这时目的字符串结尾将没有终止符\0,这一点务必注意。如果源字符串的字符数小于n,则strncpy()的行为与strcpy()完全一致。

返回值:返回一个字符串指针(即char*),指向第一个参数

疑问:dest与src的长度比较,src与n的比较,dest与n的长度比较

  1. 如果src字符串比dest长会有什么结果?
  2. 排除疑问1,如果src字符串比指定的n短怎么样?
  3. 如果src字符串比指定的n短怎么样?
  • my_strncpy()

    char *my_strncpy(char *dest, char *src, int n) {char *ret = dest;for (int i = 0; i < n && *src != '\0'; i++) {*dest++ = *src++;if (*dest == '\0'){break;}}// 添加终止符if (*src == '\0'){*dest = '\0';}return ret;
    }
    

strcat()(缓冲区溢出)

功能:strcat()函数用于连接字符串。即将源字符串s2拼接在目标字符串s1后面。

函数原型:char* strcat(char *s1, const char *s2);

参数:它接受两个字符串作为参数,把第二个字符串的副本添加到第一个字符串的末尾。这个函数会改变第一个字符串,但是第二个字符串不变。

返回值:strcat()的返回值是一个字符串指针,指向第一个参数。

注意:

  1. 要确保两字符串长度之和小于源字符串的容量长度,否则可能会导致缓冲区溢出。
  • 一个错误代码例子

    #include <stdio.h>
    #include <time.h>
    #include <string.h>int main () {char s1[8] = "test";char *s2 = "hello";// sizeof = 8, strlen = 4  testprintf("sizeof = %d, strlen = %d  %s\n", sizeof(s1), strlen(s1), s1);strcat(s1, s2);// sizeof = 8, strlen = 9  testhelloprintf("sizeof = %d, strlen = %d  %s\n", sizeof(s1), strlen(s1), s1);return 0;
    }
    

strncat()

功能:与strcat()完全一致,strncat()用于连接两个字符串。

函数原型:char* strncat(const char *dest, const char *src, size_t n);

参数:增加了第三个参数,指定最大添加的字符数。在添加过程中,一旦达到指定的字符数,或者在源字符串中遇到空字符\0,就不再添加了。

返回值:strncat()返回第一个参数,即目标字符串指针。

为了保证连接后的字符串,不超过目标字符串的长度,strncat()通常会写成下面这样。

strncat(str1,str2,sizeof(str1) - strlen(str1) - 1
);

strncat()总是会在拼接结果的结尾,自动添加空字符\0,所以第三个参数的最大值,应该是str1的变量长度减去str1的字符串长度,再减去1

strcmp()

功能:strcmp()函数用于比较两个字符串的内容(从左到右比较字符串中的ASCII码值)。

函数原型:int strcmp(const char* s1, const char* s2);

参数:需要比较的两个字符串

返回值:按照字典顺序,如果两个字符串相同,返回值为0;如果s1小于s2strcmp()返回值小于0;如果s1大于s2,返回值大于0。

// s1 = Happy New Year
// s2 = Happy New Year
// s3 = Happy Holidaysstrcmp(s1, s2) // 0
strcmp(s1, s3) // 大于 0
strcmp(s3, s1) // 小于 0

注意:

  1. strcmp()只用来比较字符串,不用来比较字符。字符直接用相等运算符(==)就能比较。
  • my_strcmp.c

    int my_strcmp(const char *s1, const char *s2){while( (*s1) && (*s2) && (*s1 == *s2)){s1++;s2++;}return (*s1 - *s2);
    }
    

strncmp()

功能:strncmp()只比较到指定位置的字符串(从左到右比较字符串中字符的ASCII码值)。

函数原型:int strncmp( const char* s1, const char* s2, **size_t n**);

参数:该函数增加了第三个参数,指定了比较的字符数。

返回值:与strcmp()一样。如果两个字符串相同,返回值为0;如果s1小于s2strcmp()返回值小于0;如果s1大于s2,返回值大于0。

  • my_strncmp

    int my_strncmp(const char *s1, const char *s2, size_t n){int num = 0;while( (*s1) && (*s2) && (*s1 == *s2)){num++;if (num == n) {break;}s1++; // 偏移量增加要放在判断后面s2++;}return (*s1 - *s2);
    }
    

strchr(),strrchr()

功能:strchr()strrchr()都用于在字符串中查找指定字符。不同之处是,strchr()从字符串开头开始查找,strrchr()从字符串结尾开始查找,函数名中多出来的r表示 reverse(反向)。

函数原型:

  1. char* strchr(char* str, int c);
  2. char* strrchr(char *str, int c);

参数:第一个参数是字符串指针,第二个参数是所要查找的字符。

返回值:一旦找到该字符,它们就会停止查找,并返回指向该字符的指针。如果没有找到,则返回 NULL。

  • my_strchr和my_strrchr

    // 正向搜索
    char *my_strchr(char *str, int c){while (*str) {if (*str == c) {return str;} else {str++;}}
    }// 反向搜索
    char *my_strrchr(char *str, int c){int size = strlen(str);for (int i = size; i >= 0; i--) {if (*(str + i - 1) == c) {return str + i - 1;}}return NULL;
    }
    
  • 确定二维字符串(以NULL结尾)中是否含有某个字符(还是不能区分二者版本的区别)

    #include <stdio.h>
    #include <assert.h>int main() {char *strings[] = {"Hello", "World","Test", NULL};char value = 'l';int result = find_char(strings, value);if (result == 1) {printf("The character '%c' is found in one of the strings.\n", value);} else {printf("The character '%c' is not found in any of the strings.\n", value);}return 0;
    }
    
    // 版本一,没有副作用,将原来的字符串指针拷贝一份
    int find_char(char **strings, char value){char *string;while((string = *strings++) != NULL){while(*string != '\0'){if (*string++ == value) {return 1;}}}return 0;
    }
    

    需要注意的是,虽然 *strings++ 表达式不会直接修改原始字符串指针数组,但是它会将 strings 指向下一个字符串指针。这意味着,如果我们在循环外部还需要访问原始字符串指针数组,那么在循环结束后,副本strings 指针已经指向了最后一个字符串指针的下一个位置,可能导致访问越界。因此,在使用这个版本的函数时,需要注意循环结束后 strings 指针的位置。

    // 版本二,仅仅只能检测一次,因为有副作用    
    int find_char(char **strings, char value) {assert(strings != NULL); // 这本不是函数的事情,strings建立时,就应检查是否为空while(*strings != NULL){while(**strings != '\0'){if (*(*strings)++ == value){ // 副作用在这里,对传递进来的参数进行解引用后更改return 1;}}strings++;}return 0;
    }
    

    当我们传递一个字符串数组 char **strings 给函数 find_char 时,我们有两种处理方式来查找指定字符 value。在第一个版本中,我们使用了一个新的指针 string 来拷贝原始字符串指针 *strings 的值。这意味着我们在函数内部操作的是拷贝后的指针,而不是原始字符串指针。因此,在这个版本中,无论我们对 string 进行任何修改,都不会影响到原始字符串指针。这样的好处是,我们可以多次调用 find_char 函数,每次都会在拷贝的字符串指针上进行查找,而不会影响到其他调用。同时,由于没有修改原始字符串指针,这个版本更加安全。

    在第二个版本中,我们直接操作原始字符串指针 *strings。这意味着对原始指针的任何修改都会影响到其他调用 find_char 函数的地方。具体到这个例子中,我们在内层循环中对 *strings 进行自增操作,即 (*strings)++,这会导致 *strings 指向下一个字符。因此,如果我们需要多次调用 find_char 函数,就会在每次调用之后改变原始字符串指针的位置,从而导致错误的结果或者不可预期的行为。这种副作用的存在可能会对程序的正确性和可维护性造成严重影响。

    总结起来,第一个版本通过拷贝字符串指针来避免副作用,确保了代码的安全性和可维护性。第二个版本虽然更加节省内存,但是具有副作用,可能会引发错误,因此使用时需要格外小心。选择哪个版本取决于具体的需求和场景。

相关文章:

【C语言】string.h——主要函数总结

string.h主要定义了字符串处理函数和内存操作函数。 字符串处理函数 strlen() 功能&#xff1a;strlen()函数返回字符串的字节长度&#xff0c;不包括末尾的空字符\0。 函数原型&#xff1a;size_t strlen(const char* s); 返回值&#xff1a;返回的是size_t类型的无符号整…...

如何在前端优化中减少页面加载时间?

在前端优化中&#xff0c;减少页面加载时间是至关重要的&#xff0c;因为快速加载的页面可以提高用户体验&#xff0c;减少跳出率&#xff0c;从而提升网站的整体性能。本文将介绍一些实用的前端优化技巧&#xff0c;以帮助您减少页面加载时间。 一、优化图片 图片是页面加载…...

Typecho后台无法登录显示503 service unavailable问题及处理

一、Typecho 我的博客地址&#xff1a;https://www.aomanhao.top 使用老薛主机动态Typecho博客框架handsome主题的搭配&#xff0c;文章内容可以异地网页更新&#xff0c;可以听后台背景音乐&#xff0c;很好的满足我的痛点需求&#xff0c;博客部署在云端服务器访问响应较快…...

Python入门(一)

anaconda安装 官网&#xff1a;https://www.anaconda.com下载 jupyter lab 简介&#xff1a; 包含了Jupyter Notebook所有功能。 JupyterLab作为一种基于web的集成开发环境&#xff0c;你可以使用它编写notebook&#xff0c;操作终端&#xff0c;编辑markdown文本&#xf…...

云表企业级无代码案例-自主开发ERP管理系统

痛点 我是一名企业经营者&#xff0c;同时也是信息化建设的坚定倡导者。凭借管理专业背景&#xff0c;我深知经营数据对于企业的至关重要性。如何高效搜集、精准分析经营数据&#xff0c;并将其转化为决策依据&#xff0c;直接关乎企业的生死存亡。太多因盲目决策而倒闭的企业…...

Qt —— 编译Qt5版本QFTP库,并实现连接服务、获取列表、上传、下载、删除文件等操作(附源码、附基于Qt5编译好的QFTP库)

示例效果1 示例效果2 介绍 QFTP是Qt4的库,Qt5改用了QNetworkAccessManager来代替。但是Qt5提供的QNetworkAccessManager仅支持FTP的上传和下载,所以只能将QFTP库编译为Qt5的库来进行调用。 QFTP在Github的下载地址:https://github.com/qt/qtftp 客户端源码生成的release结果…...

碰到es6的...拓展运算符

第一次碰到&#xff0c;哥们啥也不会 let searchForm ref({}) let formData ref({}) const initArgs async() > { args.value props.init_data formData .value { ...searchForm.value,//把值都带过来 workWhere : args.value.workWhere, statusArgs : args.value.sta…...

JDK8新特性详解

☆* o(≧▽≦)o *☆嗨~我是小奥&#x1f379; &#x1f4c4;&#x1f4c4;&#x1f4c4;个人博客&#xff1a;小奥的博客 &#x1f4c4;&#x1f4c4;&#x1f4c4;CSDN&#xff1a;个人CSDN &#x1f4d9;&#x1f4d9;&#x1f4d9;Github&#xff1a;传送门 &#x1f4c5;&a…...

ELK+Filebeat 部署实验

Filebeat是轻量级的开源日志文件数据搜集器。通常在需要采集数据的客户端安装 Filebeat&#xff0c;并指定目录与日志格式&#xff0c;Filebeat 就能快速收集数据&#xff0c;并发送给 logstash 进行解析&#xff0c;或是直接发给 Elasticsearch 存储&#xff0c;性能上相比运行…...

利用wireshark lua扩展能力增加自定义解析器[注释解读版]

前言 Wireshark提供了lua扩展能力&#xff0c;可以定制一些Listner和Dissector&#xff0c;用于一些自定义的使用场景&#xff0c;例如: lua插件适应场景Listener报文统计、内容抽取等Dissector协议树解析&#xff0c;在wireshark中立等可看 已在以前的文档中积累了对于List…...

GPT-5不叫GPT-5?下一代模型会有哪些新功能?

OpenAI首席执行官奥特曼在上周三达沃斯论坛接受媒体采访时表示&#xff0c;他现在的首要任务就是推出下一代大模型&#xff0c;这款模型不一定会命名GPT-5。虽然GPT-5的商标早已经注册。 如果GPT-4目前解决了人类任务的10%&#xff0c;GPT-5应该是15%或者20%。 OpenAI从去年开…...

2024.1.23(347.前k个高频元素)

2024.1.23(347.前k个高频元素) 思路 这道题目主要涉及到如下三块内容&#xff1a; 1.要统计元素出现频率 2.对频率排序 3.找出前K个高频元素 首先统计元素出现的频率&#xff0c;这一类的问题可以使用map来进行统计。 然后是对频率进行排序&#xff0c;这里我们可以使用一种…...

MySQL对数据库的操作

前腰&#xff1a;本节只是的数据库本身进行增删查改、备份、恢复等操作&#xff0c;而不是对数据库内的数据表做操作&#xff0c;还请您区分好这两点。 1.创建数据库 # 创建数据库的语法形式 CREATE DATABASE [IF NOT EXISTS] database_name [create_specification]# 大写的是…...

解决Unity WebGLInput插件全屏输入的问题

unity webgl的中文输入插件WebglInput在全屏的时候会出现无法输入中文/输入的英文会字母出现在光标后面/什么都输入不了的等无法正常使用的情况。 插件官网作者给出了unity的2017&#xff0c;2018&#xff0c;2019版本的全屏输入解决方法。 最新插件下载地址&#xff1a;http…...

Android14实战:调整A2DP音量曲线(五十三)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀 人生格言: 人生从来没有捷径,只…...

vector讲解

在学习玩string后我们开始学习vector&#xff0c;本篇博客将对vector进行简单的介绍&#xff0c;还会对vector一些常用的函数进行讲解 vector的介绍 实际上vector就是一个数组的数据结构&#xff0c;但是vector是由C编写而成的&#xff0c;他和数组也有本质上的区别&#xff…...

nvm 配置淘宝镜像失效,以及安装node后 npm-v 无效

win11 nvm版本 1.1.4 和1.1.7和1.1.12&#xff08;目前最新版本24年 一月二十三日&#xff09; 以上nvm版本都会出现一下问题&#xff0c; 从https://github.com/coreybutler/nvm-windows/releases 下载nvm安装包如下图 傻瓜式安装后&#xff0c;不用去配置环境变量&#…...

【Android Gradle 插件】Gradle 基础配置 ④ ( Gradle Wrapper 配置作用 | Gradle 下载的依赖库存放位置 )

一、Gradle Wrapper 配置作用 gradle wrapperdistributionBaseGRADLE_USER_HOME distributionPathwrapper/dists distributionUrlhttps\://services.gradle.org/distributions/gradle-6.7.1-bin.zip zipStoreBaseGRADLE_USER_HOME zipStorePathwrapper/distsGradle Wrapper 配…...

Deepin_Ubuntu_查看树形目录结构(tree)

Linux系统&#xff08;Deepin、Ubuntu&#xff09;中&#xff0c;可以使用tree命令来查看树形目录结构&#xff0c;下面是一些示例&#xff1a; 查看当前目录的树形结构&#xff1a; tree查看指定目录的树形结构&#xff0c;例如/etc/X11/fonts目录&#xff1a; tree /etc/X…...

Java Excel分割成许多小文件

最近在处理excel&#xff0c;数据很多&#xff0c;需要将excel拆分成许多小块&#xff0c;并保留原来的格式&#xff0c;于是写了该算法&#xff0c;并能保留原来的样式&#xff0c;使用很简单&#xff1a; Sheet splitSheet ExcelUtil.split(sheet, 0, 20, 5, 8); 传入开始…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...