【C生万物】 字符串内存函数篇 (上)

news2024/11/26 4:53:25

 欢迎来到 Claffic 的博客 💞💞💞                               👉 专栏:《C生万物 | 先来学C》👈

前言:

过了指针这个坎后,下一步就是C语言中关于字符的处理,这一期来讲讲常用字符函数和字符串函数:strlen,strcpy,strcat,memcpy,memmove,memcmp 等。 


目录

Part1:写在前面

Part2:函数介绍

1.strlen

2.strcpy

3.strcat

4.strcmp

5.strncpy

6.strncat

7.strncmp

8.strstr

9.strtok

10.memcpy

11.memmove

12.memcmp 


Part1:写在前面

说到字符串大家应该不陌生了,但你知道如何处理字符串吗?

C 语言中对字符和字符串的处理很是频繁,但是 C 语言本身是没有字符串类型的(在C++中解决了这个问题,引入了string类),字符串通常放在常量字符串中或者 字符数组 中。
字符串常量 适用于那些对它不做修改的字符串函数 .

Part2:函数介绍

1.strlen

strlen - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strlen/?kw=strlen

size_t strlen ( const char * str );

这个函数是获取字符串长度的,下面是注意的点:

• 字符串已经 '\0' 作为结束标志, strlen 函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' );
• 参数指向的字符串必须要以 '\0' 结束;
• 注意函数的返回值为 size_t ,是无符号的。

可以利用此函数来比较两个字符串的大小:

#include<stdio.h>
#include<string.h>
int main()
{
	const char* str1 = "abcdef";
	const char* str2 = "ggg";
	if (strlen(str2) - strlen(str1) > 0)
	{
		printf("str2>str1\n");
	}
	else
	{
		printf("srt1>str2\n");
	}
	return 0;
}

👁️‍🗨️运行结果: 

2.strcpy

strcpy - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strcpy/?kw=strcpy

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

这个函数是用来拷贝字符串的

注意传参:将后部的字符串拷贝到前部的空间中

• 源字符串必须以 '\0' 结束;
• 会将源字符串中的 '\0' 拷贝到目标空间;
• 目标空间必须足够大,以确保能存放源字符串;
• 目标空间必须可变。

例子:

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[40];
	const char* str2 = "abc";
	char* str = strcpy(str1, str2);
	printf("%s\n", str);

	return 0;
}

 👁️‍🗨️运行结果: 

3.strcat

strcat - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strcat/?kw=strcat

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

这个函数是在一个字符串末尾追加字符串的

• 源字符串必须以 '\0' 结束;
• 目标空间必须有足够的大,能容纳下源字符串的内容;
• 目标空间必须可修改。

例子:

#include<stdio.h>
#include<string.h>
int main()
{
	char str[80];
	strcpy(str, "these ");
	strcat(str, "strings ");
	strcat(str, "are ");
	strcat(str, "concatenated.");
	puts(str); // 输出字符串,传递char*类型,遇到\0结束
	return 0;
}

👁️‍🗨️运行结果:

4.strcmp

strcmp - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strcmp/?kw=strcmp

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

这个函数的作用就是比较两个字符串的

标准规定: 

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

注意注意:不是比较字符串的长度,而是一个字符一个字符地比较字符的 ASCII 码值

例子:

#include<stdio.h>
#include<string.h>
int main()
{
	char* str1 = "abcdef"; 
	char* str2 = "abcdef";
	char* str3 = "abcde";
	char* str4 = "cpp";

	printf("%d\n", strcmp(str1, str2));
	printf("%d\n", strcmp(str1, str3));
	printf("%d\n", strcmp(str1, str4)); // 第一个字符就小

	return 0;
}

 👁️‍🗨️运行结果:

其实这个函数的最大作用就是0的情况,即判断两个字符串相等。

5.strncpy

strncpy - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strncpy/?kw=strncpy

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

这个函数也是拷贝字符串的,不过它相比 strcpy 多了一个参数 num ,说明可以指定拷贝字符串的字符个数。

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

例子:

#include<stdio.h>
#include<string.h>
int main()
{
	char str1[40] = { '0' };
	char str2[30] = { '0' };
	const char* str3 = "abcdef";

	strncpy(str1, str3, 6);
	strncpy(str2, str3, 2);

	printf("%s\n", str1);
	printf("%s\n", str2);

	return 0;
}

👁️‍🗨️输出结果: 

6.strncat

 strncat - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strncat/?kw=strncat

这个函数也是,加了 n ,可控制要追加的字符长度

• 追加字符,

例子:

