【C语言】内存函数介绍

news2025/1/12 15:49:25

它们所在的头文件:

(这里出现的arr都为char类型数组)

    • strlen

作用:计算一个字符串的长度

本质:历经千辛找一个 \0 ,找到 \0 就立马停止。(就是找 \0 )

易错:strlen 返回值为 size_t ,易错点

strlen 的模拟实现:

//方法一
#include <stdio.h>
#include <assert.h>

int my_strlen(const char* str)
{
    assert(str != NULL);
    const char* soc = str;

    while (*soc++ != '\0')
    {
        ;
    }

    return soc - str - 1;

}

int main()
{
    char arr[20] = { 0 };
    scanf("%s", arr);

    printf("%d", my_strlen(arr));

    return 0;
}


//方法二
//#include <stdio.h>
//#include <assert.h>
//
//int my_strlen(const char* str)
//{
//    assert(str != NULL);
//    int count = 0;
//
//    while (*str++ != '\0')
//    {
//        count++;
//    }
//
//    return count;
//
//}
//
//int main()
//{
//    char arr[20] = { 0 };
//    scanf("%s", arr);
//
//    printf("%d\n", my_strlen(arr));
//
//    return 0;
//}


//方法三
//#include <stdio.h>
//#include <assert.h>
//
//int my_strlen(const char* str)
//{
//    assert(str != NULL);
//    
//    if (*str++ != '\0')
//    {
//        return 1 + my_strlen(str);
//    }
//    else
//    {
//        return 0;
//    }
//
//}
//
//int main()
//{
//    char arr[20] = { 0 };
//    scanf("%s", arr);
//
//    printf("%d\n", my_strlen(arr));
//
//    return 0;
//}
//

2、strcpy 和 strncpy

strcpy

格式: strcpy(arr1, arr2);

作用:将源字符串拷贝到目标字符串

核心:

while (*str1 = *str2)

{

;

}

(将arr2的内容全部赋给arr1, 不管arr1里面是什么,只要放的下就行)

一旦知道了其核心,就知道它相关的细节问题:

如上 arr2 的 \0 赋过去时才停止,所以会把 arr2 的 \0 赋过去

就是要注意,目标空间(arr1)够大,放得下 arr1;并且是可修改空间(arr1内容不能是字符常量)

strcpy模拟实现:

#include <stdio.h>
#include <string.h>
#include <assert.h>


char* my_strcpy(char* str1, const char* str2)
{
    assert(str1 != NULL);
    assert(str2 != NULL);

    while (*str1++ = *str2++)
    {
        ;
    }

}



int main()
{
    char arr1[20] = { 0 };
    char arr2[20] = { 0 };
    scanf("%s", arr1);
    scanf("%s", arr2);

    my_strcpy(arr1, arr2);

    printf("%s", arr1);

    return 0;
}

strncpy

格式:strncpy(arr1, arr2, num);

作用:将源字符串的 num 个字符拷贝到目标字符串

核心内容:

除了返回值,不同在于循环时多了个条件来限制给值

while (num && (*str1++ = *str2++))

{

num--;

}

模拟实现:

#include <stdio.h>
#include <assert.h>

char* my_strncmp(char* str1, const char* str2, size_t num)
{
    assert(str1 != NULL);
    assert(str2 != NULL);

    while (num && (*str1++ = *str2++))
    {
        num--;
    }

    if (num)
    {
        while (--num)
        {
            *str1++ = '\0';
        }
    }

    return str1;

}


int main()
{
    char arr1[20] = { 0 };
    char arr2[20] = { 0 };
    scanf("%s", arr1);
    scanf("%s", arr2);

    my_strncmp(arr1, arr2, 3);

    printf("%s\n", arr1);

    return 0;
}

3、strcmp 和 strncmp

srtcmp

作用:比较两个字符串对应位置上的字符

格式:strcmp(arr1, arr2);

返回值:(相等比下一个,直到结束)

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

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

若对应字符全都相等,才返回0

(visual stdio中大于0是返回1,小于0返回-1, 其他环境下不一定)

模拟实现 stcmp:

//实现strcmp
#include <stdio.h>
#include <assert.h>

int my_strcmp(const char* str1, const char* str2)
{
    assert(str1 != NULL);
    assert(str2 != NULL);

    while (*str1 == *str2)
    {
        if (*str1 == 0)
        {
            return 0;
        }

        str1++;
        str2++;
    }

    if (*str1 > *str2)
    {
        return 1;
    }
    else
    {
        return -1;
    }

    /*return *str1 - *str2;*/

}

