探索字符与字符串:基本库函数的使用(一)

news2024/11/19 18:17:59

目录

前言

函数介绍

        strlen

        strcpy

        strcat

        strcmp

        strncpy

        strncat

        strncmp

        strstr

        strtok

总结


前言

感谢您阅读我的博客。在本期文章中,我将为您介绍一些常用的字符和字符串处理函数,并提供一些注意事项和实现方法。


本期我们将会对以下库函数进行重点介绍以及模拟实现,其他的我们也会介绍使用方法以及注意事项。

求字符串长度
strlen

长度不受限制的字符串函数
strcpy
strcat
strcmp 

内存操作函数

memcpy
memmove

函数介绍

strlen

函数原型:

size_t strlen ( const char * str );

字符串以 '\0' 作为结束标志,strlen函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0')。
参数指向的字符串必须要以 '\0' 结束
注意函数的返回值为size_t,是无符号的( 易错 ),我们在使用strlen函数时要格外注意,例如以下代码:

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

我们可以判断出str1长度是大于str2的,可是最终的输出为:str2>str1,这是因为size_t,是无符号的,两个无符号的数据进行相减,最终结果也会是无符号的。

所以在使用的过程中要格外注意,避免这样直接做差来判断字符串(可以将类型转换为int类型再做差),视情况而定。

 strcpy

 函数原型:

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

 strcpy函数的作用是字符拷贝,destination为目标字符串,source为源字符串,将字符串source拷贝到destination目标字符串。

另外在使用时我们还要注意以下几点:

  • 源字符串必须以 '\0' 结束。
  • 会将源字符串中的 '\0' 拷贝到目标空间。
  • 目标空间必须足够大,以确保能存放源字符串。
  • 目标空间必须可修改
  • 目标空间必须可修改,举个例子:
int main()
{
	char arr1[] = "Hello world!";
	char* arr2 = "xxxxxxxxxxxxxxxxxxx";
	printf("%s\n", strcpy(arr2, arr1));
	return 0;
}

 这里的arr2确实指向一个字符串,但arr2的字符串属于常量字符串是不可以修改的。那么这样使用必然会使程序崩溃。

strcat

函数原型:

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

strcat函数的作用是连接两个字符串 ,将source这个源字符串追加到destination目标字符串的末尾。

注意事项:

  • 源字符串必须以 '\0' 结束,连接的过程中会将源字符串末尾的\0一同拷贝过去,作为字符串结束标志。
  • 目标空间必须有足够的大,能容纳下源字符串的内容。
  • 目标空间必须可修改。
  • 同一个数组字符串不可以自己给自己追加。即
strcat(arr, arr);

在某些编译器上或许能够运行成功,但是会出现使用未初始化的内存空间这样的警告,这样的操作是很危险的,所以还是建议尽量不要这样去用,至于为什么我会在模拟实现的时候向大家介绍原因。

strcmp

函数原型:

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

strcmp的作用时比较两个2字符串大小。

比较规则:

  • 第一个字符串大于第二个字符串,则返回大于0的数字
  • 第一个字符串等于第二个字符串,则返回0
  • 第一个字符串小于第二个字符串,则返回小于0的数字

那两个字符串是如何比较的呢?

strcmp函数会逐个比较两个字符串对应位置上的字符的ASCII码大小,直到遇到不相等的字符或者遇到字符串结束符'\0'。如果遇到不相等的字符,则返回两个字符的ASCII码差值;

我们来举例使用一下:

int main()
{
	int ret = strcmp("abcdef", "abc");//1
	int ret1 = strcmp("abcdef", "bbc");//-1
	int ret2= strcmp("abc", "abc");//0
	
	return 0;
}
  •  第一个比较,前三个字符相等到第四个字符对应位置进行比较,d和\0进行比较,‘d’>‘\0’所以返回大于0的数。
  • 第二个,两字符串第一个字符就不一样,那就对第一个字符进行比较,‘b'>‘a’所以返回小于0的数-1.
  • 第三个,两字符串相等,返回0。

strncpy

函数原型:

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

 作用:

  • 拷贝num个字符从源字符串到目标空间。
  • 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。

我们举例使用一下:

int main()
{
	char arr[20] = "abcdef";
	char arr1[] = "xxxxxxxxxxxxxxxx";
	strncpy(arr, arr1, 3);
	return 0;
}

 

 通过调试我们发现也确实只拷贝过去了三个。除此之外还有我们的strncat和strncmp

strncat

函数原型:

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

规则如下:

  • 将源字符串src的前n个字符(或者直到遇到源字符串的结束符'\0')追加到目标字符串dest的末尾
  • 追加完成后,目标字符串dest的末尾会自动添加一个结束符'\0

