C语言——字符串及字符函数的介绍

news2024/12/23 4:23:28

C语言——字符串及字符函数的介绍

  • 一、字符函数
    • 1.strlen
      • 1.1strlen的使用
      • 1.2strlen的三种模拟实现
        • 1.2.1计数器实现strlen函数
        • 1.2.2递归方法实现strlen函数
        • 1.2.3指针方法实现strlen函数
      • 1.3 注意事项
    • 2.strcpy
      • 2.1strcpy使用
      • 2.2strcpy的模拟实现
      • 2.3strcpy的注意事项
    • 3.strcat
      • 3.1strcat的使用
      • 3.2strcat的模拟实现
      • 3.3strcat注意事项:
    • 4.strcmp
      • 4.1strcmp的使用
      • 4.2strcmp的模拟实现
      • 4.3strcmp注意事项
    • 5.strstr
      • 5.1strstr的使用
      • 5.2strstr的模拟实现
    • 6.strtok
      • 6.1strtok的使用
      • 6.2strtok的使用注意事项
    • 7.memcpy
      • 7.1memcpy的使用
      • 7.2memcpy的模拟实现
      • 7.3memcpy的注意事项
    • 8.memmove
      • 8.1memmove的使用
      • 8.2memmove的模拟实现
      • 8.3memmove的注意事项:

一、字符函数

1.strlen

在这里插入图片描述

1.1strlen的使用

int main()
{
	char arr1[] = "hello world!";
	int ret = strlen(arr1);
	printf("%d", ret);
	return 0;
}

运行结果:
在这里插入图片描述

1.2strlen的三种模拟实现

1.2.1计数器实现strlen函数

int my_strlen(const char* arr1)
{
	assert(*arr1);
	int count = 0;
	while (*arr1 != '\0')
	{
		*arr1++;
		count++;
		
	}
	return count;
	
}
int main()
{
	char arr1[] = "hello world!";
	int ret = my_strlen(arr1);
	printf("%d", ret);
	return 0;
}

1.2.2递归方法实现strlen函数

//递归
//不创建临时变量求字符串长度
int my_strlen(const char* str)
{
	if (*str != '\0')
		return 1 + my_strlen(str + 1);
	else
		return 0;
}

1.2.3指针方法实现strlen函数

int my_strlen(const char* str)
{
	char* p = str;
	while (*p != '\0')
	{
		*p++;
	}
	return p - str;
}

int main()
{
	char arr1[] = "hello world!";
	int ret = my_strlen(arr1);
	printf("%d", ret);
	return 0;
}

1.3 注意事项

①、字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包含 ‘\0’ )。
②、参数指向的字符串必须要以 ‘\0’ 结束。
③、注意函数的返回值为size_t,是无符号的( 易错 )
eg1:

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

因为strlen函数的返回值为size_t,是无符号的,所以输出值为 printf(“str2>str1\n”);
运行结果:
在这里插入图片描述

2.strcpy

在这里插入图片描述

2.1strcpy使用

int main()
{
	char arr1[] = "hello world!";
	char arr2[20];
	strcpy(arr2, arr1);
	printf("%s", arr2);
	return 0;
}

运行结果:
在这里插入图片描述

2.2strcpy的模拟实现

char* my_strcpy(char* dest, const char* src)
{
	char* ret = dest;
	assert(dest && src);
	while (*dest ++= *src++)
	{
		;
	}
	return ret;

}
int main()
{
	char arr1[] = "hello world!";
	char arr2[20];
	my_strcpy(arr2, arr1);
	printf("%s", arr2);
	return 0;
}

2.3strcpy的注意事项

①、源字符串必须以 ‘\0’ 结束。
②、会将源字符串中的 ‘\0’ 拷贝到目标空间。
③、目标空间必须足够大,以确保能存放源字符串。
④、目标空间必须可变。

3.strcat

在这里插入图片描述

3.1strcat的使用

#include<stdio.h>
int main()
{
	char arr1[20] = "hello ";
	char arr2[20] = "world!";
	strcat(arr1, arr2);
	printf("%s\n", arr1);
	return 0;
}

运行结果:
在这里插入图片描述
调试过程:

在这里插入图片描述
在这里插入图片描述

3.2strcat的模拟实现