int main()
{
    char arr1[20] = { 0 };
    char arr2[20] = { 0 };
    scanf("%s", arr1);
    scanf("%s", arr2);

    int ret = my_strcmp(arr1, arr2);

    printf("%d\n", ret);

    return 0;
}

strncmp

作用:比较两个字符串 num 个数前的字符

格式:strncmp(arr1, arr2, num);

返回值标准和 strcmp 一样

模拟实现(简易版):

//实现简易strcmp
#include <stdio.h>
#include <assert.h>

int my_strncmp(const char* str1, const char* str2, size_t num)
{
    assert(str1 != NULL);
    assert(str2 != NULL);

    while ((*str1 == *str2) && num)
    {
        if (*str1 == 0)
        {
            return 0;
        }

        str1++;
        str2++;
        num--;
    }

    if (!num)
    {
        return 0;
    }

    if (*str1 > *str2)
    {
        return 1;
    }
    else if (*str1 < *str2)
    {
        return -1;
    }

    /*return *str1 - *str2;*/

}

int main()
{
    char arr1[20] = { 0 };
    char arr2[20] = { 0 };
    scanf("%s", arr1);
    scanf("%s", arr2);

    size_t num = 0;
    scanf("%u", &num);

    int ret = my_strncmp(arr1, arr2, num);

    printf("%d\n", ret);

    return 0;
}

4、strcat 和 strncat

strcat

作用:在一个目标字符串后追加字符串

格式:strcat(arr1, arr2);

意思是在 arr1 后追加一个 arr2

etc. arr1 = "abcde"; arr2 = "abc";

strcat (arr1, arr2); 这样的结果是:arr1里的内容变成: abcdeabc\0

strcat(arr1, "abcdef"); (例二)

模拟实现:

//模拟实现 strcat
#include <stdio.h>
#include <assert.h>

char* my_strcat(char* str1, const char* str2)
{
    assert(str1 && str2);
    char* soc = str1;

    while (*str1)
    {
        str1++;
    }

    while (*str1++ = *str2++)
    {
        ;
    }

    return soc;

}


int main()
{
    char arr1[20] = { 0 };
    char arr2[20] = { 0 };
    scanf("%s", arr1);
    scanf("%s", arr2);

    my_strcat(arr1, arr2);

    printf("%s", arr1);

    return 0;
}

strncat

作用:和strcat差不多,在目标字符串后追加一定数目的字符(变得可以控制长度)

格式:strncat(arr1, arr2, 4);

意思是在 arr1 后追加一个 arr2 里的前 4 个字符

etc. arr1 = "abcdef"; arr2 = "abcde";

strncat (arr1, arr2, 4); 这样的结果是:arr1里的内容变成: abcdeabcd\0

strncat(arr1, "abcdef", 5); (例二)

模拟实现 strncat:

//模拟实现 strncat
#include <stdio.h>
#include <assert.h>

char* my_strncat(char* str1, const char* str2, size_t num)
{
    assert(str1 && str2);
    char* soc = str1;

    while (*str1)
    {
        str1++;
    }

    while (num-- && (*str1++ = *str2++))
    {
        ;
    }

    return soc;

}


int main()
{
    char arr1[20] = { 0 };
    char arr2[20] = { 0 };
    scanf("%s", arr1);
    scanf("%s", arr2);

    size_t num = 0;
    scanf("%u", &num);

    my_strncat(arr1, arr2, num);

    printf("%s", arr1);

    return 0;
}

5、strstr

作用:寻找字符串arr1中 是否存在 字符串arr2

格式:strstr(arr1, arr2);

意思是寻找 arr1 里的子字符串 有没有和 arr2 相等的

有 就返回:arr1里 目标字符串的首字符地址 (可能不止存在一个,返回找到的第一个子字符串手字符地址)

etc. arr1 = "abcde"; arr2 = "abc";

strstr(arr1, arr2); 返回的结果是arr1中字符 'a' 的地址

模拟实现:

//简易版
#include <stdio.h>
#include <assert.h>
#include <string.h>


int my_strncmp(const char* str1, const char* str2, int sz)
{
    while (sz-- && (*str1 == *str2))
    {
        if (0 == sz)
        {
            return 0;
        }

        str1++;
        str2++;
    }

    return 1;

}


