《C和指针》笔记34:字符串函数

文章目录

  • 1. 获取字符串长度
    • strlen
  • 2. 复制字符串
    • strcpy
    • strncpy
  • 3. 拼接字符串
    • strcat
    • strncat
  • 4. 字符串比较
    • strcmp
    • strncmp

1. 获取字符串长度

strlen

库函数strlen的原型如下:

size_t strlen( char const *string );

注意strlen返回一个类型为size_t的值。这个类型是在头文件stddef.h中定义的,它是一个无符号整数类型。在表达式中使用无符号数可能导致不可预料的结果。例如,下面两个表达式看上去是一样的:

if( strlen( x ) >= strlen( y ) ) ...
if( strlen( x )strlen( y ) >= 0 ) ...

但事实上它们是不相等的。第1条语句将按照你预想的那样工作,但第2条语句的结果将永远是真。strlen的结果是个无符号数,所以操作符>=左边的表达式也将是无符号数,而无符号数绝不可能是负的

表达式中如果同时包含了有符号数和无符号数,可能会产生奇怪的结果。和前一对语句一样,下面两条语句并不相等,其原因相同。

if( strlen( x ) >= 10 ) ...
if( strlen( x )10 >= 0 ) ...

如果把strlen的返回值强制转换为int,就可以消除这个问题。

2. 复制字符串

strcpy

用于复制字符串的函数是strcpy,它的原型如下所示:

char *strcpy( char *dst, char const *src );

这个函数把参数src字符串复制到dst参数。如果参数src和dst在内存中出现重叠,其结果是未定义的。由于dst参数将进行修改,所以它必须是个字符数组或者是一个指向动态分配内存的数组的指针,不能使用字符串常量。该函数返回它们第1个参数的一份拷贝,就是一个指向目标字符数组的指针。

目标参数的以前内容将被覆盖并丢失。即使新的字符串比dst原先的内存更短,由于新字符串是以NUL字节结尾,所以老字符串最后剩余的几个字符也会被有效地删除。举个例子来说:

char message[] = "Original message";
...
if (...)strcpy(message, "Different");

如果条件为真并且复制顺利执行,数组将包含下面的内容:

在这里插入图片描述

第1个NUL字节后面的几个字符再也无法被字符串函数访问,因此从任何现实的角度看,它们都已经是丢失的了。

程序员必须保证目标字符数组的空间足以容纳需要复制的字符串。如果字符串比数组长,多余的字符仍被复制,它们将覆盖原先存储于数组后面的内存空间的值。strcpy无法解决这个问题,因为它无法判断目标字符数组的长度。例如:

```c
char message[] = "Original message";
...
if (...)strcpy(message, "A different message");

第2个字符串太长了,无法容纳于message字符数组中。因此,strcpy函数将侵占数组后面的部分内存空间,改写原先恰好存储在那里的变量。这可能发生意想不到的效果。如果在使用这个函数前确保目标参数足以容纳源字符串,就可以避免大量的调试工作。

strncpy

strcpy一样,strncpy把源字符串的字符复制到目标数组。然而,它总是正好向dst写入len个字符。它的原型如下:

char *strncpy(char *dst, char const *src, size_t len);

如果strlen( src )的值小于len,dst数组就用额外的NUL字节填充到len长度。如果strlen( src )的值大于或等于len,那么只有len个字符被复制到dst中。注意!它的结果将不会以NUL字节结
尾 。

strncpy调用的结果可能不是一个字符串,因此字符串必须以NUL字节结尾。如果在一个需要字符串的地方(例如strlen函数的参数)使用了一个不是以NUL字节结尾的字符序列,会发生什么情况呢?strlen函数将无法知道NUL字节是没有的,所以它将继续进行查找,一个字符接一个字符,直到它发现一个NUL字节为止。或许它找了几百个字符才找到,而strlen函数的这个返回值从本质上说是一个随机数。或者,如果函数试图访问系统分配给这个程序以外的内存范围,程序就会崩溃。

这个问题只有当你使用strncpy函数创建字符串,然后或者对它们使用str开头的库函数,或者在printf中使用%s格式码打印它们时才会发生。在使用不受限制的函数之前,你首先必须确定字符串实际上是以NUL字节结尾的。例如,考虑下面这个代码段:

char buffer[BSIZE];
...
strncpy(buffer, name, BSIZE);
buffer[BSIZE - 1]=`\0';