#include<stdio.h>
#include<assert.h>
char *my_strcat(char* dest, const char* src)
{
	//防止其为空指针
	assert(dest && src);
	char* ret = dest;
	//找到'\0'
	while (*dest != '\0')
	{
		dest++;
	}
	//拷贝
	while (*dest++ = *src++)
	{
		;
	}
	return ret;
}
int main()
{
	char arr1[20] = "hello ";
	char arr2[20] = "world";
	my_strcat(arr1, arr2);
	printf("%s", arr1);
	return 0;
}


运行结果:
在这里插入图片描述
接下来,让我们试试其是否可以追加自己

int main()
{
	char arr1[20] = "hello";
	char arr2[20] = "world!";
	strcat(arr1, arr1);
	printf("%s", arr1);
	return 0;
}

运行结果:
在这里插入图片描述
在这里插入图片描述

3.3strcat注意事项:

①、源字符串必须以 ‘\0’ 结束。
②、目标空间必须有足够的大,能容纳下源字符串的内容。
③、目标空间必须可修改
④、strcat()函数并不检查第一个数组是否能够容纳第二个字符串。如果没有为第一个数组分配足够大的空间,多出来的字符溢出到相邻存储单元时就会出现问题。

4.strcmp

在这里插入图片描述

4.1strcmp的使用

int main()

{
	char arr1[10] = "abcd";
	char arr2[10] = "bcde";
	int ret = strcmp(arr1, arr2);
	printf("%d", ret);
	return 0;
}

运行结果:
在这里插入图片描述

4.2strcmp的模拟实现

int my_strcmp(const char* arr1, const char* arr2)
{
	assert(arr1 && arr2);
	while (*arr1 == *arr2)
	{
		if (*arr1 == '\0')
			return 0;
		arr1++;
		arr2++;
	}
	return *arr2 - *arr1;
}
int main()
{
	char arr1[10] = "abcd";
	char arr2[10] = "bcde";
	int ret = my_strcmp(arr1, arr2);
	printf("%d", ret);
	return 0;
}

运行结果:
在这里插入图片描述

4.3strcmp注意事项

1.初学者常常会编写下面的表达式

if(strcmp(a,b))

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

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

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

5.strstr

在这里插入图片描述

5.1strstr的使用

#include<stdio.h>
#include<string.h>
int main()
{
	char arr1[20] = "hello.world!";
	char* pch;
	pch=strstr(arr1, "o");
	printf("%s", pch);
	return 0;
}

运行结果:
在这里插入图片描述

5.2strstr的模拟实现

char *my_strstr(const char* str1, const char* str2)
{
	char* s1 = NULL;
	char* s2 = NULL;
	char* cp =(char*) str1;
	while (*cp)
	{
		s1 = cp;
		s2 = (char*)str2;
		while (*s1 && *s2 && *s1 == *s2)
		{
			s1++;
			s2++;
		}
		if (*s2 == '\0')
		{
			return cp;
		}
		cp++;
	}


}
int main()
{
	char arr1[10] = "abcde";
	char arr2[10] = "bcdef";
	char* ret = my_strstr(arr1, arr2);
	if (ret == NULL)
	{
		printf("找不到\n");
	}
	else
		printf("%s", ret);
	return 0;
}

6.strtok

6.1strtok的使用

在这里插入图片描述
第一种方法:

int main()
{
	char arr1[20] = "1826362719@qq.com";
	const char *arr2 = "@.";
	char* str = strtok(arr1, arr2);
	printf("%s\n", str);
	str = strtok(NULL, arr2);
	printf("%s\n", str);
 str = strtok(NULL, arr2);
	printf("%s\n", str);
	return 0;
}

第二种方法:

int main()
{
	char arr1[20] = "1826362719@qq.com";
	char arr2[30] = { 0 };
	strcpy(arr2, arr1);
	const char *p = "@.";
	char* str = NULL;
	for (str = strtok(arr2, p); str!= NULL; str = strtok(NULL, p))
	{
		printf("%s\n",str);
	}
	return 0;
}

运行结果:
在这里插入图片描述

6.2strtok的使用注意事项

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

7.memcpy

在这里插入图片描述

7.1memcpy的使用

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

运行结果:
在这里插入图片描述

7.2memcpy的模拟实现