char* my_strstr(const char* str1, const char* str2)
{
    assert(str1 != NULL);
    assert(str2 != NULL);

    size_t sz1 = strlen(str1);
    size_t sz2 = strlen(str2);

    if (sz1 < sz2)
    {
        printf("非法输入\n");
    }

    for (int i = 0; i <= sz1 - sz2; i++)
    {
        char* soc = str2;
        //abcdef
        //cde

        if (!my_strncmp(str1, soc, sz2))
        {
            return str1;
        }

        str1++;

    }

    return NULL;

}

int main()
{
    char arr1[20] = { 0 };
    char arr2[20] = { 0 };
    scanf("%s", arr1);
    scanf("%s", arr2);

    char* p = my_strstr(arr1, arr2);

    if (p != NULL)
    {
        printf("\n\n是否存在:存在\n");
        printf("\n打印符合要求字符串及后面的全部字符:%s\n", p);
    }
    else
    {
        printf("\n存在情况:不存在 (null)\n");
    }

    return 0;
}

6、strtok

作用:将一串带有特殊符号的字符串分隔开(特殊符号一般指标点如 '.' 、'@' 、' * ' )

etc. zhuzhu@yxr.com

strtok 函数可以将上面字符串分割成 "zhuzhu" ,"yxr", "com"

格式:char*strtok ( char*strToken, constchar*strDelimit );

作用的原理是将特殊字符变为 '\0' ,所以实现得先将特殊字符写成一串字符串,放到一个指针里(等下传参也这样规定)

函数第一个参数为要被分隔的字符串;第二个参数为指向分隔符的指针,实现准备好了穿过指针去就OK

返回值:返回该次 “截剪” 的字符串首元素地址 (如上使用一次strtok,返回字符 'z' 的地址);最后分隔符找完会返回 NULL

细节:因为其作用原理(是将分隔符赋为'\0'),所以会改变传过去的字符串内容,当我们不想一个字符串被改变时,可以先把字符串拷贝一份,再传过去

注意使用一次strtok只是将第一个要分隔的地方进行分隔,相当于还没“剪完”,所以要多次使用 ———> 想到循环

而第二次使用时:

第一个参数只要传 NULL 空指针就好,strtok会记录上次改 \0 的位置,在其后再寻找分隔符(第二次:strtok(NULL, pc) )

(可猜出strtok函数中使用了statistic,以至于一些数据一直存在不被销毁)

基本用法:(基本循环写法)

7、strerror

#include

当程序出现各种错误时,每周错误对应一个数字编码,如果只把数字编码反馈出来给我们看,看不懂反正我不看

而 strerror 相当于一个翻译官,可以将这些数字编码转化,返回一个字符串首元素地址,这串对应的字符串就是我们可以看得懂的错误信息,返回该地址后我们用printf来打印,就可以知道错误信息

头文件:

格式:strerror(errno)

作用:返回错误信息

具体用法:

首先的知道当产生错误后,用时也会产生一个数字编码,而这个数字编码存放在哪里呢?是存放在errno这个变量里

所以使用 strerror 时,我们要到 errno 这个变量里去拿到数字编码,所以格式为 strerror(errno)

etc. printf("%s", strerror(errno) );

8、memcpy

格式:memcpy(arr1, arr2, num);

作用:拷贝源空间到目标空间

一定要注意 num 的单位,字节为单位

所以传num时,num = 1字节 * 类型大小 * 拷贝个数

etc. num = 1 * 4 * 要拷贝整型数的个数

模拟实现初级memcpy:(该版本不能拷贝自身局部内容)

//memcpy 的初级实现(移植性强版本)
#include <stdio.h>
#include <assert.h>

void* my_memcpy(void* dest, const void* src, size_t num)
{
    assert(dest && src);
    void* soc = dest;

    while (num--)
    {
        *(char*)dest = *(char*)src;
        dest = (char*)dest + 1;
        src = (char*)src + 1;
    }

    return soc;

}

int main()
{
    /*char arr1[20] = { 0 };
    char arr2[20] = { 0 };
    scanf("%s", arr1);
    scanf("%s", arr2);*/

    int arr1[20] = { 1, 2, 3, 4, 5 };
    int arr2[20] = { 6, 7, 8, 9, 10 };

    size_t num = 0;
    scanf("%zu", &num);

    my_memcpy(arr1, arr2, num);

    /*printf("%s", arr1);*/

    for (int i = 0; i < 5; i++)
    {
        printf("%d ", *(arr1 + i));
    }

    return 0;
}

