字符串和字符串函数(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.mzph.cn/bicheng/21613.shtml

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

相关文章

【Linux基础】安装nginx

【Linux基础】安装nginx 文章目录 【Linux基础】安装nginx1、下载nginx2、安装nginx3、使用nginx4、配置nginx环境变量 1、下载nginx 在Nginx的官网的下载页面中(http://nginx.org/en/download.html)&#xff0c;就展示了当前Nginx版本&#xff0c;并提供了下载的连接。 如下&a…

图像处理之基于标记的分水岭算法(C++)

图像处理之基于标记的分水岭算法&#xff08;C&#xff09; 文章目录 图像处理之基于标记的分水岭算法&#xff08;C&#xff09;前言一、基于标记点的分水岭算法应用1.实现步骤&#xff1a;2.代码实现 总结 前言 传统分水岭算法存在过分割的不足&#xff0c;OpenCV提供了一种…

【C语言进阶】动态内存管理及柔性数组

动态内存的开辟在C语言中相当重要的知识 1、为什么会存在动态内存分配 内存的开辟方式&#xff1a; int a20;//在栈空间上开辟4个字节 int arr[10];//在栈空间上开辟40个字节的连续空间 这种开辟空间的方式有两个特点&#xff1a; 1、开辟的空间大小是固定的 2、数组在声明的…

二叉树创建和遍历

个人主页 &#xff1a;敲上瘾-CSDN博客二叉树介绍&#xff1a;二叉树(详解)-CSDN博客 目录 一、二叉树的创建 二、二叉树的遍历 1.前序遍历 2.中序遍历 3.后序遍历 4.层序遍历 三、相关计算 1.总节点个数计算 2.叶子节点个数计算 3.深度计算 一、二叉树的创建 关于…

如何在路由器上安装代理服务:详细教程

如何在路由器上安装代理服务&#xff1a;详细教程 步骤一&#xff1a;通过漏洞进入路由器系统开启Telnet服务使用Telnet登录路由器系统查看系统信息和CPU信息步骤二&#xff1a;交叉编译MIPS程序 Go对MIPS的支持 安装TFTP Server使用BusyBox tftp传输文件在路由器系统中下载编译…

❤机器学习正则化算法的总结。耗时10个小时完成。❤

❤纯 干 货~❤ 目录 纯干货 1、L1 正则化&#xff08;Lasso 正则化&#xff09; 2、L2 正则化&#xff08;岭正则化&#xff09; 3、弹性网络正则化&#xff08;Elastic Net 正则化&#xff09; 4、Dropout 正则化&#xff08;用于神经网络&#xff09; 5、贝叶斯Rid…

海外盲盒小程序:跨文化营销的利器

在全球化的浪潮下&#xff0c;跨境电商正迎来前所未有的发展机遇。作为这一领域中的新兴力量&#xff0c;海外盲盒小程序凭借其独特的魅力和优势&#xff0c;正逐渐崭露头角&#xff0c;成为跨文化营销的利器。本文将探讨海外盲盒小程序在跨文化营销中的应用及其带来的价值。 一…

【30天精通Prometheus:一站式监控实战指南】第16天:snmp_exporter从入门到实战:安装、配置详解与生产环境搭建指南,超详细

亲爱的读者们&#x1f44b;   欢迎加入【30天精通Prometheus】专栏&#xff01;&#x1f4da; 在这里&#xff0c;我们将探索Prometheus的强大功能&#xff0c;并将其应用于实际监控中。这个专栏都将为你提供宝贵的实战经验。&#x1f680;   Prometheus是云原生和DevOps的…

ldap协议(常用于统一身份认证)与dict协议(在线词典)

文章目录 LDAPDICT LDAP LDAP&#xff08;Light Directory Access Portocol&#xff09;&#xff0c;轻量目录访问协议。 目录是一个为查询、浏览和搜索而优化的数据库&#xff0c;它成树状结构组织数据&#xff0c;类似文件目录一样。 目录数据库和关系数据库不同&#xff0c…

Docker安装极简版(三分钟搞定)

什么是Docker? Docker是一个开源的应用容器引擎&#xff0c;它允许开发者打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口。 化。容器是…

简易图像处理器的设计

1 概述 Python是一种高级、通用、解释型的编程语言&#xff0c;由Guido van Rossum于1991年创造。它被设计为易读易写的语言&#xff0c;具有简洁而清晰的语法&#xff0c;使得它成为许多领域的首选语言&#xff0c;如Web开发、科学计算、人工智能、数据分析等。结合本科阶段以…

三维地图校内导航系统解决方案

在如今的数字化时代&#xff0c;越来越多的学校开始实施智慧校园计划&#xff0c;旨在为学生和教师提供更高效、便捷的学习和教学环境。智慧校园运用互联网、大数据、人工智能等技术&#xff0c;对校园内各信息进行收集、整合、分析和应用&#xff0c;实现教学、管理、服务等多…

【matlab】绘图插入并放大/缩小子图

参考链接 代码分为两个&#xff1a;绘图代码与magnify.m 绘图代码就是普通的绘图代码&#xff0c;以下为例 %https://zhuanlan.zhihu.com/p/655767542 clc clear close all x 0:pi/100:2*pi; y1 sin(x); plot(x,y1,r-o); hold on y2sin(x)-0.05; y3sin(x)0.05; xlim([0 2*…

eclipse-向Console控制台输出信息

首先这里主要用到的是org.eclipse.ui.console这个包&#xff0c;所以现在顺道先来了解一下&#xff1a; org.eclipse.ui.console是一个可扩展的console视图插件&#xff0c;利用它可以实现各种console&#xff0c;并把它们显示出来。该插件本身就实现了一个Message Console&…

本地 Java API 访问云上 HDFS 集群的问题与解决

前言 这篇文章默认是已经在云上配置好了 Haoop 集群&#xff0c;因此本文主要是记录一些可能会出现错误的地方。 如果还不会配置 Hadoop 集群&#xff0c;那么可以参考本专栏的另一篇文章&#xff1a;云上配置 Hadoop 集群详解 另外在进行本文的学习之前也建议先看看该文章&…

边缘计算的AI小板——OrangePi AI Pro

简介 OrangePi AI Pro是一款基于Allwinner H6处理器的嵌入式AI计算设备&#xff0c;适用于物联网和边缘计算。它具有强大的性能、低功耗、多接口和小尺寸。 本文分为三个部分&#xff1a; 一、对该板进行简单的开箱介绍。 二、 将SD卡中的系统迁移到由于该板支持SD卡、SSD…

必看——怎么让网站实现HTTPS访问?

让网站实现HTTPS访问的步骤可以简化为以下几个基本步骤&#xff0c;非常适合非技术背景人士理解&#xff1a; 1. 申请SSL证书&#xff1a; - SSL证书是实现HTTPS的关键&#xff0c;它能加密网站数据&#xff0c;保证用户信息的安全。你可以从一些提供免费SSL证书的机构&#xf…

Spring boot集成mybatis

Spring boot集成mybatis maven依赖 我的spring boot版本是2.5.0&#xff0c;集成mybatis&#xff0c;首先需要数据库的支持&#xff0c;这里我选择mysql数据库&#xff0c;版本是8.0.11&#xff0c;然后使用druid连接池&#xff0c;其次就需要加上mybatis的依赖。 <!--mys…

[ue5]建模场景学习笔记(2)——用vectornoise降低重复率

1.问题分析&#xff1a; 利用改uv的方式降低重复率并不理想&#xff0c;在一定程度上的确能够达到降低重复率的效果&#xff0c;但远看仍然有较清晰的重复效果&#xff0c;尝试优化一下。 2.操作实现&#xff1a; 1.首先先看一下修改后的效果&#xff1a; 这是未修改前&#…

【Web API DOM02】如何获取、操作DOM元素

一&#xff1a;获取DOM元素 1 根据CSS选择器获取 语法格式如下&#xff1a; &#xff08;1&#xff09;选中一个DOM元素 document.querySeletor(CSS选择器) <ul><li>1</li><li>2</li><li>3</li> </ul> document.querySel…