学C的第二十八天【字符串函数和内存函数的介绍(一)】

news2025/6/10 0:20:24

=========================================================================

相关代码gitee自取:C语言学习日记: 加油努力 (gitee.com)

 =========================================================================

接上期

学C的第二十七天【指针的进阶(三)】_高高的胖子的博客-CSDN博客

 =========================================================================

                     

前言:

(1).

C语言中对于字符字符串的处理很是频繁,但是C语言本身没有字符串类型字符串通常放在 常量字符串 中或者 字符数组

             

(2).

字符串常量 适用于那些对其不做修改字符串函数

             

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

1 . 函数介绍

(1). strlen()函数:求字符串(字符数组)长度

函数返回值类型和相关参数:

             

size_t strlen ( const char * str );

                    

(接收 常量字符指针 ,返回 无符号整数

                    

注意事项:

(1).

字符串以 '\0' 作为结束标志,需要 string.h 头文件strlen函数返回的是在字符串中 '\0' 前面出现的字符个数不包 含 '\0' )。

                  

(2).

参数指向的字符串必须要以 '\0' 结束(不然统计个数为随机值)。

                

(3).

注意函数的返回值为size_t,是无符号的( 易错 ),如下:

                

(4).

学会strlen函数的模拟实现(下面第2个模块有)

                     


                    

(2). strcpy()函数:拷贝字符串

函数返回值类型和相关参数:

             

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

                     

