字符串和字符串函数(2)

前言:

        在字符串和字符串函数(1)-CSDN博客中,已将将字符串和字符函数的使用了解,并且实现模拟了一些字符串的库函数。        

        接下来将继续深入学习字符串和字符串函数。并且模拟实现一些较为复杂的函数。

可控制字符长的的函数

介绍并使用strncpy函数

       相同点 strncpy函数和strcpy函数的形同点是都可以实现字符串的拷贝,可以将一个字符串中的内容拷贝到另一个字符串中。

       不同点strnpy和strcpy函数的区别在于,strcpy只能将一个字符串中的所有内容全部拷贝到另一个字符串中,但是strnpy可以将一个字符串中的内容,有选择的拷贝到另一个字符串当中,参数也从2个变成了3个。   

例如:我要将arr1[]中的前3个字符拷贝到arr2[]中:

        可不可以这样实现,其实问题就在于传完3个字符之后,有没有将\0也传进去?

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

通过调试可以看到:

        在arr1中:

拷贝之后,arr2中是这样:

发现:并没有将'\0'考进去!

所以,分两种情况:

    1、如果我想把一个字符串中几个字符给拿出来,这时候需要注意我们要手动将拿出来的字符串中的最后一个字符后面的一个字符加上'\0'

     2、如果我只是想将一个字符串中的前几个元素做一个替换,此时就不需要手动加上'\0'。

例1:拿出arr1中的3个字符。

#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = { "ab cd ef" };char arr2[20];strncpy(arr2, arr1, 3);arr2[3] = '\0';printf("%s\n", arr2);return 0;
}

打印结果:

        

例2:替换arr2中的前三个字符
        

#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = { "ab cd ef" };char arr2[20] = {"hjklo"};strncpy(arr2, arr1, 3);printf("%s\n", arr2);return 0;
}

模拟实现strncpy函数:

        我们可以在strcpy的基础上再进行一些修改:

#include<stdio.h>
#include<assert.h>
char* my_strnpy( char* arr2, const char* arr1, size_t num)
{assert(arr1 != NULL);assert(arr2 != NULL);char* start = arr2;while (num){*arr2++ = *arr1++;num--;}return start;
}int main()
{char arr1[] = {"love you"};char arr2[] = { "like me" };my_strnpy(arr2, arr1,4);printf("%s\n", arr2);return 0;
}

介绍并使用strncat函数:

与strcat相比较:

相同点都可以实现对字符串的追加。

不同点strncat按自我需求调整所追加的字符串的长度。

                strcat只能将一个字符串全部内容追加到另一个字符串当中。

追加的时候是从目的地字符数组的'\0'处开始追加。

看一组代码:

#include<stdio.h>
#include<string.h>
int main()
{char arr1[] = {"abcd"};char arr2[20] = { "asdf " };strncat(arr2, arr1, 4);printf("%s\n", arr2);return 0;
}

通过调试来观测一下:

        初始化之后:

进入函数之后:

        

注意:这是后也没有主动追加'\0',可以最后手动追加

模拟实现strncat函数:

        

char* my_strncat(char* arr1, const char* arr2, size_t num)
{assert(arr1 != NULL);assert(arr2 != NULL);char* start = arr1;while (*arr1){arr1++;}while (num){*arr1++ = *arr2++;num--;}return start;
}
int main()
{char arr1[20] = {"love me "};char arr2[] = { "like you" };my_strncat(arr1, arr2, 4);printf("%s\n", arr1);return 0;
}

介绍并使用strncmp函数:

        

相关介绍和返回值,发现和strcmp函数的返回值是一样的。

区别:除了多了一个参数num,也就是你要比较几个字符之外,其他的都是一样的。

int main()
{char arr1[] = {"abcdef"};char arr2[] = { "abcds" };int a =  strncmp(arr1, arr2,5);if (a == 0){printf("=");}else if (a < 0){printf("<");}else{printf(">");}return 0;
}

模拟实现strncmp函数

        