使用实例:

int main()
{
	char arr[20] = "abcdef";
	char arr1[] = "xxxxxxxxxxxxxxxx";
	strncat(arr, arr1, 3);
	return 0;
}

 将3个xxx添加到abcdef后边。

strncmp

函数原型:

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

 str1和str2是要比较的两个字符串,num是要比较的最大字符数。

比较规则和strcmp规则相同。

使用实例:

int main()
{
	char arr[] = "abcdef";
	char arr1[] = "abddd";
	printf("%d",strncmp(arr, arr1, 3));
	return 0;
}

 strstr

函数原型:

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

 作用:用于在一个字符串中查找指定子串的第一次出现位置。

规则如下:

  • 在字符串中查找子串的第一次出现位置。
  • 如果找到了子串,则返回指向该位置的指针。
  • 如果未找到子串,则返回NULL。

 使用实例:

int main()
{
	char a[] = "abcdefjhidef";
	char b[] = "def";
	printf("%s", strstr(a, b));//defjhidef
	return 0;
}

 strtok

函数原型:

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

 这个函数有点奇怪,和我们平常使用的库函数都有所不同,这个函数的作用是切割字符串,具体怎么切割,规则如下:

  • 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
  • strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
  • strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
  • strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
  • 如果字符串中不存在更多的标记,则返回 NULL 指针。

 什么意思呢?接下来我会用代码向大家展示:

int main()
{
	char arr[] = "hello$world@haha";
	char tarr[30];
	strcpy(tarr, arr);
	char sep[] = "$@";
	char* ret=strtok(tarr, sep);
	printf("%s", ret);//hello

	return 0;
}

 这段代码的输出是hello,sep是一个存放分割标记的数组,当在数组tarr中检查到sep中的字符时,strtok函数就会将该字符替换成\0,并返回到起始位置(字符串首元素地址处)。

如果再次调用该函数,传进去一个空指针:

int main()
{
	char arr[] = "hello$world@haha";
	char tarr[30];
	strcpy(tarr, arr);
	char sep[] = "$@";
	char* ret=strtok(tarr, sep);
	
	ret = strtok(NULL, sep);
	printf("%s", ret);//world
	return 0;
}

 它的输出就是world,从第一个切割标记的字符$那里开始,查找下一个标记处,将标记改位\0,返回本次函数调用标记的起始位置。直到遇到\0为止,返回一个空指针。

在使用时我们也可以这样使用:

int main()
{
	char arr[] = "hello$world@haha*666";
	char tarr[30];
	strcpy(tarr, arr);
	char sep[] = "$@*";
	char* ret = NULL;
	for (ret = strtok(tarr, sep); ret != NULL; ret = strtok(NULL, sep))
	{
		printf("%s\n", ret);
	}
	return 0;
}

 将ret=strtok(tarr, sep);作为初始值标记第一个分割点,ret != NULL;作为条件,ret = strtok(NULL, sep)作为自增量,这样不管我们是否知道需要分割的字符串被分割的次数,都可以将字符串根据自己的需求进行分割。

memcpy

 函数原型:

void * memcpy ( void * dest, const void * src, size_t n );

 作用:将指定长度的数据从源内存地址复制到目标内存地址。dest是目标内存地址,src是源内存地址,n是要复制的字节数。

规则如下:

  • 将源内存地址src中的前n个字节的数据复制到目标内存地址dest中。
  • 如果源内存地址和目标内存地址有重叠,复制的结果是不确定的。

 就是说如果将一个数组的片段,复制给同一个数组,就可能会导致复制重叠,无法达到我们预期的结果,不同的编译器结果可能也不相同。

例如:

int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr + 2, arr, 20);

 这样写可能会导致复制结果出错,建议不要这样去使用。

使用实例:

#include<string.h>//使用memcpy函数要引用头文件
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr1[20] = { 0 };
	memcpy(arr1, arr, 20);
	for (int i = 0; i < 20; i++)
	{
		printf("%d ", arr1[i]);
	}
	
	return 0;
}

 memmove

函数原型:

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

 使用规则如下:

  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理

 使用实例:

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr + 2, arr, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);//1 2 1 2 3 4 5 8 9 10
	}
	return 0;
}

 memcmp

函数原型:

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

 作用:

比较两个内存区域的内容是否相等。

其中ptr1和ptr2是要比较的两个内存区域的起始地址,num是要比较的字节数

比较规则如下:

  • 比较两个内存区域的前n个字节的内容。
  • 如果两个内存区域的内容相等,返回0。
  • 如果两个内存区域的内容不相等,返回两个不相等字节的差值(按字节的无符号比较)

 需要注意:

memcmp函数比较的是字节内容,而不是字符内容。因此,对于包含非字符数据(如结构体、数组等)的内存区域,也可以使用memcmp进行比较。

使用实例:

int main()
{
	int arr[] = { 1,2,1,4,5 };
	int arr1[] = { 1,2,257 };
	int ret=memcmp(arr, arr1, 9);
	printf("%d", ret);//0
	return 0;
}

 我们比较前9个字节的内存返回值为0,说明两数组前9个字节的内容相等。

通过调试我们也可以观察到:


总结

好的文章到这里内容到此就结束了,在学习字符和字符串处理函数的过程中,我们不仅需要掌握其使用方法,还需要了解其背后的原理和细节。希望本篇文章能够激发您对字符和字符串处理的兴趣,让您深入探究其中的奥秘。最后,感谢您的耐心阅读。如果您想了解更多关于字符和字符串处理的知识,请继续关注我的博客,下期我将对一些基本的库函数进行模拟实现。

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

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

相关文章

前端框架Layui实现动态表格效果用户管理实例(对表格进行CRUD操作-附源码)

目录 一、前言 1.什么是表格 2.表格的使用范围 二、案例实现 1.案例分析 ①根据需求找到文档源码 ②查询结果在实体中没有该属性 2.dao层编写 ①BaseDao工具类 ②UserDao编写 3.Servlet编写 ①R工具类的介绍 ②Useraction编写 4.jsp页面搭建 ①userManage.jsp ②…

如何清除视频和照片中水印的几种方式

文章目录 如何清除视频和照片中水印的几种方式一、清除视频中水印的几种方式1、截除水印区域2、模糊水印区域3、使用人工智能技术工具3.1 通过【iMyFone-MarkGo[^1]】消除水印3.2 通过【嗨格式视频转换器[^2]】消除水印3.3 通过【PR 视频编辑器】消除水印3.4 通过 【美图秀秀】…

从Vue2到Vue3【零】——Vue3简介及创建

系列文章目录 内容链接从Vue2到Vue3【零】Vue3简介及创建 文章目录 系列文章目录前言一、Vue3的发布带来了什么1.1 性能提升1.2 源码升级1.3 支持TypeScript1.4 新特性 二、创建Vue3.0工程2.1 什么是Vite2.2 利用Vite创建Vue3.0工程2.3 利用vue-cli脚手架创建Vue3.0工程 三、 …

iPad远控Windows解决方案

最近入手了一台iPad&#xff0c;但我不想让它沦为爱奇艺的工具&#xff0c;遂考虑如何在iPad上获得桌面级Windows的生产力。主要还是之前背着电脑出远门太累了&#xff0c;这也是促成我买iPad的重要因素。 一种方案就是通过远程控制&#xff0c;在iPad上远程操作自己的电脑&am…

【技能实训】DMS数据挖掘项目-Day10

文章目录 任务10【任务10.1.1】安装Mysql数据库&#xff0c;创建项目所需的数据库dms_学号、表及用户名、密码等&#xff0c;并搭建数据访问的基础环境(JDBC)【任务10.1.2】加载JDBC包【任务10.1.3】编写mysql.properties文件【任务10.1.4】编写Config类【任务10.2】编写访问数…

LinkedBlockingQueue 原理

目录 基本的入队出队 加锁分析 put 操作 take 操作 性能比较 LinkedBlockingQueue 是 Java 中用于实现线程安全队列的类。它是一个基于链接节点的阻塞队列&#xff0c;并且在队列为空时&#xff0c;获取元素的线程会阻塞;当队列满时&#xff0c;存储元素的线程会阻塞。Link…

re学习(16)[网鼎杯 2020 青龙组]singal1(魔法库:angr)

下载地址&#xff1a; BUUCTF在线评测 angr用法参考视频&#xff1a; angr符号执行练习 00_angr_find_哔哩哔哩_bilibili 本题其实也是可以通过静态分析得到的&#xff0c;详细地址请观看&#xff1a;【CTF&WP&BUUCTF】网鼎杯2020青龙组Singal_哔哩哔哩_bilibili …

Spring Security OAuth 2.0

1 概念 OAuth 2.0 到底是什么呢&#xff1f;我们先从字面上来分析下。OAuth 2.0 一词中的字母 “O” 是 Open 的简称&#xff0c;表示 “开放” &#xff0c; “Auth” 表示 “授权”&#xff0c;连在一起就表示 “开放授权”。 OAuth 2.0是一种授权框架&#xff0c;提供了一…

Linux下做性能分析5:Amdahl模型

[前言] 前一个Blog我们使用了一个叫cs的程序作为例子&#xff0c;那个程序是我为了举例子临时写的&#xff0c;这个代码我共享在这里&#xff1a;GitHub - nekin2012/btest。后面我要再举例子的话&#xff0c;就都加到这个地方来。由于这些代码没有经过最基本的软件质量保证工…

