【再识C进阶3(上)】详细地认识字符串函数、进行模拟字符串函数以及拓展内容

news2025/6/18 5:18:09

       小编在写这篇博客时,经过了九一八,回想起了祖国曾经的伤疤,勿忘国耻,振兴中华!加油,逐梦少年!

前言

💓作者简介: 加油,旭杏,目前大二,正在学习C++数据结构等👀
💓作者主页:加油,旭杏的主页👀

⏩本文收录在:再识C进阶的专栏👀

🚚代码仓库:旭日东升 1👀

🌹欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖

学习目标:

       在上一篇博客中,我们已经充分的学习了指针的相关知识,那么这篇博客,我们来重点关注一下字符串函数,主要学习求字符串长度的函数长度受限制的字符串函数长度不收限制的字符串函数,以及字符串查找函数,最后再来介绍一下错误信息报告

       之后,我们会将一些函数进行模拟实现,再拓展一下其他内容,C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串类型通常放在常量字符串或者字符数组中,字符串常量适用于那些对它不做修改的字符串函数。所以这篇博客还是比较重要的。


学习内容:

通过上面的学习目标,我们可以列出要学习的内容:

  1. 求字符串长度的函数,以及手撕代码,模拟实现
  2. 长度受限制的字符串函数,同样手撕代码,模拟实现
  3. 长度不受限制的字符串函数,观看其源代码,了解原理
  4. 字符串查找函数,同样手撕代码,模拟实现
  5. 介绍一下错误信息报告

       小编了解有些人是不会看学习目标,那么我就再说一遍:说起字符串,C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中。常量字符串适用于那些对他不做修改的字符串函数。 

一、求字符串长度的函数——strlen

1.1 函数介绍

       在【初阶C语言3】特别详细地介绍函数中,小编已经介绍了如何查找库函数的参数和具体用法,在这里小编就不多说了。回归主题,我们来看strlen函数。

       简单来说,strlen函数是求字符串长度的库函数,传递的参数是要求字符串长度的首元素地址即可。但是要注意的是strlen函数本质上统计的是字符串中 '\0' 之前的字符的个数。看下面的代码进行区分:

#include <stdio.h>
#include <string.h>  //别忘了引头文件
int main()
{
	char arr1[] = "sdgeghkoe";
	char arr2[] = "sdgeg\0hkoe";
	printf("strlen(arr1) = %d\n", strlen(arr1));
	printf("strlen(arr2) = %d\n", strlen(arr2));
	return 0;
}

       在来看strlen函数返回值的特点,仔细看,在库函数中,strlen函数的返回值的类型是无符号整形(size_t)。怎么理解这个无符号整形呢?我们来看下面的一道题:

int main()
{
	const char* str1 = "abcdfre";  //const修饰,使指针指向的字符串不能被修改
	const char* str2 = "fsfe";
	if (strlen(str2) - strlen(str1) > 0)
	{
		printf("str2 > str1");
	}
	else
	{
		printf("str1 > str2");
	}
	return 0;
}

       这道题按照常理来讲,str2指向的字符串长度比str1指向的字符串长度小,所以这个运算的结果应该是str1 > str2,但为什么结果是str2 > str1,。

       因为strlen函数的返回值是无符号整形两个无符号整形进行相加减的时候是不会出现负数的情况,所以不论这道题的结果是什么,永远都是str2 > str1。

1.2 模拟实现一下strlen函数

       模拟实现strlen函数有三种方法:一个是计数器、一个是递归的方法、一个是指针减指针的方法。下面,小编来一一为大家进行讲解:

1.2.1 计数器方法实现strlen函数

1.3 总结一下strlen函数的要点

二、长度不受限制的字符串函数

2.1 strcpy函数

2.1.1 函数介绍

       strcpy——string copying,表示的是字符串拷贝的工作,如果我们不清楚,我们可以在网站上进行搜索strcpy函数。

       上面的意思是: 将源头的字符串传给目的地的字符串中,包括 '\0'。在使用strcpy函数进行拷贝字符串的时候,源字符串必须要有 '\0'其是strcpy函数拷贝结束的标志,否则程序将会打印出一些不必要的内容。请看下图进行解释:

基本用法:

//第一种写法
int main()
{
	char arr1[20] = "xxxxxxxxx";
	char arr2[] = { 's','a','d','\0'};
	printf("%s\n", strcpy(arr1, arr2));
	return 0;
}
//第二种写法
int main()
{
	char arr1[20] = "xxxxxxxxx";
	char arr2[] = "sad";
	printf("%s\n", strcpy(arr1, arr2));
	return 0;
}
int main()
{
	char arr1[20] = "xxxxxxxxx";
	char arr2[] = { 's','a','d' };
	printf("%s\n", strcpy(arr1, arr2));
	return 0;
}

2.1.2 strcpy函数使用时出现的一些问题

问题一:目的地的字符数组的大小比源头的字符数组的大小要小

代码:

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

结果:

       虽然会弹出警告,但是strcpy函数还是会完成其使命,将源头的字符串拷贝到目的地的字符串中,因为strcpy函数是不受长度限制的函数。

问题二:将源头的字符串拷贝到常量字符串中

代码:

int main()
{
	char* p = (char* )"feifhw";
	char arr2[] = "hello";
	printf("%s\n", strcpy(p, arr2));
	return 0;
}

结果:

2.1.3 总结一下strcpy函数的要点

  1. 源字符串必须以 '\0' 结束
  2. 在拷贝的过程中,会将源字符串中的 '\0' 拷贝到目标空间中
  3. 目标空间必须足够大,以确保能存放源字符串
  4. 目标空间必须可变,不能是常量字符串

2.1.4 模拟实现一下strcpy函数

char* my_strcpy(char* base, const char* serc) //源头的内容不用改,用const修饰
{
	assert(base && serc); //检查指针是否指空
	char* ans = base;
	while (*base++ = *serc++)
	{
		;
	}
	return ans;
}

2.2 strcat函数

2.2.1 函数介绍

       这个函数是用于字符追加的,如果我们不清楚,我们依然可以进行在网站上查询strcat函数。下面小编我将会为大家用代码示范一下如何使用strcat函数:

基本用法:

int main()
{
	char arr1[20] = "asd";
	char arr2[] = "hjk";
	printf("%s\n", strcat(arr1, arr2));
	return 0;
}

       在上面的用法中,我们好像已经浅浅地了解了strcat函数的用法,就是将源头的字符串追加到目的地的字符串中。那么这时,我们要来思考一下问题:1)到底是遇见 '\0' 进行追加,还是遇见字符串末尾进行追加呢?2)字符串在拷贝的过程中是否将源头的 '\0' 也拷贝过去呢?3)目的地字符串数组是否要足够大?下面我们来解决一下这些问题:

2.2.2 解决上述strcat函数的相关问题

问题一:到底是遇见什么进行追加(遇见'/0'进行追加)

问题二:在拷贝的过程中将源头的'\0'拷贝过去

int main()
{
	char arr1[20] = "asdxxx\0xxxxx";
	char arr2[] = "hjk";
	printf("%s\n", strcat(arr1, arr2));
	return 0;
}

问题三:目的地数组要足够大(与strcpy类似)

int main()
{
	char arr1[] = "asdxxx";
	char arr2[] = "hjk";
	printf("%s\n", strcat(arr1, arr2));
	return 0;
}

2.2.3 总结一下strcat函数的要点

  1. 源字符串必须要以 '\0' 结束,保证能够找到目标空间的末尾
  2. 目标变量必须要足够大,能容纳下源字符串的内容
  3. 目标函数必须可以修改

2.2.4 模拟实现一下strcat函数

char* my_strcat(char* str1, const char* str2)
{
	assert(str1 && str2);
	char* ret = str1;
    //找到目标空间的末尾
	while (*str1 != 0)
	{
		str1++;
	}
    //数据追加
	while (*str1++ = *str2++)
	{
		;
	}
	return ret;
}

2.2.5 思考一下字符串能和自己追加呢?

       显然是不能的,因为如果自己给自己进行追加,会导致字符串的内容发生一些变化,将字符0给堵盖掉,就没有结束标志了,看下图进行理解:

2.3 strcmp函数

2.3.1 函数介绍

       strcmp——string compare,表示的是字符串比较的工作,注意这个字符串函数比较的不是字符串的大小,而是对应位置上字符的大小(ASCII值)。我们也可以在网站上搜索strcmp函数。 