#include <stdio.h>
#include <string.h>
int main()
{
	char str1[20];
	char str2[20];
	strcpy(str1, "To be "); str1 中存入 To be
	strcpy(str2, "or not to be"); str2 中存入 or not to be
	strncat(str1, str2, 6); str1 追加 str2 中的6个字符 or no
	puts(str1);
	return 0;
}

👁️‍🗨️输出结果: 

7.strncmp

 strncmp - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strncmp/?kw=strncmp

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

相比 strcmp,它可以指定最多比较 num 个字符

• 比较到出现另个字符不一样或者一个字符串结束或者 num 个字符全部比较完。

例子:

#include <stdio.h>
#include <string.h>
int main()
{
	char str[][5] = { "R2D2" , "C3PO" , "R2A6" };
	int n;
	puts("Looking for R2 astromech droids...");
	for (n = 0; n < 3; n++)
	{
		if (strncmp(str[n], "R2xx", 2) == 0)
			printf("found %s\n", str[n]);
	}
	return 0;
}

 👁️‍🗨️输出结果: 

这个例子的意思就是在 str 中寻找含有 R2 的字符串。

8.strstr

strstr - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strstr/?kw=strstr

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

这个函数的作用就是寻找相等的字符串,返回指针类型

• 在 str1 中寻找 str2 ,找到了就返回指向 str1 中与 str2 相同字符的指针,如果没有(str2 不是 str1 的一部分),就返回 NULL

• 匹配过程不包括空字符串。 

例子:

#include <stdio.h>
#include <string.h>
int main()
{
	char str[] = "This is a simple string";
	char* pch;
	pch = strstr(str, "simple");
	if (pch != NULL)
		strncpy(pch, "sample", 6);
	puts(str);
	return 0;
}

👁️‍🗨️输出结果:

简单解释,在 str 中寻找字符串 simple,将其地址保存到 pch 中,再将 simple 替换为 sample,最终输出替换后的结果。

9.strtok

strtok - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/strtok/?kw=strtok

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

这个函数是做字符串切分的

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

看着挺复杂的,其实... ...就是复杂的。

接下来看个例子,相信会好些:

#include <stdio.h>
#include <string.h>
int main()
{
	char str[] = "- This, a sample string.";
	char* pch;
	printf("Splitting string \"%s\" into tokens:\n", str);
	pch = strtok(str, " ,.-"); // 分割符可以是字符集合
	while (pch != NULL)
	{
		printf("%s\n", pch);
		pch = strtok(NULL, " ,.-");
	}
	return 0;
}

 👁️‍🗨️输出结果:

这个例子就是将字符串 - This, a sample string. 按照 , - . 三个分隔符切割,注意进行多个字符的切割时,要进行 pch = strtok(NULL, " ,.-"); 操作,对应 strtok 函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记 

10.memcpy

 
memcpy - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/memcpy/?kw=memcpy

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

这个 void 类型不是没有,而是可以接受多种类型 

这个函数是复制数据用的

• 函数  memcpy  从  source  的位置开始向后复制  num  个字节的数据到  destination  的内存位置;
• 这个函数在遇到 '\0' 的时候并 不会 停下来;
• 如果 source   和  destination   有任何的重叠,复制的结果都是未定义的。  

例子:

#include <stdio.h>
#include <string.h>

struct 
{
	char name[40];
	int age;
} person, person_copy;

int main()
{
	char myname[] = "Pierre de Fermat";

	/* using memcpy to copy string: */
	memcpy(person.name, myname, strlen(myname) + 1);// +1是要把'\0'拷贝上 
	person.age = 46;

	/* using memcpy to copy structure: */
	memcpy(&person_copy, &person, sizeof(person));

	printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);

	return 0;
}

👁️‍🗨️输出结果:

解释:定义了一个结构体,包含名字和年龄,先将 myname 中的内容拷贝到结构体的 name 成员中,再将整个结构体拷贝给自己(可拷贝类型有多种)。 

11.memmove

 
memmove - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/memmove/?kw=memmove

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

参数类型与 memcpy 是相同的,两者的不同在哪里呢?

• 差别就是 memmove 函数处理的源内存块和目标内存块是可以重叠的;

• 如果源空间和目标空间出现重叠,就得使用 memmove 函数处理。

也就是说,在不确定源空间和目标空间是否重叠的情况下,memmove 可以保证拷贝的内容是正确的,所以 memmove 相比 memcpy 更安全。

例子:

#include <stdio.h>
#include <string.h>

int main()
{
	char str[] = "memmove can be very useful......";
	memmove(str + 20, str + 15, 11);
	puts(str);
	return 0;
}

👁️‍🗨️输出结果:

这个例子可以充分说明源空间和目标空间存在重叠的时候可以保证拷贝成功。

12.memcmp 

