C语言函数:字符串函数及模拟实现strncpy()、strncat()、strncmp()

news2024/11/20 12:18:19

C语言函数:字符串函数及模拟实现strncpy()、strncat()、strncmp()

 

        在了解strncpy、strncat()、前,需要先了解strcpy()、strncat():

C语言函数:字符串函数及模拟实现strlen() 、strcpy()、 strcat()_srhqwe的博客-CSDN博客

strncpy():

        作用:拷贝受限制长度的字符串,意思是:可以指定拷贝字符的个数到目标字符串内。

        限制字符串个数是为了让程序相对安全,降低访问越界等情况出现的可能性。但是不会绝对安全,一个程序员要写bug如挥手一般简单.

参数部分:

char * __cdecl strncpy (
        char * dest,
        const char * source,
        size_t count
        )

count是指定传入的个数。

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int main()
{
	char de[20] = "abcdef";
	char so[] = "qwer";
	strncpy(de, so, 2);//拷贝2个字符
	printf("%s\n", de);
	//结果:qwcdef
	return 0;
}

        当拷贝的字符串的个数超出原字符串的个数时,多出的部分会传\0进去:

 

 

strncpy函数的实现:

        在strcpy基础上,写strncpy并不难。

        因此直接展示源码:

char * __cdecl strncpy (
        char * dest,
        const char * source,
        size_t count
        )
{
        char *start = dest;

        while (count && (*dest++ = *source++) != '\0')    /* copy string */
                count--;

        if (count)                              /* pad out with zeroes */
                while (--count)
                        *dest++ = '\0';

        return(start);
}

        因为多了count用于控制长度,所以while循环也多了一个count:

        当count不为0时,while循环继续。

        直到count为0时,自动跳出。

        (*dest++ = *source++) != '\0') 和strcpy一样。其中!=\0可以去掉。

        当没有\0时,dest和source一起++找下一个字符。

        当在source找到\0时,把\0传入后while循环结束

        if语句是为了保证count被置为0,因为count是我们需要拷贝的字符串个数。

        就是上面所说的,如果超越了source本身的个数,会自动补\0

        最后return 最初的dest,即start

strncat():

        作用:追加受限制的字符串。

参数部分:

char * __cdecl strncat (
        char * front,
        const char * back,
        size_t count
        )

         

int main()
{
	char de[20] = "abcd";
	char so[] = "qwer";
	strncat(de, so, 2);
	printf("%s\n", de);
	//结果:abcdqw
	return 0;
}

        与strncpy一样,如果追加的个数超出so的范围呢?会和strcpy一样?

int main()
{
	char de[20] = "abcd";
	char so[] = "qwer";
	strncat(de, so, 6);
	printf("%s\n", de);
	//结果:abcdqwer
	return 0;
}

        并不会,具体是怎么做的呢?那就先看看这个函数的实现:

strncat的实现:

strncat的源码:

char * __cdecl strncat (
        char * front,
        const char * back,
        size_t count
        )
{
        char *start = front;

        while (*front++)
                ;
        front--;

        while (count--)
                if ((*front++ = *back++) == 0)
                        return(start);

        *front = '\0';
        return(start);
}

        第一个while循环,和strcat一样,先找到front的\0,然后从\0开始向后追加。

        第二个while循环,count--作为条件语句,意思是循环count次,从而可以保证追加的个数。

        while循环的if语句,是从front的\0开始向后追加back的元素,当在back中遇到是\0时,==0,那么就直接返回。因此如果追加的个数超出范围,不会追加\0,而是直接返回。

        当count==0时,while循环退出,说明目前为止,已经把想传入的字符串传完了,因为上面是后置++,所以此时的front已经指向了最后一个元素的后面的指针。所以直接将此时指针指向的front的元素改成\0,即: *front = '\0';

        最后return 原front地址

strncmp():

   在了解strncmp()前,需要先了解strcmp():

C语言函数:字符串函数及模拟实现strcmp()_srhqwe的博客-CSDN博客

        作用:对比受限制的两串字符串

        strncmp和strcmp其实相差并不大,只是限制了对比的范围。返回值与strcmp是一样的

        

 参数部分:

int __cdecl strncmp
(
    const char *first,
    const char *last,
    size_t      count
)

 

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int main()
{
	char de[20] = "abcd";
	char so[] = "aba";
	strncmp(de, so, 3);
	printf("%s\n", de);
	//结果:1
	return 0;
}

        输入3比较的就是de和so的前三个字符

        

#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>

int main()
{
	char de[20] = "abad";
	char so[] = "aba";
	int ret = strncmp(de, so, 7);
	printf("%d\n",ret );
	//结果:1
	return 0;
}

        即使输入的数字超出了两个字符串的个数也没事,因为往后比较的都是\0。与strcmp基本一致。

strncmp()函数的实现:

        strncmp函数源码:

int __cdecl strncmp
(
    const char *first,
    const char *last,
    size_t      count
)
{
    size_t x = 0;

    if (!count)
    {
        return 0;
    }

    if( count >= 4 )
    {
        /* unroll by four */
        for (; x < count-4; x+=4)
        {
            first+=4;
            last +=4;

            if (*(first-4) == 0 || *(first-4) != *(last-4))
            {
                return(*(unsigned char *)(first-4) - *(unsigned char *)(last-4));
            }

            if (*(first-3) == 0 || *(first-3) != *(last-3))
            {
                return(*(unsigned char *)(first-3) - *(unsigned char *)(last-3));
            }

            if (*(first-2) == 0 || *(first-2) != *(last-2))
            {
                return(*(unsigned char *)(first-2) - *(unsigned char *)(last-2));
            }

            if (*(first-1) == 0 || *(first-1) != *(last-1))
            {
                return(*(unsigned char *)(first-1) - *(unsigned char *)(last-1));
            }
        }
    }

    /* residual loop */
    for (; x < count; x++)
    {
        if (*first == 0 || *first != *last)
        {
            return(*(unsigned char *)first - *(unsigned char *)last);
        }
        first+=1;
        last+=1;
    }

    return 0;
}

        第一个if语句,如果count==0那么就不用比较了,因为比较的区间没有。

        第二个if语句只是将区间划分成[0,4]和(4,正无穷)讨论

        之后的语句就是把每个每个字符进行比较,返回比较的结果。

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

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

相关文章

包装类详解(装箱,拆箱)

Object 引用可以指向任意类型的对象&#xff0c;但有例外出现了&#xff0c;8 种基本数据类型不是对象&#xff0c;那岂不是刚才的泛型机制要失效了&#xff1f;&#xff08;泛型详解._阿瞒有我良计15的博客-CSDN博客&#xff09; 实际上也确实如此&#xff0c;为了解决这个问题…

数据结构与算法-二叉树-序列化与反序列化

可能性探究:我们可以想到的是只有一棵树按照某个序是唯一确定要给结构的情况才可能被序列化和反序列化&#xff0c;比如我们对于以下的二叉树可以找到它的先序、中序、后序如下&#xff1a; 根据它的先序和后序我们找不到任何其他可能的树&#xff0c;所以可以根据先序和后序去…

NLP预训练模型

Models Corpus RoBERTa: A Robustly Optimized BERT Pretraining Approach 与BERT主要区别在于&#xff1a; large mini-batches 保持总训练tokens数一致&#xff0c;使用更大的学习率、更大的batch size&#xff0c;adam β20.98\beta_20.98β2​0.98&#xff1b;dynamic ma…

aws eks 集群初始化过程中pause容器的启动逻辑

eks集群默认策略在磁盘使用量达到threshold时会清除镜像&#xff0c;其中pause镜像也可能会被清除 https://aws.amazon.com/cn/premiumsupport/knowledge-center/eks-worker-nodes-image-cache/ pause容器能够为pod创建初始的名称空间&#xff0c;pod的内的容器共享其中的网络空…

库函数qsort 的模拟实现

在之前了解了库函数qsort的使用之后 我们来模拟实现一下上篇有介绍 qsort的底层实现是快速排序 由于害怕没有人了解过快速排序 我就用大家熟知的冒泡排序进行模拟实现 先来展示完整代码 以下代码为升序排序 如果降序将冒泡排序中的大于号改为小于号就可以了#define _CRT_SECURE…

malloc实现原理探究

2021年末面试蔚来汽车&#xff0c;面试官考察了malloc/free的实现机制。当时看过相关的文章&#xff0c;有一点印象&#xff0c;稍微说了一点东西&#xff0c;不过自己感到不满意。今天尝试研究malloc的实现细节&#xff0c;看了几篇博文&#xff0c;发现众说纷纭&#xff0c;且…

MySql启动错误(Mac系统 安装 mysql-8.0.32-macos13-arm64 后每次点击启动 无法启动) --- 已解决

MySql启动的时候: 立即变红! 查看日志如下: 2023-03-04T14:18:01.089671Z 0 [System] [MY-010910] [Server] /usr/local/mysql/bin/mysqld: Shutdown complete (mysqld 8.0.32) MySQL Community Server - GPL. 2023-03-04T14:18:10.304169Z 0 [System] [MY-010116] [Server]…

【EDA工具使用】——VCS和Verdi的联合仿真的简单使用

目录 1.芯片开发所需的工具环境 2.编译仿真工具 3.三步式混合编译仿真&#xff08;最常用&#xff09;​编辑 4.两步式混合编译仿真​编辑 5.VCS的使用 ​6.verdi的使用 1.产生fsdb文件的两种方法​编辑 1.芯片开发所需的工具环境 2.编译仿真工具 3.三步式混合编译仿真…

按位与为零的三元组[掩码+异或的作用]