9、memmove (与memcpy很相似)

格式:memmove(arr1, arr2, num);

作用:拷贝源空间到目标空间

一定要注意 num 的单位,字节为单位(和memcpy一样)

所以传num时,num = 1字节 * 类型大小 * 拷贝个数

etc. num = 1 * 4 * 要拷贝整型数的个数

模拟实现初级memmove:

//memmove 的初级实现
#include <stdio.h>
#include <assert.h>

#define count 1000

void* my_memcpy(void* dest, const void* src, size_t num)
{
    assert(dest && src);
    void* soc = 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 soc;

}

int main()
{
    int arr[20] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    size_t num = 0;
    printf("请输入要移动的字节数:");
    scanf("%zu", &num);

    my_memcpy(arr + 2, arr, num);

    /*printf("%s", arr1);*/

    for (int i = 0; i < 10; i++)
    {
        printf("%d ", *(arr + i));
    }

    return 0;
}

10、一些常见的字符函数

这些函数直接使用就好了,如果记不住那就去记就好啦(可能可以在一些时候帮忙哦)

相关试题就放到后面再更新咯,大家记得电赞哦,不然晚上会梦见小只因哦(真的,昨天晚上我就梦见了)

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

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

相关文章

物联网无线通信技术中蓝牙和WIFI有哪些区别?

在物联网快速发展的时代&#xff0c;联网运行的设备越来越多&#xff0c;无线通信技术在物联网中发挥着举足轻重的作用&#xff0c;无线通信技术的发展改变了信息传输的方式&#xff0c;人们在任何时间、任何地点都可以访问设备&#xff0c;目前最常用的两种无线通信技术分别是…

云服务器CentOS前后端部署流程记录

部署流程记录 购买云服务ecs服务器&#xff0c;建立CentOS系统 通过xftpxshell访问远程服务 doker部署&#xff08;https://www.runoob.com/docker/centos-docker-install.html&#xff09; docker docker部署环境&#xff08;mysql&#xff09; docker常用命令 1. docker i…

【Linux】进程状态与优先级

文章目录进程状态概念Linux中的进程状态R(running)状态S(sleeping)状态D(disk sleep)状态T(stopped)状态t(tracing stop)状态X(dead)状态Z(zombie)状态特殊的孤儿进程进程优先级进程性质补充进程状态概念 《现代操作系统》中给出的进程状态的定义如下&#xff1a; 进程状态反映…

Qt+C++窗体界面中英文多语言切换

程序示例精选 QtC窗体界面中英文语言切换 如需安装运行环境或远程调试&#xff0c;见文章底部个人微信名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<QtC窗体界面中英文语言切换>>编写代码&#xff0c;代码整洁&#xff0c;规则&#x…

【Linux】软件包管理器 yum

目录 一、什么是软件包 二、如何进行软件安装 1、yum 的使用 2、yum 配置 一、什么是软件包 在Linux下安装软件&#xff0c;一个通常的办法是下载到程序的源代码&#xff0c;并进行编译&#xff0c;得到可执行程序。但是这样太麻烦了&#xff0c;于是有些人把一些常用的软…

InnoDB数据存储结构

InnoDB数据存储结构 本专栏学习内容来自尚硅谷宋红康老师的视频 有兴趣的小伙伴可以点击视频地址观看 1. 数据库的存储结构&#xff1a;页 索引结构给我们提供了高效的索引方式&#xff0c;不过索引信息以及数据记录都是保存在文件上的&#xff0c;确切来说是存储在页结构中。…

不讨论颜色的前提下,如何证明自己不是色盲?神奇的零知识证明

0x01 一个小故事 《阿里巴巴与四十大盗》中有这样一段小故事&#xff1a; 阿里巴巴会芝麻开门的咒语&#xff0c;强盗向他拷问打开山洞石门的咒语&#xff0c;他不想让人听到咒语&#xff0c;又要向强盗证明他知道这个咒语。 那应该怎么办呢&#xff1f; 便对强盗说&#xf…

基于KVM安装部署RHCOS操作系统

参考&#xff1a;Openshift 4.4 静态 IP 离线安装系列&#xff1a;初始安装 - 米开朗基杨 - 博客园 一、Openshift OCP集群安装架构示意图 RHCOS 的默认用户是 core 如果安装有问题会进入 emergency shell&#xff0c;检查网络、域名解析是否正常&#xff0c;如果正常一般是以…