memcmp - C++ Reference (cplusplus.com)https://legacy.cplusplus.com/reference/cstring/memcmp/?kw=memcmp

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

看返回类型是 int 类型,啊哈,这个函数是比较两个数据的

• 比较从  ptr1    ptr2  指针开始的  num  个字节;

例子:

#include <stdio.h>
#include <string.h>

int main()
{
	char buffer1[] = "DWgaOtP12df0";
	char buffer2[] = "DWGAOTP12DF0";
	int n;
	n = memcmp(buffer1, buffer2, sizeof(buffer1));
	// 注意:大写字符的ASCII码值 小于 小写字符的ASCII码值
	if (n > 0) 
		printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
	else if (n < 0) 
		printf("'%s' is less than '%s'.\n", buffer1, buffer2);
	else 
		printf("'%s' is the same as '%s'.\n", buffer1, buffer2);

	return 0;
}

👁️‍🗨️输出结果:

大写字符的ASCII码值 小于 小写字符的ASCII码值

所以才会有这样的结果,跟想想中的不一样... ... 


总结: 

这期主要是带大家认识各种常见的字符串处理函数,知道有这些好用的函数并且会应用就可以了,下期带大家尝试实现几个其中的函数。

码文不易 

如果你觉得这篇文章还不错并且对你有帮助,不妨支持一波哦  💗💗💗

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

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

相关文章

chatgpt赋能Python-python5个一行

Python: 5行代码改变世界 Python是一种高级编程语言&#xff0c;以其简单易学的特性而闻名。Python的发明者Guido van Rossum在1980年代末和1990年代初创造了Python&#xff0c;旨在创建一种语言&#xff0c;既易于理解又易于使用。如今&#xff0c;Python已经成为了最受欢迎的…

【离散数学】陪集和拉格朗日定理编程题

1&#xff1a;编写一个程序能够计算有限群G的子群H的左陪集 输入一个n阶有限群G的二元运算表及相关的子群&#xff0c;输出其左陪集。 &#xff08;注意&#xff1a;按照表头元素顺序计算每个陪集&#xff0c;下图为G的二元运算表示例&#xff09; 样例1&#xff1a; 输入&…

干货 | 利用SPSS进行高级统计分析第三期

Hello&#xff0c;大家好&#xff01; 这里是壹脑云科研圈&#xff0c;我是喵君姐姐~ 在本期中&#xff0c;我们继续为大家介绍如何利用SPSS进行&#xff1a;单因素方差分析、多因素方差分析、重复测量方差分析等。 1. 单因素方差分析【组间实验单一因变量&#xff1b;进行差…

iptables防火墙中的SNAT和DNAT

SNAT的原理和应用 SNAT 应用环境∶局域网主机共享单个公网IP地址接入Internet &#xff08;私有IP不能在Internet中正常路由&#xff09; SNAT原理∶修改数据包的源地址。 SNAT转换前提条件∶ 局域网各主机已正确设置IP地址、子网掩码、默认网关地址Linux网关开启IP路由转发…

游资92科比到底牛在哪里?

昨天一天时间把92科比之前的一个帖子全部看完&#xff0c;从科比对情绪周期的把握来看那简直总结的已经是标准答案了&#xff0c;那么为何92科比公布了答案&#xff0c;还是有很多人“痛苦”的做不到&#xff1f; 这个问题我觉得跟退学炒股是一样的&#xff0c;退学先解决了小…

springcloud-alibaba (03)sentinel下载安装

Sentinel 一&#xff0c;下载安装&#x1f4a0;二&#xff0c;编写脚本&#x1f9ff;三&#xff0c;启动sentinel&#x1f48e;四&#xff0c;Win-访问控制台✨ 在Linux中下载安装Spring Cloud Alibaba Sentinel&#xff0c;可以按照以下步骤进行操作&#xff1a; 一&#xff0…

Python常见面试题. Python中的解包操作及其应用场景

这是个简单的知识点&#xff0c;但有的同学并不理解 unpacking解包 解&#xff0c;对应的是*或者**&#xff0c;也有自动解包之说 包对应的可迭代对象 Python助学大礼包点击跳转获取 目录 一、自动解包二、数据过多的解包*三、星号在函数中的使用四、两个星号的解包五、场…

Lesson13---人工神经网络(2)

13 人工神经网络&#xff08;2&#xff09; 多层神经网络-非线性分类问题多层神经网络的损失函数不是凸函数&#xff0c;很难计算解析解通常采用梯度下降法&#xff0c;得到数据解&#xff0c;梯度下降法可以用来求解函数极值问题 批量梯度下降随机梯度下降小批量梯度下降 1…

[Nacos] Nacos Client获取所有服务和定时更新Client端的注册表 (三)