标准规定:

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

       要注意的是,这个函数的返回值为int,两个参数都是const char*类型的,因为我只是想要比较两个字符串的大小,不需要进行修改。 

基本用法:

int main()
{
	char arr1[] = "dsgfer";
	char arr2[] = "dsgfty";
	printf("%d\n", strcmp(arr1, arr2));
	return 0;
}

2.3.2 模拟实现一下strcmp函数

//第一种写法,返回值是1和-1
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 == *str2)
	{
		if (*str2 == 0)
			return 0;
		str1++;
		str2++;
	}
	if (*str1 < *str2)
		return -1;
	else if(*str1 > *str2)
		return 1;
}

//第二种写法,返回值不一定是1和-1
int my_strcmp(const char* str1, const char* str2)
{
	assert(str1 && str2);
	while (*str1 && *str2 && *str1 == *str2)
	{
		str1++;
		str2++;
	}
	return *str1 - *str2;
}

2.4 长度不受限制的字符串函数的特点

       这些字符串函数都会将直接完成该完成的任务,不会管目的地字符串数组能否放的下,它都会将放入其中,这些函数是简单粗暴的,而我们学的下几个函数不会像这几个函数一样。

三、长度受限制的字符串函数

       我们来看这几个函数strncpy,strncat,strncmp,它们都多了一个n,也就是number。这些函数都会确定几个字符进行该函数的工作,所以说,它们是长度受限制的字符串函数

3.1 strncpy函数

3.1.1 函数介绍

       在和strcpy函数进行比较时,会发现参数部分多了一个num,要和strcpy进行区分一下,所以其作用是拷贝num个字符从源字符串到目标空间中。我们依然可以在网站上搜索strncpy函数。

3.1.2 strncpy函数要注意的要点

要点一:是否在后面拷贝 '\0' ?

       这个函数并没有在后拷贝 '\0' ,可以看下面的代码:

int main()
{
	char arr1[] = "xxxxxxxxxxx";
	char arr2[] = "asd";
	printf("%s\n", strncpy(arr1, arr2, 3));
	return 0;
}

要点二:如果源字符串的长度小于num,怎么办? 

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

int main()
{
	char arr1[] = "xxxxxxxxxxx";
	char arr2[] = "asd";
	printf("%s\n", strncpy(arr1, arr2, 6));
	return 0;
}

3.2 strncat函数

3.2.1 函数介绍

       这个函数和strcat函数的功能是一样的,我们同样可以在网站上搜索strncat函数。

基本用法:
 

int main()
{
    char arr1[20] = "hoojp";
    char arr2[20] = "wqoieh";
    strncat(arr1, arr2, 4);
    printf("%s\n", arr1);
    return 0;
}

3.2.2 strncat函数要注意的要点

       我们要记住strncat函数将几个字符追加到另一个字符串中,会在后面添加一个 '\0'。看下面的代码:

int main()
{
    char arr1[20] = "hoojp\0xxxxx";
    char arr2[20] = "wqoieh";
    strncat(arr1, arr2, 4);
    printf("%s\n", arr1);
    return 0;
}

3.3 strncmp函数

       该函数的功能是比较到出现另一个字符不一样或者一个字符串结束或者num个字符全部比较完。看下图的精确含义:

基本用法:

int main()
{
    char arr1[20] = "hjoihsoad";
    char arr2[20] = "hjoihjdkp";
    int ret = strncmp(arr1, arr2, 5);
    printf("%d\n", ret);
    return 0;
}

四、字符串查找函数

       这些函数还是比较怪的,不同于前面讲述的三类函数,是一下关于字符串内容的操作,我们来一起看看吧!

4.1 strstr函数

4.1.1 函数介绍

       strstr——string string,是在字符串中查找子字符串中的操作,根据函数原型,可以发现是在str1中找到str2第一次出现的位置,如果str1中没有str2,就返回NULL。

基本用法:

int main()
{
    char str[] = "This is a simple string";
    char* pch;
    pch = strstr(str, "simple");
    printf("%s", pch);
    return 0;
}

 

4.1.2 模拟实现一下strstr函数

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