(接收 目标空间指针内容不能被修改的源字符串指针 ,返回 目标空间指针

                    

注意事项:

(1).

源字符串指针 指向的 字符串 复制目标空间指针 指向的空间 中,

包括 终止空字符即 \0 ,并在该点停止

                  

(2).

源字符串必须以 '\0' 结束

                

(3).

会将源字符串中的 '\0' 拷贝到目标空间

                

(4).

目标空间必须足够大,以确保能存放源字符串

                

(5).

目标空间必须可变

                

(6).

学会strcpy函数的模拟实现(下面第2个模块有)

                     


                    

(3). strcat()函数:追加字符串到另一字符串后

函数返回值类型和相关参数:

             

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

                     

(接收 目标空间指针内容不能被修改的源字符串指针 ,返回 目标空间指针

                    

注意事项:

(1).

源字符串的副本追加到目标字符串

目的地中的 '\0' 源字符串的第一个字符覆盖

并且 '\0'在新字符串的末尾

需要<string.h>头文件。

                  

(2).

源字符串必须以 '\0' 结束

                

(3).

目标空间必须有足够的大,能容纳下源字符串的内容

                

(4).

目标空间必须可修改

             

(5).

学会strlen函数的模拟实现(下面第2个模块有)

                     


                    

(4). strcmp()函数:比较两个字符串的大小

函数返回值类型和相关参数:

             

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

             

(接收 两个常量字符串的首字符指针,返回 一个整数

                    

注意事项:

(1).

此函数开始比较时会比较每个字符串的第一个字符

如果它们彼此相等,则继续比较下一对

直到 字符不同 比较完所有字符都相同 为止

                  

(2). 标准规定

                   

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

(假设 “abcdef” 和 “abc” 比较,abc都相等第四次比较时 e>\0,那么"abcdef"更大返回 大于0 的数字

             

第一个字符串的字符 等于 第二个字符串的字符,则 返回0

(假设 “abc” 和 “abc” 比较,abc都相等第四次比较时 \0==\0返回 0

                         

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

(假设 “abcdef” 和 “abq” 比较,a和b都相等第三次比较时 c<q,那么"abq"更大返回小于0 的数字

                    

(3).

学会strlen函数的模拟实现(下面第2个模块有)

                     


                    

(5). strncpy()函数:拷贝字符串的num个字符

函数返回值类型和相关参数:

             

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

                   

和 strcpy()函数 相同,只是参数多了个 拷贝的字符个数

                    

注意事项:

(1).

将 源字符串指针 指向的 字符串前num个字符 复制到 目标空间指针 指向的空间 中,

包括 终止空字符,即 \0 ,并在该点停止。(和strcpy()函数类似但限制了拷贝个数

                  

(2).

源字符串拷贝num个字符到目标空间

                

(3).

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

                     


                    

(6). strncat()函数:追加字符串的num个字符到另一字符串

函数返回值类型和相关参数:

             

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

                   

和 strcat()函数 相同,只是参数多了个 拷贝的字符个数

                    

注意事项:

(1).

源字符串的副本的num个字符追加到目标字符串。

目的地中的 '\0' 被源字符串的第一个字符覆盖,

并且 '\0' 会在新字符串的末尾。

和strcat()函数类似但限制了追加个数

                  

(2).

如果源字符串的长度小于num,也只追加 源字符串 的字符串
    不会像strncpy一样补0

                     


                    

(7). strncmp()函数:在num个字符内比较两个字符串

函数返回值类型和相关参数:

             

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

            

和 strcmp()函数 相同,只是参数多了个 限定在num个字符中比较

                    

注意事项:

(1).

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

                        


                    

(8). strstr()函数:在字符串中找子字符串

函数返回值类型和相关参数:

             

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

                   

(参数接收 两个常量字符串,返回 字符指针

                    

注意事项:

(1).

str1 中 找 str2 首次出现的地址,如果 str2 中没有 str1 返回 空指针NULL

        

(4).

学会strstr函数的模拟实现(下面第2个模块有)

             


                    

(9). strtok()函数:使用自定义分隔符对字符串进行分割

函数返回值类型和相关参数:

             

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

                      

(参数接收 被分割的字符串首字符地址 指定的分隔符指针

返回 被分割的子字符串指针

                    

注意事项:

(1).

sep参数是个字符串,定义了用作分隔符的字符集合

                  

(2).

str参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记

                

(3).

strtok函数找到str中的下一个标记,并将其用 \0 结尾把找到的标记变为 \0 ),

返回一个指向这个标记的指针

(注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容 并且可修改。)

                

(4).

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

                

(5).

strtok函数第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始查找下一个标记

                

(6).

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

                     


                    

(10). strerror()函数:将错误码以字符串形式提供出来

函数返回值类型和相关参数:

             

char * strerror ( int errnum );

                      

(参数接收 错误码,返回 错误码的字符串信息地址

                     

注意事项:

(1).

库函数在执行时,发生了错误,会将一个错误码存放在 errno 这个变量中

errno C语言提供的一个全局变量

         

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

             

2 . 库函数的模拟实现

(1). 模拟实现strlen()函数:

方法1:计数器方式

                

对应代码:

#include <stdio.h>
//方法1:计数器方式
size_t my_strlen(const char* str)
	//和库函数的strlen函数一样
	//返回值为无符号整型,参数为常量字符指针
{
	int count = 0; //计数器
	while (*str != '\0')
		//还没到结束符就继续统计
	{
		count++;//没到结束符就统计+1
		str++;//判断下一位
	}
	return count;//返回计数器
}

int main()
{
	size_t sz = my_strlen("abc");
	//使用模拟实现的strlen函数返回一个size_t(无符号整数)的数

	//进行打印:
	printf("%u\n", sz);
	//%u:打印无符号的数

	return 0;
}

                  

方法2:指针方式

                

对应代码:

#include <stdio.h>
//方法2:指针方式
size_t my_strlen(const char* str)
//和库函数的strlen函数一样
//返回值为无符号整型,参数为常量字符指针
{
	char* p = str;
	while (*p != '\0')
		//还没到结束符就继续统计
	{
		p++;//没指向结束符就判断下一位
	}

	return p-str;//用移动后的指针 - 原来的指针 == 字符串长度
}

int main()
{
	size_t sz = my_strlen("abc");
	//使用模拟实现的strlen函数返回一个size_t(无符号整数)的数

	//进行打印:
	printf("%u\n", sz);
	//%u:打印无符号的数

	return 0;
}

                  

方法3:迭代方式

                

对应代码:

#include <stdio.h>
//方法3:迭代方式
size_t my_strlen(const char* str)
//和库函数的strlen函数一样
//返回值为无符号整型,参数为常量字符指针
{
	if (*str == '\0')
	{
		return 0;//如果第一个就指向\0,说明长度是0
	}
	else
	{
		return 1 + my_strlen(str + 1);
	}
}

int main()
{
	size_t sz = my_strlen("abc");
	//使用模拟实现的strlen函数返回一个size_t(无符号整数)的数

	//进行打印:
	printf("%u\n", sz);
	//%u:打印无符号的数

	return 0;
}

                  

(2). 模拟实现strcpy()函数:

主函数:

                    

模拟实现strcpy()函数:

                  

对应代码:

//模拟strcpy函数:
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src)
//返回值类型 和 参数 与库函数strcpy相同
//返回值设置为char*,是为了能够使用链式访问,把返回值作为其它函数的参数
{
	//保存目标空间指针原位置,方便最后进行返回
	char* ret = dest;

	//进行断言,两个指针都不为空指针,需要头文件<assert.h>
	assert(dest != NULL);
	assert(src != NULL);

	//只要 源字符串 还没指向 \0 就继续循环拷贝
	while (*src != '\0')
	{
		*dest = *src; //将源字符串的一位赋给目标空间
		//下次赋值下一位,所以要移动两个指针:
		dest++;
		src++;
	}

	//循环中没有将 \0 赋给目标空间,所以要加上:
	*dest = *src;
	//循环完后,dest移向了新位置,src在\0位置,所以直接赋值即可

	//返回拷贝后的目标指针原地址:
	return ret;
}

int main()
{
	//目标空间(字符数组):
	char arr1[20] = "xxxxxxxxxxxxxxxx";
	//源字符串:
	char arr2[] = "hello world";

	my_strcpy(arr1, arr2); //使用模拟的函数来拷贝
	//arr1为目标空间指针,arr2为源字符串指针
	//将arr2指向的内容 拷贝到 目标空间指针中

	//打印拷贝结果:
	printf("%s\n", arr1);

	return 0;
}

                       

可进行化简:

                 

对应代码:

//模拟strcpy函数:
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src)
//返回值类型 和 参数 与库函数strcpy相同
//返回值设置为char*,是为了能够使用链式访问,把返回值作为其它函数的参数
{
	//保存目标空间指针原位置,方便最后进行返回
	char* ret = dest;

	//进行断言,两个指针都不为空指针,需要头文件<assert.h>
	assert(dest != NULL);
	assert(src != NULL);

	//只要 源字符串 还没指向 \0 就继续循环拷贝
	while (*dest++ = *src++)
	{
		;
	}

	//返回拷贝后的目标指针原地址:
	return ret;
}

int main()
{
	//目标空间(字符数组):
	char arr1[20] = "xxxxxxxxxxxxxxxx";
	//源字符串:
	char arr2[] = "hello world";

	my_strcpy(arr1, arr2); //使用模拟的函数来拷贝
	//arr1为目标空间指针,arr2为源字符串指针
	//将arr2指向的内容 拷贝到 目标空间指针中

	//打印拷贝结果:
	printf("%s\n", arr1);

	return 0;
}

                

(3). 模拟实现strcat()函数:

                  

对应代码:

//模拟strcat函数:
#include <stdio.h>
#include <string.h>
#include <assert.h>

char* my_strcat(char* dest, const char* src)
{
	//进行断言,两个字符串都不为\0 (空)
	assert(dest);
	assert(src);

	//保存目标地址的原位置
	char* ret = dest;

	//找到目标字符串的\0,作为连接的起点:
	while (*dest)
	{
		dest++;
	}

	//开始连接字符串,和strcpy是一样的
	while (*dest++ = *src++)
	{
		;
	}

	//返回连接后的目标空间指针:
	return ret;
}

int main()
{
	//目标空间(数组):
	char arr1[20] = "hello";

	//源字符串:
	char arr2[] = " world";

	//使用模拟的自定义函数,将arr2连接到arr1后
	my_strcat(arr1, arr2);

	//打印连接后的新字符串:
	printf("%s\n", arr1);

	return 0;
}

                

(4). 模拟实现strcmp()函数:

                  

对应代码:

//模拟strcmp函数:
#include <stdio.h>
int my_strcmp(const char* str1, const char* str2)
{
	while (*str1 == *str2)
		//两字符串同位置上的值相同的情况
	{
		if (*str1 == '\0')
			//同位置上都是\0说明两个字符串相同
		{
			return 0; //相同则返回 0
		}
		//不是\0,是其它值相同,则判断下一位
		str1++;
		str2++;
	}

	if (*str1 > *str2)
		//当前位置,字符串1的字符大于字符串的字符
	{
		return 1; //大于则返回大于0的数
	}
	else
		//当前位置,字符串1的字符小于字符串的字符
	{
		return -1; //小于则返回小于0的数
	}
}

int main()
{
	//使用自定义函数进行比较:
	int ret = my_strcmp("abq", "abc");

	printf("%d\n", ret);

	return 0;
}

                

(5). 模拟实现strstr()函数:

模拟的自定义函数:

                      

主函数:

                   

对应代码:

//模拟strncmp函数:
#include <stdio.h>
#include <string.h>
char* my_strstr(char* str1, char* str2)
{
	char* cp = str1; //开始进行判断的初始位置指针
	char* s1 = cp; //在arr1中的cp位置开始逐位进行匹配的指针
	char* s2 = str2; //在arr2中逐位进行匹配的指针

	//如果要找的子字符串为空指针,则返回str1:
	if (*str2 == '\0')
	{
		return str1;
	}

	while (*cp != '\0')
		// \0之后不可能找到arr2的内容
	{
		//开始匹配:
		s1 = cp; //让s1在初始位置开始进行逐位判断
		s2 = str2;

		while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
			//两字符串都未到\0,如果当前位置的内容相同,则再循环判断下一位
		{
			s1++;
			s2++;
		}

		if (*s2 == '\0')
			//如果子字符串已经到了\0,
			//说明arr1中有arr2,匹配成功
		{
			return cp; 
			//匹配成功,则返回子字符串的初始位置
		}

		cp++; //判断arr1下一个初始位置
	}

	return NULL; //未找到则返回空指针
}

int main()
{
	char arr1[] = "abbbcdef";
	char arr2[] = "bbc";

	//使用自定义函数进行查找:
	char* ret = my_strstr(arr1, arr2);
	if (ret != NULL)
	{
		printf("%s\n", ret);
	}
	else
	{
		printf("未找到");
	}

	return 0;
}

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

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

相关文章

linux驱动开发:驱动开发框架,linux内核字符设备驱动开发过程

一、驱动框架 1.Linux内核模块和字符驱动的关系 模块是Linux进行组建管理的一种方式, 结构体:对设备的管理内核需要抽象出来一个结构体来描述设备所有的共性信息写驱动需要申请一个结构体并赋值(初始化),然后注册给内核让内核统一管理 驱动:由内核统一管理,所以驱动…

NUXT3学习笔记2

1、配置Ant design Vue (两个安装方式随便选一种&#xff0c;yarn会安装的更快) npm i ant-design-vue --save yarn add ant-design-vue 2、使⽤的 Vite&#xff0c;你可以使⽤ unplugin-vue-components 来进⾏按需加载。 yarn add unplugin-vue-components --save 在nuxt.…

设计模式——享元模式

享元模式 定义 享元模式&#xff08;Flyweight Pattern&#xff09;是池技术的重要实现方式。 使用共享对象可以有效地支持大量的细粒度对象。 优缺点、应用场景 优点 可以大大减少应用程序创建对象的数量&#xff0c;降低程序内存占用。 缺点 提高了系统的复杂度&…

5分钟上手IP代理服务

一 IP代理服务 在网上找了一个性价比高的IP代理服务&#xff0c;一个IP地址1分钱。 二 API协议 调用方式为http协议&#xff0c;响应数据格式支持JSON和txt&#xff0c;都是比较常用的方式。 三 源码范例 包括一些主流的编程语言&#xff0c;一分钟上手。 我用的python比较…

【Redis应用】查看附近(五)

&#x1f697;Redis应用学习第五站~ &#x1f6a9;本文已收录至专栏&#xff1a;Redis技术学习 查看附近的XXX在我们的实际应用中非常广泛&#xff0c;能支持该功能的技术有很多&#xff0c;而在我们的Redis中主要依靠GEO数据结构来实现该功能&#xff01; 一.GEO用法引入 GE…

问题解决:win10连接手机热点总是频繁自动断开

问题描述:尝试解决 问题解决:win10连接手机热点总是频繁自动断开 问题描述: 在使用win10笔记本电脑连接手机热点上网时,是不是的网络自动就断掉了,而且重新连上后,用着用着又断了, 这就让人有点恼火了, 尝试解决 重启电脑与手机 以前没出现过而现在有这种情况,可能是电脑或手机…

Spark复习笔记

文章目录 Spark在Hadoop高可用模式下读写HDFS运行流程构成组件作业参数RDD机制的理解算子map与mapPartition区别Repartition和Coalesce区别reduceBykey 与 groupByKeyreduceByKey、foldByKey、aggregateByKey、combineByKey区别cogroup rdd 实现原理宽窄依赖为什么要划分stage如…

Elasticsearch:语义搜索、知识图和向量数据库概述

结合对你自己的私有数据执行语义搜索的概述 什么是语义搜索&#xff1f; 语义搜索是一种使用自然语言处理算法来理解单词和短语的含义和上下文以提供更准确的搜索结果的搜索技术。 这种方法基于这样的想法&#xff1a;搜索引擎不仅应该匹配查询中的关键字&#xff0c;还应该尝…

LINUX命令:update-alternatives(软件版本管理工具)

前言   在基于 LINUX 操作系统之上安装所需开发环境组件时&#xff0c;可能会遇到无可避免的场景是&#xff1a;同一个组件&#xff0c;我们需要同时使用到两个或者更多的版本&#xff0c;比如 Java 有 1.6、1.7、1.8 等多版本&#xff0c;又比如 Python 有 2、3 等等&#x…

「2024」预备研究生mem-数学强化-整数、因数与倍数

一、整数、因数与倍数 二、带余除数 三、奇数与偶数 四、不定方程

Nature子刊-柔性薄膜上3D电极的直接激光写入

美国俄勒冈大学研究员设计了一种集成在柔性薄膜上的3D微电极阵列&#xff0c;其制造过程结合了传统的硅薄膜处理技术和双光子光刻在微米分辨率下的3D结构的直接激光书写技术&#xff0c;首次提出了一种产生高深宽比结构的方法。 发表在《自然通讯》杂志上的这项研究&#xff0c…

js实现控制台格式化打印版权信息(2023.7.16)

js代码在控制台格式化打印版权信息 2023.7.16 1、需求分析2、js实例&#xff08;浏览器版权信息&#xff09;2.1 百度一下2.1.1 js代码2.1.2 浏览器控制台输出效果 2.2 京东官网2.2.1 js代码2.2.2 浏览器控制台输出效果 2.3 EarthSDK地球页面2.3.1 js代码2.3.2 浏览器控制台输出…

【JMeter】JMeter进行JDBC数据库负载测试

JMeter进行JDBC数据库负载测试 前置准备1.创建线程组2.JDBC连接配置3.新建JDBC链接4.查看汇总报告 前置准备 此示例使用 MySQL 数据库驱动程序。 要使用此驱动程序&#xff0c;必须将其包含.jar文件&#xff08;例如 mysql-connector-java-X.X.X-bin.jar&#xff09;复制到 JM…

精选估值,解决买车卖车难题

在现代社会&#xff0c;车辆已经成为了人们生活中不可或缺的一部分。车辆的买卖交易也成为了许多人的生活中不可避免的问题。而估值则是买卖交易的过程中非常重要的一个环节。估值的准确与否直接影响到最后交易的结果。因此&#xff0c;选择一种准确便捷的估值方式就显得尤为重…

JAVA集合详解:用法、实例及适用场景

引言&#xff1a; 在JAVA编程中&#xff0c;集合是一种非常重要且常用的数据结构。通过使用集合&#xff0c;我们可以高效地组织和操作不同类型的数据。本文将深入探讨JAVA中各种集合的用法及实例&#xff0c;并介绍适用场景&#xff0c;以帮助更好地理解和应用集合。 --------…

TTX1994-可调谐激光器控制系统

花了两周时间&#xff0c;利用下班时间&#xff0c;设计了一个ITLA可调谐激光器控制系统&#xff0c;从硬件到软件。下面这个图片整套硬件系统&#xff0c;软件硬件都自己设计&#xff0c;可以定制&#xff0c;做到单片机问题也不大。相当于一套光源了 这是软件使用的界面&…

【算法】换根DP

文章目录 什么是换根DP例题分析——P3478 [POI2008] STA-Station题目列表1834. 树中距离之和⭐⭐⭐⭐⭐&#xff08;两次 dfs&#xff09;思路——冷静分析&#xff0c;列出式子算法分析⭐⭐⭐⭐⭐ 310. 最小高度树⭐⭐⭐⭐⭐2581. 统计可能的树根数目⭐⭐⭐⭐⭐C. Bear and Tr…

Coggle 30 Days of ML(23年7月)打卡

前言 最近开始关注LLM相关知识&#xff0c;但之前的NLP范式的技能不能丢。 这个练习还是比较适合我&#xff0c;感谢举办方选题&#xff0c;快速全部打卡一波。 打卡记录 任务一: 报名比赛&#xff0c;下载比赛数据集并完成读取 比赛链接&#xff1a;https://challenge.xfy…

第十六章:Understanding Convolution for Semantic Segmentation——理解用于语义分割的卷积

0.摘要 最近深度学习特别是深度卷积神经网络&#xff08;CNN&#xff09;的进展&#xff0c;显著提高了之前语义分割系统的性能。在这里&#xff0c;我们展示了通过操作与卷积相关的操作来改进逐像素的语义分割&#xff0c;这些操作在理论和实践上都具有价值。首先&#xff0c;…

【Java动态代理】—— 每天一点小知识

&#x1f4a7; J a v a 动态代理 \color{#FF1493}{Java动态代理} Java动态代理&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f984; 个人主页——微风撞见云的博客&#x1f390; &#x1f433; 《数据结构与算法》专栏的文章图文并茂&am…