void* my_strcpy(void* dest, const void* src, size_t nums)
{
	assert(dest && src);
	void* ret = dest;
	while (nums--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
	float arr1[10] = { 1.0f,2.0f,3.0f,4.0f,5.0f,6.0f,7.0f,8.0f,9.0f,10.0f };
	float arr2[5] = { 0 };
	my_strcpy(arr2, arr1, 20);
	int i = 0;
	for (i = 0; i < 7; i++)
	{
		printf("%f ", arr2[i]);
	}
	return 0;

}

7.3memcpy的注意事项

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

8.memmove

在这里插入图片描述

8.1memmove的使用

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

运行结果:
在这里插入图片描述

8.2memmove的模拟实现

void* my_memmove(void* dest, void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	//前-》后
	if (dest < src)
	{
		while (num--)
		{
			*(char*)dest == *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;

		}
	}
	else//后--》前
		while (num--)
		{
			*((char*)dest + num) =* ((char*)src + num);
		}
	return ret;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr1 + 2, arr1, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

运行结果:
在这里插入图片描述

8.3memmove的注意事项:

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

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

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

相关文章

【小样本分割 2022 ECCV】SSP

文章目录 【小样本分割 2022 ECCV】SSP摘要1. 介绍2. 相关工作3. 自支持小样本语义分割3.1 动机3.2 自支持原型-SSM3.3 自适应自支持背景原型-ASBP3.4 自支持匹配-SSL 3. 代码 【小样本分割 2022 ECCV】SSP 论文题目&#xff1a;Self-Support Few-Shot Semantic Segmentation 中…

SpringCloud 微服务系列——【Gateway、Config组件使用】

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

第二十三章 材质

3D模型主要是通过材质&#xff08;Material&#xff09;和贴图&#xff08;Texture&#xff09;来表现其精美的外表&#xff0c;说白了就是一张“画皮”而已。我们之前的DirectX课程中介绍过材质&#xff0c;它实际就是对光的反射率&#xff0c;这样简单的设置并不能展现3D模型…

Linux线程 概念、特点、线程间资源共享情况

1. 线程概念 线程是轻量级的进程&#xff1b;Linux中&#xff0c;线程本质上仍是进程。 进程是OS分配资源的最小单位&#xff0c;线程是OS调度的最小单位。 NPTL 当前Linux线程库为redHat开发的NPTL&#xff0c;查看本地线程库版本&#xff1a; getconf GNU_LIBPTHREAD_VE…

【C++】三元操作符、创建并初始化C++对象、C++new关键字

C的三元操作符 if的语法糖 例1 #include <iostream> #include <string>static int s_Level 1; static int s_Speed 2;int main() {if (s_Level > 5){s_Speed 10;}else{s_Speed 5;}std::cin.get(); }用三元操作符&#xff1a; s_Speed s_Level > 5 ?…

基础篇-并发篇

**63.线程状态 添加主线程和子线程 ** 65.线程状态 核心线程和任务队列都是有上限的&#xff0c;所以都满了话就开始使用救急线程; 救急线程也是有上限的&#xff0c;如果再来新的线程的话就需要拒绝策越; 注意&#xff1a;这里不需要等待5000ms&#xff0c;几乎是同时打印 注…

[230503] 2021年托福阅读真题第1篇|Grinding Grain 磨粒

11:21&#xff5e;11:41 慢 20min 正确率&#xff1a;6.5/10 题目来源&#xff1a;链接: https://pan.baidu.com/s/15FYCuD7__slfGvdsBIHgLQ 提取码: iynj --来自百度网盘超级会员v5的分享【内含2021年100篇托福阅读真题】 目录 Grinding Grain 题目 Grinding Grain It now…

2016 ICPC合肥站 传递 HDU-5961(拓扑排序 / bitset / 暴力(可hack))

题目链接&#xff1a;HDU-5961 传递 中文题面就不解释题目意思&#xff0c;解释一下名词的意思 完全图&#xff1a;对于一个无向图 G G G 而言&#xff0c;设点集为 V V V&#xff0c;点集中任意不相同两点 u , v u, v u,v 间都有且仅有一条边叫做完全图。 竞赛图&#xff1…

【玩转Git三剑客笔记】第一章 Git基础

第一章 Git基础 1.综述2.安装Git3.使用Git之前需要做的最小配置4.创建第一个仓库并配置local用户信息1.创建Git仓库2.设置Git最小配置 5.通过几次commit来认识工作区和暂存区1.将工作区中所有已经被git追踪的文件一起添加到暂存区2.git log查看提交日志 6.给文件重命名的简便方…

密码学【java语言】初探究

文章目录 前言一 密码学1.1 古典密码学1.1.1 替换法1.1.2 移位法1.1.3 古典密码破解方式 二 近代密码学2.1 现代密码学2.1.1 散列函数2.1.2 对称密码2.1.3 非对称密码 二 凯撒加密的实践2.1 基础知识&#xff1a;ASCII编码2.2 ascii编码演示2.3 凯撒加密和解密实践2.4 频率分析…

安装Ubuntu22.04虚拟机的一些常见问题解决方法

文章目录 VirttalBox 开启共享剪切板文件夹、拖放的功能VirtualBox 安装 ubuntu后安装增强工具无效的解决办法解决ubuntu您没有权限查看“ 某某文件夹”的内容所需的权限linux更换源的两种方法[如何在 Ubuntu 20.04 上安装 Visual Studio Code - ](https://zhuanlan.zhihu.com/…

【Java入门合集】第二章Java语言基础(二)

【Java入门合集】第二章Java语言基础&#xff08;二&#xff09; 博主&#xff1a;命运之光 专栏JAVA入门 学习目标 掌握变量、常量、表达式的概念&#xff0c;数据类型及变量的定义方法&#xff1b; 掌握常用运算符的使用&#xff1b; 掌握程序的顺序结构、选择结构和循环结构…

权限提升:不带引号服务路径 || 不安全的服务权限.

权限提升&#xff1a;不带引号服务路径 || 不安全的服务权限. 权限提升简称提权&#xff0c;由于操作系统都是多用户操作系统&#xff0c;用户之间都有权限控制&#xff0c;比如通过 Web 漏洞拿到的是 Web 进程的权限&#xff0c;往往 Web 服务都是以一个权限很低的账号启动…

Nature:李龙等揭示抑郁症模型中社交压力阻断社交奖赏的神经环路机制

在人类社会中&#xff0c;社会压力尤其是创伤性社会经历会导致抑郁症、社交焦虑及创伤后应激障碍等多种精神疾病【1】。在抑郁症研究领域&#xff0c;有研究表明社会创伤会损害大脑负责奖赏的脑区功能&#xff0c;使社交活动变得不再有奖赏性&#xff0c;从而导致严重的社交回避…

【ShenYu系列】ShenYu Dubbo插件全流程源码解析

网关启动 在ShenyuConfiguration注入ShenyuWebHandler。 Bean("webHandler")public ShenyuWebHandler shenyuWebHandler(final ObjectProvider<List<ShenyuPlugin>> plugins, final ShenyuConfig config, Lazy final ShenyuLoaderService shenyuLoaderS…

初识Go语言20-包与工程化【用go mod管理工程、包引入规则、init调用链、可见性】

文章目录 包与工程化用go mod管理工程包引入规则init调用链可见性 包与工程化 用go mod管理工程 初始化项目: go mod init $module_name$module_name和目录名可以不一样。上述命令会生成go.mod文件&#xff0c;该文件内容形如&#xff1a; module go-coursego 1.17require (…

HarmonyOS服务卡片开发-文件组织与配置学习

HarmonyOS服务卡片开发-文件组织与配置学习 1.文件组织 目录结构 JS服务卡片(entry/src/main/js/Component)的典型开发目录结构如下&#xff1a; 目录结构中文件分类如下&#xff1a; .hml结尾的HML模板文件&#xff0c;这个文件用来描述卡片页面的模板布局结构。 .css结…

云计算(Cloud Computing)

一、从技术概念理解云计算 早期的云计算就是虚拟化主机上的分布式计算&#xff0c;现阶段的云计算&#xff0c;已经不单单是一种分布式计算&#xff0c;而是分布式计算、效用计算、负载均衡、并行计算、网络存储、热备份冗杂和虚拟化等计算机技术混合演进并跃升的结果。云计算…

飞书接入ChatGPT,打造属于自己的智能问答助手

文章目录 前言环境列表视频教程1.飞书设置2.克隆feishu-chatgpt项目3.配置config.yaml文件4.运行feishu-chatgpt项目5.安装cpolar内网穿透6.固定公网地址7.机器人权限配置8.创建版本9.创建测试企业10. 机器人测试 转载自远控源码文章&#xff1a;飞书接入ChatGPT - 将ChatGPT集…

太酷了,库昊

昨天晚上凌晨3点30&#xff0c;勇士和国王的第7场比赛开打。 在上一局在勇士主场干翻勇士后&#xff0c;国王队的信心倍增&#xff0c;他们用自己的节奏一次次击溃勇士&#xff0c;特别是今天的前两节&#xff0c;国王能能够回应勇士的进球&#xff0c;防守也更有侵略性。今天不…