int my_strncmp(const char* arr1, const char* arr2, size_t num)
{assert(arr1 != NULL);assert(arr2 != NULL);while ( *arr1 - *arr2 == 0){arr1++;arr2++;num--;if (num-1 == 0){break;}}return *arr1-*arr2;
}
int main()
{char arr1[] = {"abcd"};char arr2[] = {"abfde"};int a = my_strncmp(arr1,arr2,4);if (a == 0){printf("=");}else if (a < 0){printf("<");}else{printf(">");}return 0;
}

其他类型库函数

介绍并使用strstr函数:

        

返回指向 str1 中首次出现的 str2 的指针,如果 str2 不是 str1 的一部分,则返回空指针.

        

int main()
{char arr1[] = {"love you best"};char *arr =  strstr(arr1, "you");printf("%s\n", arr);return 0;
}

   在arr1中找you,找到第一次出现的地方返回第一次出现的首字符的地址。

打印结果:

如果找不到,就返回NULL;

例如:

int main()
{char arr1[] = {"love you best"};char *arr =  strstr(arr1, "yoo");printf("%s\n", arr);return 0;
}

打印结果:

注:这里找相同的字符串必须完全相同,差一个字符都不行!!

模拟实现strstr函数:

        首先通过画图来讲解:

        

char* my_strstr(const char* arr1, const char* arr2)
{char* cp = (char*)arr1;//表示arr1的红色指针char* a;//表示arr1的绿色指针char* b;//表示arr2的绿色指针while (*cp){if (*cp == *arr2){a = cp;b = (char*)arr2;while (*cp == *b){cp++;b++;if (*b == '\0')return a;}}cp++;}return NULL;
}
int main()
{char arr1[] = { " welcom next new world" };char arr2[] = {"new"};char *str = my_strstr(arr1, arr2);printf("%s\n", str);return 0;
}

介绍并使用memcpy(内存拷贝函数)函数:

        

之前探讨了strcpy和strncpy,这两个库函数是用来拷贝字符串的,其它类型的不能拷贝,那么其他类型的数据该如何拷贝呢?

        就需要用到memcpy函数,可以拷贝任意类型的数据!

例如:

int main()
{int arr1[] = {1,2,3,4,5};int arr2[20];memcpy(arr2,arr1, 20);return 0;
}

需要三个参数,目的地地址,源头地址,需要拷贝的字节数,

        通过调试发现:

拷贝成功!

模拟实现memcpy函数

void* my_memcpy(void* str1, const void *str2, size_t sz)
{void* start = str1;assert(str1 && str2);while (sz){*(char*)str1 = *(char*)str2;str1 = (char*)str1 + 1;str2 = (char*)str2 + 1;sz--;}return start;
}
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[10];my_memcpy(arr2,arr1,20);return 0;
}

拷贝完成!

但是,这回突发奇想,想将arr1中的前4个拷贝到从第二个整形开始。可不可以呢?

void* my_memcpy(void* str1, const void *str2, size_t sz)
{void* start = str1;assert(str1 && str2);while (sz){*(char*)str1 = *(char*)str2;str1 = (char*)str1 + 1;str2 = (char*)str2 + 1;sz--;}return start;
}
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9 };my_memcpy(arr1+2,arr1,16);return 0;
}

发现是不可以的,那么如果我要实现重叠部分的拷贝,应该怎么办,可以使用库函数中的memmove函数!

        接下来就来探究一下memmove函数!

介绍并使用memmove函数

和memcopy相比,memmove可以完成重叠部分的拷贝工作!

int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9 };memmove(arr1+2,arr1,16);return 0;
}

发现可以进行重叠部分的拷贝!

模拟实现memmove函数:

        那么应该怎样拷贝,才不会出现在memcpy中的情况呢,这里分为三种情况:

1、源头地址在目的地的左侧,源头低地址,目的地高地址。

此时不会再出现被覆盖的情况。

2、源头地址在目的地的左右侧,源头高地址,目的地低地址。

3、源头和目的地没有重叠部分

这种情况怎么拷贝都行,只要空间够用即可。

以上这几种情况就是memmove函数的思路!

以下是代码:

void* my_memmove(void* str1, void* str2, size_t num)
{void* start = str1;int sz = num;if (str1 > str2){while (sz){str2 = (char*)str2+1;str1 = (char*)str1 + 1;sz--;}while (sz != num){*(char*)str1 = *(char*)str2;str1 = (char*)str1-1;str2 = (char*)str2 - 1;sz++;}}else {while (sz--){*(char*)str1 = *(char*)str2;str1 = (char*)str1 + 1;str2 = (char*)str2 + 1;}}return start;
}int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9 };my_memmove(arr1,arr1+2,12);return 0;
}

        

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

跟着小白学linux的基础命令

小白学习记录&#xff1a; 前情提要&#xff1a;Linux命令基础格式!查看 lsLinux 的7种文件类型及各颜色代表含义 进入指定目录 cd查看当前工作目录 pwd创建一个新的目录(文件夹&#xff09; mkdir创建文件 touch查看文件内容 cat、more操作文件、文件夹- 复制 cp- 移动 mv- 删…

redis安裝启动

1、下载redis解压 https://github.com/tporadowski/redis/releases 2、打开cmd&#xff0c;切换到解压的文件夹 3、redis-server.exe redis.windows.conf 启动redis redis可通过命令行输入config set requirepass password和直接修改redis.config文件中修改 requirepass 来设…

工业级物联网边缘网关解决方案-天拓四方

随着工业4.0时代的到来&#xff0c;越来越多的企业开始寻求智能化升级&#xff0c;以提高生产效率、降低运营成本并增强市场竞争力。然而&#xff0c;在实际的转型升级过程中&#xff0c;许多企业面临着数据孤岛、设备兼容性差、网络安全风险高等问题&#xff0c;这些问题严重制…

Flink的简单学习二

一 Flink的核心组件 1.1 client 1.将数据流程图DataFlow发送给JobManager。 1.2 JobManager 1.收集client的DataFlow图&#xff0c;将图分解成一个个的task任务&#xff0c;并返回状态更新数据给client 2.JobManager负责作业调度&#xff0c;收集TaskManager的Heartbeat和…

精选网络安全书单:打造数字世界的钢铁长城!

目录 1.前言 2.书单推荐 2.1. 《内网渗透实战攻略》 2.2. 《Kali Linux高级渗透测试&#xff08;原书第4版&#xff09;》 2.3. 《CTF那些事儿》 2.4. 《权限提升技术&#xff1a;攻防实战与技巧》 2.5. 《数字政府网络安全合规性建设指南&#xff1a;密码应用与数据安全…

华为鲲鹏应用开发基础: 计算机系统概述(一)

1. 计算机系统演进及分类 1.1 计算机发展的四个阶段 1.2 当前计算机通常分为以下五类: 分类超级计算机大型计算机迷你计算机(服务器)微型计算机工作站特点• 功能最强、运算速度最快、 存储容量最大的计算机 • 多用于国家高科技领域和 尖端技术研究 例如,“神威太湖之光”…

数字智能数字人直播带货软件系统 实现真人形象的1:1克隆 前后端分离 带完整的安装代码包以及搭建教程

系统概述 数字智能数字人直播带货小程序源码系统是一套集人工智能、3D建模、云计算等技术于一体的综合性解决方案。该系统通过深度学习算法&#xff0c;能够实现对真人形象的精准捕捉和1:1克隆&#xff0c;使数字人在直播过程中呈现出与真人无异的表现力。同时&#xff0c;系统…

使用Kimi月之暗面快速完成学术论文【全流程】

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 国内大型互联网公司如阿里、腾讯、360纷纷开始免费提供长文本生成服务&#xff0c;体验了一把国产级的模型Kimi&#xff0c;小编只有一个感觉&#xff1a;国产AI模型只能说越来越牛逼了…

06- 数组的基础知识详细讲解

06- 数组的基础知识详细讲解 一、基本概念 一次性定义多个相同类型的变量&#xff0c;并且给它们分配一片连续的内存。 int arr[5];1.1 初始化 只有在定义的时候赋值&#xff0c;才可以称为初始化。数组只有在初始化的时候才可以统一赋值。 以下是一些示例规则&#xff1a; …

NocoDB开源的智能表格详解-腾讯文档本地替代品