重修JAVA

程序员的差距是在构思上&#xff1a;思想决定了深度&#xff0c;思想的精髓高深是很多人学不来的&#xff01; 每一门语言都有它的特点&#xff0c;有优势也有劣势&#xff0c; 所以不必拘泥于招式&#xff0c;掌握底层原理即可&#xff01; 每一们语言实际上都是一个“工具”&…

如何在您的香港主机帐户上注册多个域名

注册多个域名非常普遍。事实上&#xff0c;香港主机服务提供商鼓励这样做&#xff0c;因为它既有意义又是必要的。下面将介绍决定为什么您可能需要在香港主机上注册多个域名的几个因素。注册多个域名的原因是什么?方便多个项目如果香港主机帐户的所有者在网络上有多个不同域名…

优化vue项目后, 启动编译项目过程中 报 javaScript heap out of memory 错误 及 nodejs内存溢出

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 1、优化vue项目后&#xff0c;运行npm run serve 启动编译项目过程中 报 javaScript heap out of memory 错误 2、项目启动时&#xff0c;出现 nodejs 内存溢出错误 问题描述 提示&#xff1a;遇到…

分布式事务的背景和解决方案

在常用的关系型数据库&#xff0c;都是具备事务特性的。 那什么是事务呢&#xff1f;事务是数据库运行的一个逻辑工作单元&#xff0c;在这个工作单元内的一系列SQL命令具有原子性操作的特点&#xff0c;也就是说这一系列SQL指令要么全部执行成功&#xff0c;要么全部回滚不执…

经典算法之深度优先搜索(DFS)

&#x1f451;专栏内容&#xff1a;算法学习笔记⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;日拱一卒&#xff0c;功不唐捐。 目录一、前言二、基本概念1.简单介绍2. 官方概念三、动图分析四、模板框架五、例题分析组合问题题干描述&#xff1a;思路…

leetcode146. LRU 缓存【python3哈希表+双向链表】利用OrderedDict以及自实现双向链表

题目&#xff1a; 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。实现LRUCache类&#xff1a; LRUCache(int capacity) 以正整数作为容量capacity初始化 LRU 缓存int get(int key) 如果关键字key存在于缓存中&#xff0c;则返回关键字的值&#xff0c;否则…

【论文速递】9位院士Science88页长文:人工智能的进展、挑战与未来

【论文速递】9位院士Science88页长文&#xff1a;人工智能的进展、挑战与未来 【论文原文】&#xff1a;Intelligent Computing: The Latest Advances, Challenges and Future 获取地址&#xff1a;https://spj.science.org/doi/10.34133/icomputing.0006摘要&#xff1a; ​…

【阶段三】Python机器学习15篇:机器学习项目实战:支持向量机回归模型

本篇的思维导图: 项目实战(支持向量机回归模型) 项目背景 股票投资(Stock Investment)是指企业或个人用积累起来的货币购买股票,借以获得收益的行为。股票投资的收益是由“收入收益”和“资本利得”两部分构成的。收入收益是指股票投资者以股东身份,按照持股的份…

大网规划部署刷题讲解(带答案)

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.大网规划刷题 前言 本章将会讲解大网规划刷题的讲解。 一.大网规划刷题 …

ArcGIS基础实验操作100例--实验85创建线要素间的最近垂线

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验85 创建线要素间的最近垂线 目录 一、实验背景 二、实验数据 三、实验步骤 &#xf…

【一文速通】数据分布不同解决办法

1. 构造合适的验证集当出现训练集和测试集分布不一致的&#xff0c;我们可以试图去构建跟测试集分布近似相同的验证集&#xff0c;保证线下验证跟线上测试分数不会抖动&#xff0c;这样我们就能得到稳定的benchmark。Qiuyan918在基于对抗验证的基础上&#xff0c;提出了三种构造…

为什么流媒体直播的延迟很高

通信技术的发展促进了视频点播和直播业务的兴起&#xff0c;4G 和 5G 网络技术的进步也使得流媒体技术变得越来越重要&#xff0c;但是网络技术并不能解决流媒体直播的高延迟问题&#xff0c;本文不会介绍网络对直播业务的影响&#xff0c;而是会分析直播中常见的现象 — 主播和…