4.1.3 拓展一下kmp算法 

4.2 strtok函数

       strtok函数是用来切割字符串的,如果在一个字符串中有分隔符的话,我们可以使用这个函数去按照分隔符将一个字符串分割成好几份。下面来看这个函数的参数:

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

基本用法:

int main()
{
    char arr[] = "shdakio@iahd.isauh";
    char buf[200] = { 0 };
    strcpy(buf, arr);
    const char* p = "@.";
    char* s = NULL;
    for (s = strtok(arr, p); s != NULL; s = strtok(NULL, p))
    {
        printf("%s\n", s);
    }
    return 0;
}

五、错误信息报告函数strerror

       strerror函数是将错误码翻译成错误信息,返回错误信息的字符串的起始位置。错误码有是什么,C语言在使用库函数时,如果发生错误,会将错误码放在errno中,errno是全局变量,可直接使用。

基本用法:

int main()
{
    int i = 0;
    for (int i = 0; i < 10; i++)
    {
        printf("%s\n", strerror(i));
    }
    return 0;
}


学习产出:

  1. 求字符串长度的函数,以及手撕代码,模拟实现
  2. 长度受限制的字符串函数,同样手撕代码,模拟实现
  3. 长度不受限制的字符串函数,观看其源代码,了解原理
  4. 字符串查找函数,同样手撕代码,模拟实现
  5. 介绍一下错误信息报告

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

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

相关文章

【短文】sambe添加用户时报错Failed to add entry for user

2023年9月20日&#xff0c;周三晚上 Samba fails to add a user entry, how do I fix this? - Ask Ubuntu 也就是说&#xff0c;添加的sambe用户必须是Linux操作系统的用户

2023/09/20 day4 qt

做一个动态指针钟表 头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPainter> //绘制事件类 #include <QPaintEvent> //画家类 #include <QTime> #include <QTimer> #include <QTimerEvent> QT_BEGIN…

k8s使用时无法ping通服务器From IP地址 icmp_seq=1 Destination Host Unreachable

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

canvas-绘图库fabric.js简介

一般情况下简单的绘制&#xff0c;其实canvas原生方法也可以满足&#xff0c;比如画个线&#xff0c;绘制个圆形、正方形、加个文案。 let canvas document.getElementById(canvas);canvas.width 1200;canvas.height 600;canvas.style.width 1200px;canvas.style.height 6…

Canal实现Mysql数据同步至Redis、Elasticsearch