Visual Studio 自定义的颜色字体不生效

问题描述&#xff1a; 1、dll1中引用第三方库的类不识别&#xff0c;颜色黑白&#xff0c;自定义颜色不生效&#xff1b;定义的是结构体 2、在dll2引用另一个dll1中的结构体。结构体不识别&#xff0c;今天成员函数cpp中自定义颜色不生效。 问题解决方式&#xff1a; 全部清…

基于linux下的高并发服务器开发(第一章)- GDB调试(4)1.16

05 / GDB命令-调试命令 在第8行打上断点和bubbleSort打上断点 在第16行也打上断点&#xff0c;然后i b查看断点 执行run&#xff0c;停在第一个断点&#xff0c;这一行还没有执行 接下来按c继续执行&#xff0c;停在了bubbleSort list bubble.cpp:bubbleSort

【C】动态内存管理详解

动态内存管理 C/C内存开辟区域为什么存在动态内存分配&#xff1f; 动态内存函数的介绍&#xff08;在头文件stdlib.h中&#xff09;mallocfreecallocrealloc 常见的动态内存的错误对NULL解引用操作对动态开辟的空间进行越界访问对非动态开辟的空间进行free释放使用free释放动态…

探索Python异常:让程序不再崩溃!

文章目录 前言什么是异常捕获异常基本语法捕获指定类型异常捕获多个指定类型的异常捕获异常描述信息捕获所有异常elsefinally 异常的嵌套自定义异常结语 前言 在编程的世界中&#xff0c;我们常常会面对各种各样的错误和异常情况。尤其当我们使用Python这样的高级编程语言时&a…

4. 设计测试用例 (一) 等价类 边界值 判定表

目录 1. 设计测试用例的基本要素 1.1 测试用例概念 1.2 测试用例要素 1.3 测试用例的重要性 2. 测试用例设计方法 2.1 基于需求设计测试用例 步骤 2.2 练习设计测试用例 2.3 具体设计测试用例方法 2.3.1 等价类 设计测试用例步骤 举例 2.3.2 边界值 设计测试用例…

PowerDesigner 数据库建模使用详解

目录 一、前言 二、PowerDesigner概述 2.1 PowerDesigner核心能力 2.1.1 集成多种建模能力 2.1.2 自动生产代码能力 2.1.3 强大的逆向工程能力 2.1.4 可扩展的企业库解决方案 2.2 PowerDesigner常用的几种模型 2.2.1 概念模型 2.2.2 逻辑数据模型 2.2.3 物理模型 2.2…

综合能源系统(2)——综合能源系统典型应用场景

综合能源系统关键技术与典型案例  何泽家&#xff0c;李德智主编 根据空间分布范围特征&#xff0c;综合能源系统可大致划分为楼宇级、园区级以及区域级。楼宇级综合能源系统适用于办公楼、家庭、商场等单一主体区域&#xff0c;投资、建设和运营模式较为简单&#xff0c;技术…

arm学习stm32芯片学习方波启动蜂鸣器,马达,风扇,裸机开发,soc

main.c #include "pwm.h" extern void printf(const char *fmt, ...); void delay_ms(int ms) {int i,j;for(i 0; i < ms;i)for (j 0; j < 1800; j); } int main() {//蜂鸣器初始化hal_pwm_beep_init1();//马达hal_pwm_motor_init1();//风扇hal_pwm_blower_…

基于Vue3+LeaderLine实现画线测距及线条自由调整

先看下效果&#xff1a;我们画线后可以根据比例关系自动计算距离&#xff0c;并且线条不对可以自由调整 <template><div id"image-detail"><el-image :src"myImageUrl" style"height: auto; width: 800px;" fit"scale-dow…

Django实现接口自动化平台(十)自定义action names【持续更新中】

相关文章&#xff1a; Django实现接口自动化平台&#xff08;九&#xff09;环境envs序列化器及视图【持续更新中】_做测试的喵酱的博客-CSDN博客 深入理解DRF中的Mixin类_做测试的喵酱的博客-CSDN博客 python中Mixin类的使用_做测试的喵酱的博客-CSDN博客 本章是项目的一…

高数笔记5(第一章函数 极限 连续-第三节-函数的连续性)

目录 第三节 函数的连续性&#xff08;1&#xff09;函数的连续性例1&#xff08;补充定义&#xff0c;函数连续&#xff09;例4&#xff08;无穷小*有界量&#xff09;例6 &#xff08;补充定义&#xff0c;三角函数的代换的妙用&#xff09; &#xff08;2&#xff09;连续函…