如果name的内容可以容纳于buffer中,最后那个赋值语句没有任何效果。但是,如果name太
长,这条赋值语句可以保证buffer中的字符串是以NUL结尾的。以后对这个数组使用strlen或其
他不受限制的字符串函数将能够正确工作。

3. 拼接字符串

strcat

要想把一个字符串添加(连接)到另一个字符串的后面,你可以使用strcat函数。它的原型如下:

char *strcat( char *dst, char const *src );

strcat函数要求dst参数原先已经包含了一个字符串(可以是空字符串)。它找到这个字符串的末尾,并把src字符串的一份拷贝添加到这个位置。如果src和dst的位置发生重叠,其结果是未定义的。该函数返回它们第1个参数的一份拷贝,就是一个指向目标字符数组的指针。

strcpy(message, "Hello ");
strcat(message, customer_name);
strcat(message, ", how are you?");

每个strcat函数的字符串参数都被添加到原先存在于message数组的字符串后面。其结果是下面这个字符串:

Hello Jim, how are you?

和前面一样,程序员必须保证目标字符数组剩余的空间足以保存整个源字符串。但这次并不是简单地把源字符串的长度和目标字符数组的长度进行比较,必须考虑目标数组中原先存在的字符串。

我们也可以这样嵌套,因为返回值是第一个参数的指针:

strcat( strcpy( dst, a ), b );

strcpy首先执行。它把字符串从a复制到dst并返回dst。然后这个返回值成为strcat函数的第1个参数,strcat函数把b添加到dst的后面。

它等价于:

strcpy( dst, a );
strcat( dst, b );

strncat

尽管strncat也是一个长度受限的函数,但它和strncpy存在不同之外。它从src中最多复制len个字符到目标数组的后面。它的原型如下:

char *strcat( char *dst, char const *src );

但是,strncat总是在结果字符串后面添加一个NUL字节,而且它不会像strncpy那样对目标数组用NUL字节进行填充。注意目标数组中原先的字符串并没有算在
strncat的长度中。strncat最多向目标数组复制len个字符(再加一个结尾的NUL字节),它才不管目标参数除去原先存在的字符串之后留下的空间够不够。

4. 字符串比较

strcmp

比较两个字符串涉及对两个字符串对应的字符逐个进行比较,直到发现不匹配为止。那个最先不匹配的字符中较“小”(也就是说,在字符集中的序数较小)的那个字符所在的字符串被认为“小于”另外一个字符串。如果其中一个字符串是另外一个字符串的前面一部分,那么它也被认为“小于”另外一个字符串,因为它的NUL结尾字节出现得更早。这种比较被称为“词典比较”,对于只包含大写字母或只包含小写字母的字符串比较,这种比较过程所给出的结果总是和我们日常所用的字母顺序的比较相同。

库函数strcmp用于比较两个字符串,它的原型如下:

int strcmp( char const *s1, char const *s2 );

如果s1小于s2,strcmp函数返回一个小于零的值。如果s1大于s2,函数返回一个大于零的值。如果两个字符串相等,函数就返回零。注意标准并没有规定用于提示不相等的具体值。它只是说如果第1个字符串大于第2个字符串就返回一个大于零的值,如果第1个字符串小于第2个字符串就返回一个小于零的值。一个常见的错误是以为返回值是1和-1,分别代表大于和小于。但这个假设并不总是正确的。

对于这个函数常出现的错误是:

if( strcmp( a, b ) )

他以为如果两个字符串相等,它的结果将是真。但是,这个结果将正好相反,因为在两个字符串相等的情况下返回值是零(假)。然而,把这个返回值当作布尔值进行测试是一种坏风格,因为它具有三个截然不同的结果:小于、等于和大于。所以,更好的方法是把这个返回值与零进行比较。