文章目录 1.Nacos Client获取所有服务1.1 Client如何获取所有服务1.2 Client获取服务方法getServices()详解 2.Nacos定时更新Client端的注册表2.1 Nacos和Eureka定时更新Client端的注册表的区别2.2 Client定时更新本地服务过程2.3 updateServiceNow方法解析2.4 定时更新本地注册…

DrissionPage学习(一)

一、下载适合mac环境的chromedriver.exe 1.查找chrome浏览的版本 方法二&#xff1a;查看chrome版本信息 2.确定版本后在下载chrome对应的chromedriver.exe 下载地址&#xff1a;http://chromedriver.storage.googleapis.com/index.html 3.在文件夹中找到下载的文件chro…

MyBatis-Plus or() equls() 连用的格式为 a AND (b OR c)

正确示范&#xff1a; userInterfaceQueryWrapper.and(qw -> qw .eq("status", UserInterfaceInfoStatusEnum.OFFLINE) .or() .eq("status", UserInterfaceInfoStatusEnum.TRYOUT));错误示范&#xff1a; userInterfaceQueryWrapper.eq("status&…

分布式项目10.jsonp 使用js中script的属性src进行服务器之间的访问

一般使用ajax来访问不同服务器的数据&#xff0c;可行吗&#xff1f; 做个实验&#xff1a; 第一步&#xff1a;在本服务器中使用ajax技术访问本服务器数据 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title>测试JSON跨域…

NFT游戏Mythical Beings将参加NFT Polygon 在线展会

Mythical Beings神秘生物是由Tarasca Art & Games 开发的基于区块链的卡牌收集游戏。游戏中每张卡牌所拥有的属性和背后的故事都是独一无二的&#xff0c;Mythical Beings不仅具有游戏属性&#xff0c;还兼具故事的传承。 作为一款跨链Polygon的NFT游戏&#xff0c;Mythic…

Transformer架构解析

1.Transformer架构图 本文主要来自&#xff1a;http://nlp.seas.harvard.edu/annotated-transformer/#hardware-and-schedule 论文地址: https://arxiv.org/pdf/1810.04805.pdf 1.1 Transformer模型的作用 基于seq2seq架构的transformer模型可以完成NLP领域研究的典型任务,…

ThinkPHP6模型中的获取器,修改器及搜索器的简单使用

ThinkPHP6模型中的获取器&#xff0c;修改器及搜索器的简单使用 1. 获取器2. 修改器3. 搜索器 1. 获取器 获取器的作用是对模型实例的&#xff08;原始&#xff09;数据做出自动处理。一个获取器对应模型的一个特殊方法&#xff08;该方法必须为public类型&#xff09;&#x…

MySQL(用户管理)

文章目录 1 用户1.1 用户信息1.2 创建用户1.3 删除用户1.4 修改用户密码 2 数据库的权限2.1 给用户授权2.2 回收权限 1 用户 1.1 用户信息 MySQL中的用户&#xff0c;都存储在系统数据库mysql的user表中 host&#xff1a; 表示这个用户可以从哪个主机登陆&#xff0c;如果是l…

GPT专业应用:如何让GPT策划方案

身为一名职场打工人&#xff0c;或多或少会面临需要写策划案的难题。 不管是策划一场线下活动&#xff0c;还是策划业务发展的方向&#xff1b; 甚至到生活中还需要策划婚礼&#xff0c;策划房屋装修&#xff0c;策划和朋友的聚会等等。那么如何快速积累经验&#xff0c;找准…

项目管理基础:什么是项目管理?

一、项目管理的缘起与发展 项目管理并非基础学科&#xff0c;它是人类在生产实践中不断的经验积累所总结归纳的一门学科&#xff0c;在人们不断的完善与修订下逐步形成了现有的项目管理知识体系。 项目经理是随着人们对项目管理要求的提升而逐渐分化出的一个专业职位&#xf…

SNAT与DNAT的应用

目录 一、SNAT概述 1.SNAT应用环境——局域网共享上网 2. SNAT工作原理 2.1未作SNAT转换时 2.2进行SNAT转换后 二、配置SNAT策略 1.开启IP路由转发 2.SNAT转换 3.模拟实验 3.1服务端 3.2网关服务器 3.3网关服务器设置iptables规则 3.4客户端 3.5实验结果 三、DNAT概…

Tauri应用开发(二):创建第一个Tauri应用

创建tauri应用 推荐参考官方文档&#xff1a;https://tauri.app/v1/guides/ 创建命令&#xff1a; npm create tauri-applatest&#x1f4a1;注意&#xff1a;请确保Node.js和Rust已经正确安装 在创建过程中&#xff0c;需要根据提示选择配置项。 主要配置有&#xff1a; 项目…