文章目录 一、介绍二、docker-compose部署三、登录NocoDB四、NocoDB手册1. 创建项目2. 收集统计表2.1 添加字段2.2 编辑字段2.3 字段类型2.4 发布表格 3.创建表单3.1 创建表单3.2 分享表单3.3 填写检测单 4.创建看板5.创建画廊 一、介绍 可作为腾讯文档的本地电子表格替代品&a…

mysql启动出现Error: 2 (No such file or directory)

查看mydql状态 systemctl status mysqlThe designated data directory /var/lib/mysql/ is unusable 查看mysql日志 tail -f /var/log/mysql/error.logtail: cannot open ‘/var/log/mysql/error.log’ for reading: No such file or directory tail: no files remaining 第…

小白跟做江科大32单片机之按键控制LED

原理部分 1.LED部分使用的是这样的连接方式 2.传感器模块的电路图 滤波电容如果接地&#xff0c;一般用于滤波&#xff0c;在分析电路时就不用考虑。下面这个电路就是看A端和B端哪端的拉力大&#xff0c;就能把电压值对应到相应的电压值 比较器部分 如果A端电压>B端电压&am…

Android 图表开发开源库 MPAndroidChart 使用总结

1. 引言 电视项目中需要一个折线图表示节电数据变化情况&#xff0c;类比 H5 来说&#xff0c;Android 中也应该有比较成熟的控件&#xff0c;经过调研后&#xff0c;发现 MPAndroidChart 功能比较强大&#xff0c;网上也有人说可能是目前 Android 开发最好用的一个三方库了&a…

WPS表格插件方方格子【凑数】功能:选出和等于固定数字的数

文章目录 后来发现可以下载方方格子插件&#xff0c;使用【凑数】功能https://ffcell.lanzouj.com/iwhfc1kjhayh【凑数】快速【凑数】 导师让沾发票&#xff0c;需要选出若干个数额的发票&#xff0c;使它们的和等于一个指定数。不知道怎么办了&#xff0c;查了一下&#xff0c…

Python第二语言(四、Python数据容器)

目录 一、 数据容器&#xff08;list、tuple、str、map、dict&#xff09; 1. 数据容器概念 2. 列表list&#xff08; [] &#xff09; 2.1 定义方式 2.2 嵌套列表 2.3 list通过获取下标索引获取值 2.4 下标使用概念 2.5 list列表的使用&#xff08;列表的方法&#xff…

linux nohup命令详解:持久运行命令,无视终端退出

nohup &#xff08;全称为 “no hang up”&#xff09;&#xff0c;用于运行一个命令&#xff0c;使其在你退出 shell 或终端会话后继续运行。 基本语法 nohup command [arg1 ...] [&> output_file] &command 是你想要运行的命令。[arg1 ...] 是该命令的参数。&am…

快排与归并的算法(非递归版)

一.快排 1.递归法(方法多样) 1>hoare版 注&#xff1a;该方法小编已经在上篇博客中介绍过了&#xff0c;就不在这里过多赘述了&#xff0c;如果有兴趣的小伙伴可以看看小编的上篇博客哦 2>挖坑法 1&#xff09;方法介绍&#xff1a;定义最左边的数据为key&#xff0…

生信学习入门常见错误可能的原因分类总结和求助指南

文件或目录找不到 这是常见问题&#xff0c;常见提示有 No such file or directory Error in file(file, “rt”)&#xff1a;无法打开链接 Fatal error: Unable to open file for reading (seq/WT1_1.fq) Fatal error: Unable to read from file (C:Program file/Git/usea…

OneDrive空间清理及文件历史版本查询

点击OneDrive图标 点击“在线查看” 点击“设置” 点击“OneDrive设置” 点击“其他设置” 点击“存储标准” 点击“文档” 选择需要操作的文件&#xff0c;点击“历史版本记录” 需要清理空间&#xff0c;可删除历史版本&#xff0c;需要使用历史版本&#xff0c;可还原历史版…

为什么我们需要在软件本地化过程中使用术语服务?

你知道软件翻译和本地化的术语服务吗&#xff1f;此解决方案涵盖源术语和目标术语的创建、开发和维护。所有术语都存储在具有多个字段的数据库中&#xff0c;包括术语定义、用法示例、上下文和历史记录。这使我们能够正确处理每个术语的创建或更改请求&#xff0c;避免创建重复…