由于strcmp并不修改它的任何一个参数,所以不存在溢出字符数组的危险。但是,和其他不受限制的字符串函数一样,strcmp函数的字符串参数也必须以一个NUL字节结尾。如果并非如此,strcmp就可能对参数后面的字节进行比较,这个比较结果将不会有什么意义。

strncmp

strncmp也用于比较两个字符串,但它最多比较len个字节。它的原型为:

int strncmp( char const *s1,char const *s2,size_t len );

如果两个字符串在第len个字符之前存在不相等的字符,这个函数就像strcmp一样停止比较,返回结果。如果两个字符串的前len个字符相等,函数就返回零。


参考

《C和指针》

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

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

相关文章

【K8S】常用的 Kubernetes(K8S)指令

常用的 Kubernetes&#xff08;K8s&#xff09;指令&#xff1a; 创建一个资源&#xff1a;kubectl create <资源类型> <资源名称> 例如&#xff1a;kubectl create deployment my-deployment 获取资源列表&#xff1a;kubectl get <资源类型> 例如&#xf…

[备忘.Linux]服务部署管理常用命令|systemd

在Linux上部署程序、排查程序问题会用到的一些常用命令。 偶尔会要用到&#xff0c;特放这里备忘和分享。 服务 服务&#xff08;service&#xff09;&#xff0c;指常驻在内存中的程序。 --启动服务。如果服务已经在运行&#xff0c;会忽略启动命令。 sudo systemctl star…

SpringBoot运行流程源码分析------阶段三(Spring Boot外化配置源码解析)

Spring Boot外化配置源码解析 外化配置简介 Spring Boot设计了非常特殊的加载指定属性文件&#xff08;PropertySouce&#xff09;的顺序&#xff0c;允许属性值合理的覆盖&#xff0c;属性值会以下面的优先级进行配置。home目录下的Devtool全局设置属性&#xff08;~/.sprin…

用 Go 访问 MySql 数据库

所有代码样例 package mainimport ("database/sql""fmt"_ "github.com/go-sql-driver/mysql" )var db *sql.DB// 初始化连接 func initDB() (err error) {db, err sql.Open("mysql", "root:mm..1213tcp(127.0.0.1:3306)/chapte…

【JavaEE】网络原理---TCP协议的易懂图文详解(确认应答、超时重传、连接管理、滑动窗口、流量控制)

一、TCP协议 TCP&#xff0c;即Transmission Control Protocol&#xff0c;传输控制协议。人如其名&#xff0c;要对数据的传输进行一个详细的控制。 1.1 TCP协议格式 &#xff08;为了方便排版这样化的&#xff0c;我们从上到下依次理解&#xff09; 二、TCP原理 2.1 确…

【linux系列】创建软连接

文章目录 作用命令创建软连接删除软链接修改软链接 参数 作用 现在服务器使用的时候&#xff0c;可视化界面仅显示固定目录下的内容&#xff0c;无法访问前序目录&#xff0c;导致查看内容非常麻烦&#xff0c;这时候软连接的作用就显现出来了&#xff0c;在当前目录下连接上&…

【Spring】使用aop切面编程时要给那些类加注解

&#x1f384;欢迎来到边境矢梦的csdn博文&#x1f384; &#x1f384;本文主要梳理 Spring 中使用aop切面编程时要给那些类加注解 &#x1f384; &#x1f308;我是边境矢梦&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以关注一…

C++入门(4):auto、范围for、nullptr

一、关键词 auto 1.1 概念 auto 作为一个新的类型指示符来指示编译器&#xff0c;auto 声明的变量必须由编译器在编译时期推导而得。 #include <iostream> using namespace std;int main() {int a 0;auto b a;auto c &a;auto* d &a;auto& e a;cout &…

使用达梦数据库的总结

–修改当前会话所在模式&#xff1a; set schema 模式名;–创建表空间、用户名并为用户指定表空间&#xff0c;并为用户授权 create tablespace "RSGL_BZK" datafile REGL_BZK.DBF size 7488 autoextend on next 128 maxsize 33554431 CACHE NORMAL; create user …