掩码异或的作用前言一、按位与为零的三元组二、统计分组1、map统计分组2、异或掩码总结参考资料前言 当a b 0时&#xff0c;我们能够很清楚的知道b是个什么值&#xff0c;b 0 - a -a&#xff0c;如果当a & b 0时&#xff0c;我们能够很清楚的知道b是什么值吗&#xf…

Python GUI界面编程-初识

图形用户界面(Graphical User Interface&#xff0c;简称 GUI&#xff0c;又称图形用户接口)是指采用图形方式显示的计算机操作用户界面。与早期计算机使用的命令行界面相比&#xff0c;图形界面对于用户来说在视觉上更易于接受。然而这界面若要通过在显示屏的特定位置&#xf…

HiveSQL一天一个小技巧:如何精准计算非连续日期累计值【闪电快车面试题】

0 需 求稀疏字段累计求和问题1 问题分析根据图片中数据变换的形式&#xff0c;可以看出是根据字段term补齐数据中缺失的日期&#xff0c;term为连续日期的个数&#xff0c;当为12时&#xff0c;表明由2018-12-21到2019-01-02连续日期个数为12&#xff0c;当补齐日期后&#xff…

sklearn中的逻辑回归

目录 一.名为“回归”的分类器 二.逻辑回归的优点 三.sklearn中的逻辑回归 四.linear_model.LogisticRegression 五.penalty & C(正则化) 六.逻辑回归中的特征工程 1.业务选择 2.PCA和SVD一般不用 3.统计方法可以使用&#xff0c;但不是非常必要 4.高效的嵌入法e…

【vulhub漏洞复现】CVE-2013-4547 Nginx 文件名逻辑漏洞

一、漏洞详情影响版本 Nginx 0.8.41 ~ 1.4.3 / 1.5.0 ~ 1.5.7通过%00截断绕过后缀名的限制&#xff0c;使上传的php内容文件被解析执行。当Nginx得到一个用户请求时&#xff0c;首先对url进行解析&#xff0c;进行正则匹配&#xff0c;如果匹配到以.php后缀结尾的文件名&#x…

2022秋-2023-中科大-数字图像分析-期末考试试卷回忆版

今天晚上刚考完&#xff0c;心累&#xff0c;在这里继续授人以渔(仅供参考&#xff0c;切勿对着复习不看ppt&#xff0c;ppt一定要过两遍)。 注意:往年的经验贴&#xff0c;到此为止&#xff0c;全部作废&#xff0c;一个没考。千万不要只对着复习&#xff0c;SIFT没考&#x…

JavaScript(JS)

一、三种引入方式&#xff1a; 1、内部js 通过script标签嵌入到html里面 <script>alert(hello);</script> 2、外部js 写成一个单独的.js文件&#xff0c;让html引入进来 <script src"app.js"></script> 3、行内js 直接写到html内部 &…

Python爬虫——使用socket模块进行图片下载

Python爬虫——使用socket模块进行图片下载什么是socket爬虫的工作流程socket爬取图片为什么能用socket能下载图片socket下载图片和request下载图片的区别使用socket下载一张图片使用socket下载多张图片方法1方法2什么是socket Socket 是一种通信机制&#xff0c;用于实现网络…

AQS为什么用双向链表?

首先&#xff0c;在AQS中&#xff0c;等待队列是通过Node类来表示的&#xff0c;每个Node节点包含了等待线程的信息以及等待状态。下面是Node类的部分源码&#xff1a;static final class Node {// 等待状态volatile int waitStatus;// 前驱节点volatile Node prev;// 后继节点…

【AI绘图学习笔记】深度学习相关数学原理总结(持续更新)

如题&#xff0c;这是一篇深度学习相关数学原理总结文&#xff0c;由于深度学习中涉及到较多的概率论知识&#xff08;包括随机过程&#xff0c;信息论&#xff0c;概率与统计啥啥啥的)&#xff0c;而笔者概率知识储备属实不行&#xff0c;因此特意开一章来总结&#xff08;大部…

Jackson CVE-2017-17485 反序列化漏洞

0x00 前言 同CVE-2017-15095一样&#xff0c;是CVE-2017-7525黑名单绕过的漏洞&#xff0c;主要还是看一下绕过的调用链利用方式。 可以先看&#xff1a; Jackson 反序列化漏洞原理 或者直接看总结也可以&#xff1a; Jackson总结 涉及版本&#xff1a;2.8.10和2.9.x至2.…

leetcode_贪心算法

贪心算法相关题简单题目455.分发饼干1005.K次取反后最大化的数组和860.柠檬水找零序列问题376.摆动序列法一&#xff1a;贪心法法二&#xff1a;动态规划单调递增的数字简化版本有点难度53.最大子序和贪心算法动态规划134.加油站968.监控二叉树两个维度权衡问题分发糖果406.根据…