文章目录 1.Canal简介1.1 MySQL主备复制原理1.2 canal工作原理 2.开启MySQL Binlog3.安装Canal3.1 下载Canal3.2 修改配置文件3.3 启动和关闭 4.SpringCloud集成Canal4.1 Canal数据结构![在这里插入图片描述](https://img-blog.csdnimg.cn/c64b40c2231a4ea39a95aac81d771bd1.pn…

kafka消费者多线程开发

目录 前言 kafka consumer 设计原理 多线程的方案 参考资料 前言 目前&#xff0c;计算机的硬件条件已经大大改善&#xff0c;即使是在普通的笔记本电脑上&#xff0c;多核都已经是标配了&#xff0c;更不用说专业的服务器了。如果跑在强劲服务器机器上的应用程序依然是单…

java框架-Spring-容器创建过程

java框架-Spring-容器创建源码

pip pip3安装库时都指向python2的库

当在python3的环境下使用pip3安装库时&#xff0c;发现居然都指向了python2的库 pip -V pip3 -V安装命令更改为&#xff1a; python3 -m pip install <package>

CCC数字钥匙设计【BLE】--URSK管理

1、URSK创建流程 URSK的英文全称为&#xff1a;UWB Ranging Secret Key&#xff0c;即UWB安全测距密钥。 在车主配对时会生成URSK&#xff0c;且在车主配对期间&#xff0c;车辆不得尝试生成第二个URSK。 URSK示例: ed07a80d2beb00f785af2627c96ae7c118504243cb2c3226b3679da…

面向面试知识--MySQL数据库与索引

面向面试知识–MySQL数据库与索引 优化难点与面试点 什么是MySQL索引&#xff1f; 索引的MySQL官方定义&#xff1a;索引是帮助MySQL快速获取数据的数据结构。 动力节点原文&#xff1a; MysQL官方对于索引的定义:索引是帮助MySQL高效获取数据的数据结构。 MysQL在存储数据之…

问题usr/bin/env: “python‘: Too many levels of symbolic links太多层链接的bug pycharm

问题描述 解决&#xff1a;建议不要用过去的conda环境了&#xff0c;直接新建一个环境&#xff0c;然后在图片这个步骤的时候务必选择现有的解释器 。&#xff08;产生问题的原因可能就是新建的解释器太多了&#xff09;

Mermaid画流程图可以实现从一条线中间引出另外一条线吗

这张图中开始和操作1之间引出的一条线要怎么表示啊&#xff01;&#xff01;&#xff01; Mermaid是不能实现这样的画法的吗&#xff1f;可是为什么老师就可以画出来&#xff1f;&#xff1f;&#xff1f; 求大佬指教&#xff01;&#xff01;&#xff01;&#xff01;

现场总线学习

文章目录 1.现场总线现状2.数据编码2.1 数字数据的数字编码2.2 数字数据的模拟编码 3.通信方式&#xff01;&#xff01;&#xff01;4.局域网及其拓扑结构5.工业总线协议6.为什么要在can协议的控制器和bus总线之间&#xff0c;连接一个can收发器&#xff1f;7.那其他协议也需要…

vue修改node_modules打补丁步骤和注意事项

当我们使用 npm 上的第三方依赖包&#xff0c;如果发现 bug 时&#xff0c;怎么办呢&#xff1f; 想想我们在使用第三方依赖包时如果遇到了bug&#xff0c;通常解决的方式都是绕过这个问题&#xff0c;使用其他方式解决&#xff0c;较为麻烦。或者给作者提个issue&#xff0c;然…

dev board sig技术文章:轻量系统适配ARM架构芯片平台

摘要&#xff1a;本文简单介绍OpenHarmony轻量系统移植&#xff0c;会分多篇 适合群体&#xff1a;想自己动手移植OpenHarmony轻量系统的朋友 开始尝试讲解一下系统的移植&#xff0c;主要是轻量系统&#xff0c;也可能会顺便讲下L1移植。 1.1移植类型 OpenHarmony轻量系统的…

腾讯云服务器收费价格表(腾讯云服务器租用价格表)

作为国内领先的云计算服务提供商&#xff0c;腾讯云凭借其稳定、安全、高效的特点&#xff0c;备受用户青睐。本文将详细介绍腾讯云服务器的收费价格表及使用场景&#xff0c;帮助大家更好地了解并选择合适的云服务器方案。 一、轻量应用服务器 轻量应用服务器是一款开箱即用的…

数字人民币如何将支付宝钱包余额转入到微信支付钱包余额?

数字人民币如何将支付宝钱包余额转入到微信支付钱包余额&#xff1f; 第一步&#xff1a;获取微信支付数字人民币钱包编号 1.1、手机上找到并打开数字人民币APP&#xff1b; 1.2、打开后找到微众银行&#xff08;微信支付&#xff09;微信钱包&#xff0c;并点击翻转获取收款…

攻防世界-WEB-fileinclude

访问url&#xff0c;可以看到一些提示&#xff0c;绝对路径/var/www/html/index.php&#xff0c;也提示了flag在flag.php中。 快捷键Ctrlu,查看网页源代码 思路&#xff1a; 源代码中看到 include($lan.".php"); &#xff0c;可知此处存在文件包含。$lan的值是从co…

虚拟线程最佳实践

Virtual Threads: An Adoption Guide 虚拟线程&#xff1a;采用指南 接上篇 Virtual Threads 虚拟线程 原文&#xff1a;https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html 虚拟线程是由 Java 运行时而不是操作系统实现的 Java 线程。虚拟线程和传统线程&…

Datax从mysql同步数据到HDFS

在实际使用Datax的时候&#xff0c;比较常用的是同步业务数据&#xff08;mysql中的数据&#xff09;到HDFS来实现数仓的创建&#xff0c;那么怎么实现呢&#xff1f;我们一步步来实现&#xff08;基于Datax 3.0.0&#xff09; 1、检查环境&#xff0c;需要安装完一个Datax&am…