【工具】Java请求带http重定向的地址 自动进行重定向

【工具】Java请求带http重定向的地址 自动进行重定向 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL;public class HTTPGETWithMultipleHeaders {public static voi…

嵌入式实时操作系统的设计与开发(信号量学习)

信号量 除了临界点机制、互斥量机制可实现临界资源的互斥访问外&#xff0c;信号量&#xff08;Semaphore&#xff09;是另一选择。 信号量与互斥量的区别 对于互斥量来说&#xff0c;主要应用于临界资源的互斥访问&#xff0c;并且能够有效地避免优先级反转问题。对于信号量…

Linux下导出dump文件(Oracle和PG数据)

dump文件可以快速的导入导出&#xff0c;所以在数据量较大的情况下用其他方法导出数据都不如dump。 不管是什么数据库&#xff0c;第一步都需要登录Oracle用户 su - oracle登录之后可以选择导出文件到当前目录 Oracle数据库导出&#xff1a; exp 数据库用户名/密码localhos…

UE4 中可全局获取的变量(例如游戏实例、玩家控制器等) 详解

目录 0 引言1 全局对象&#xff08;全局变量&#xff09;1.1 游戏实例 GameInstance1.1.1 介绍1.1.2 使用 GameInstance 1.2 玩家控制器 PlayerController1.3 游戏世界类 UWorld &#x1f64b;‍♂️ 作者&#xff1a;海码007&#x1f4dc; 专栏&#xff1a;UE虚幻引擎专栏&…

优雅的使用String字符串处理各种类型转换

文章目录 &#x1f31f; 优雅的使用String字符串处理各种类型转换&#x1f34a; 基本类型转字符串&#x1f34a; 字符串转基本类型&#x1f34a; 字符串与字符数组的转换&#x1f34a; 字符串与字节数组的转换&#x1f34a; 其他类型转字符串&#x1f34a; 总结 &#x1f4d5;我…

Flask后端开发(一)-基础知识和前期准备

目录 1.背景介绍1.1. 项目背景1.2. 项目难点1.3. 项目环境 2. flask后端开发实现的功能3. flask部署和前后端对接3.1. flask运行配置和服务器部署3.2. flask前后端传参 4. 后端测试工具4.1. 工具介绍4.2. 工具使用 后记 1.背景介绍 1.1. 项目背景 就是前几个月临时接手了一个…

CPU眼里的C/C++: 1.3 汇编级单步调试函数执行过程

1. 目的 2. 基于 GDB 的汇编级单步调试 原始代码 #include <stdio.h>long test() {long a 1;a 2;return a; }int main() {int ret test();printf("test return %d\n", ret);return 0; }关键 gdb 命令 si 指令执行汇编级的单步调试info registers 读取寄…

【RocketMQ系列十四】RocketMQ中消息堆积如何处理

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…

RabbitMQ原理(五):消费者的可靠性

文章目录 3.消费者的可靠性3.1.消费者确认机制3.2.失败重试机制3.3.失败处理策略3.4.业务幂等性3.4.1.唯一消息ID3.4.2.业务判断 3.5.兜底方案 3.消费者的可靠性 当RabbitMQ向消费者投递消息以后&#xff0c;需要知道消费者的处理状态如何。因为消息投递给消费者并不代表就一定…

Unsupervised Medical Image Translation with Adversarial Diffusion Models

基于对抗扩散模型的无监督医学图像翻译 论文链接&#xff1a;https://arxiv.org/abs/2207.08208 项目链接&#xff1a;https://github.com/icon-lab/SynDiff Abstract 通过源-目标模态转换对缺失图像进行补全可以提高医学成像方案的多样性。利用生成对抗网络(GAN)进行一次映…

Leetcode—104.二叉树的最大深度【简单】

2023每日刷题&#xff08;六&#xff09; Leetcode—104.二叉树的最大深度 递归实现代码 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/int maxDepth(struct TreeNode* root){…