C语言——字符函数和内存函数

devtools/2025/1/8 18:45:04/

目录

前言

字符函数

1strlen

模拟实现

2strcpy 

模拟实现

3strcat 

模拟实现 

4strcmp  

模拟实现

5strncpy

模拟实现

6strncat

模拟实现

7strncmp

模拟实现

8strstr 

模拟实现

9strtok

10strerror

11大小写字符转换函数

内存函数

1memcpy

模拟实现

2memmove

模拟实现

3memset

4memcpy


前言

 C语言对应字符串的处理很繁琐(比如经常要知道它们的长度啦,拷贝啦,移动啦):                     所以专门提供了一些列字符(串)函数来方便使用者处理使用~

 而我们在学习各种函数时,推荐cplusplus.com来进行学习使用~

字符函数

1strlen

a计算的是字符串总长度(不包含\0)

b参数传的是字符串首元素地址,返回类型是size_t (无符号整数) 

如果你对它返回类型一知半解,那么下面的这道题你一定会做错!

#include <stdio.h>
int main()
{const char* str1 = "abcdef";const char* str2 = "bbb";if (strlen(str2) - strlen(str1) > 0){printf("str2>str1\n");}else{printf("srt1>str2\n");}return 0;
}

第一眼感觉 strlen(str2) - strlen(str1) = 3 - 6 <0 所以返回的是 str>2str1

但实际上是两个无符号整数相减,结果还是正整数!

模拟实现

//计数器
int Strlen1(char* s)
{int cnt = 0;while (*s != '\0'){cnt++;s++;}return cnt;
}//递归
int Strlen2(char* s)
{if (*s == '\0') return 0;return 1 + Strlen2(++s);//先s移动再递归!
}//指针-指针
int Strlen3(char* s)
{char* begin = s, * end = s;while (*end != '\0') end++;return end - begin;
}

2strcpy 

a 源字符串(第二个参数)必须以 '\0' 结束

否则会不断给目的字符串复制,des字符串复制超过最大空间后,就会越界访问(程序崩溃)
b复制会将源字符串中的 '\0' 拷贝到目标空间。
c目标空间必须足够大,以确保能存放源字符串;小于(源字符串的长度+1)同样崩
所以目标空间必须可变,如char*类型

模拟实现

char* Strcpy(char* desnation, const char* source)
{char* ret = desnation;while (*desnation++ = *source++)//拷贝了source的'\0'后循环停止{}return ret;
}

3strcat 

a源字符串必须以 '\0' 结束
b目标空间必须有足够的大,能容纳下源字符串的内容。
c目标空间必须可修改。 

自己给自己追加,如何?

 理论上会一直遇不到‘\0’,直到越界访问程序崩溃!                                                                           但实际上库函数是可以实现自己给自己追加,但还是不推荐这样做~

模拟实现 

char* Strcat(char* desnation, const char* source)
{char* ret = desnation;while (*desnation != '\0'){desnation++;}//des指向'\0'while (*desnation++ = *source++){}return ret;
}

4strcmp  

该函数用来进行两个字符串的比较大小:从第一个字符开始比,如果相同就往下一个比...

返回值:

 >0 说明str1比str2大

 =0 说明str1与str2一样大

 <0 说明str1比str2小

模拟实现

int Strcmp(const char* str1, const char* str2)
{while (*str1 == *str2){if (*str1 == '\0') return 0;str1++;str2++;}//if (*str1 > *str2) return 1;//else return -1;return *str1 - *str2 >0 ? 1 : -1;
}

以上的strcpy,strcat和strcmp都是不受长度限制的函数,同时使用时必须先考虑字符串长度大小, 而接下来的函数则是受长度限制的函数,相对安全些~

5strncpy

与strcpy功能类似,但加了一个num参数,表示你当前要拷贝多少个字符(‘\0’算在内)

模拟实现

char* Strncpy(char* desnation, const char* source,int num)
{char* ret = desnation;while ((num--)&&(*desnation++ = *source++))//拷贝了source的'\0'后循环停止{}return ret;
}

6strncat

与strcat是类似的:但你可以选择追加num个字符(‘\0’不算在内),追加完后自动加'\0'

模拟实现

char* Strncat(char* desnation, const char* source,int num)
{char* ret = desnation;while (*desnation != '\0'){desnation++;}while ((num--)&&(*desnation++ = *source++)){}*desnation = '\0';//不管source指没指向'\0'都要添加return ret;
}

7strncmp

与strcmp是类似的:但你可以自己选择num个字符进行比较

模拟实现

int Strncmp(const char* str1, const char* str2,int num)
{while ((--num)&&(*str1 == *str2)){if (*str1 == '\0') return 0;str1++;str2++;}if (*str1 == *str2) return 0;else return *str1 - *str2 > 0 ? 1 : -1;
}

8strstr 

 从str1中找包含str2的子串,找到了就返回str1出现子串的第一个位置的地址~

模拟实现

const char* Strstr(const char* str1, const char* str2)
{if (*str2 == '\0') return str1;//边界情况//匹配过程每次比较时的开始位置const char* p1 = str1;//进行移动判断字符是否相等const char* m1;const char* m2;while (*p1 != '\0'){m1 = p1, m2 = str2;while (*m2 != '\0' && *m1 == *m2){m1++;m2++;}if (*m2 == '\0') return p1;p1++;}return NULL;
}

9strtok

a delimiters是一个标记符集合;

b 将str中出现的标记符进行替换成“\0”(调用一次只会替换一个);

c 如果替换操作完成,返回替换开始前的地址;替换失败(找不到标记符),返回NULL

d 也就是说:str传进来的参数是要被进行修改的,所以使用前要先将内容进行拷贝一份;

e 调了一次后,接下来要把str置NULL(因为strtok已经记住了下次从什么位置开始替换)

int main()
{char str[] = "zzj@qq.com";char arr[20];strcpy(arr, str);/*char* pch;pch = strtok(arr, ".@");while (pch != NULL){printf("%s\n", pch);pch = strtok(NULL, ".@");}*/for (char* pch = strtok(arr, ".@"); pch != NULL; pch = strtok(NULL, ".@")){printf("%s\n", pch);}return 0;
}

10strerror

返回错误码所对应的信息字符串,我们需要再用printf进行打印出来

相对类似的还有 perror 它不用printf打印方便些:

 

11大小写字符转换函数

小转大:toupper 大转小:tolower

内存函数

为了防止拷贝内容不只有字符串(可以用strncpy),所以需要内存函数来实现

1memcpy

从source中复制num个字节到destination中;

模拟实现

void* Memcpy(void* de, void* so, size_t num)
{while (num--){*((char*)de) = *((char*)so);//前置++在vs或许能过,但在别的平台就不能保证(++优先级高于强转)//++(char*)de;//++(char*)so;de=(char*)de+1;so=(char*)so+1;}
}

能不能实现在同一个数组进行拷贝?

如果用我们模拟实现出来的函数,是不行的:拷贝时会把后面的数给覆盖掉

标准规定:使用非一块空间复制用memcpy;使用同一块空间复制用memmove

但是如果用memcpy呢?

 居然是可以!难道是我们实现出来的代码有问题?                                                                         当然不是:我们实现出来的按照标准来说是合格了的;但在VS平台中实现的memcpy不仅是符合标准的,而且还把它给加强了,只能说是满分级别的标准~

2memmove

与memcpy的参数是一样的,通常用来解决同一块空间进行复制

模拟实现

解决上面数据被覆盖的问题,我们可以选择从后先前拷贝,那是不是所有的情况都适合?

如果是上面的情况,从后先前拷贝也出现了数据被覆盖的问题,这时选择从前向后拷贝更合适~

所以要分情况进行讨论:来决定用那种拷贝方式

3memset

 

以字节为单位:将num个字节设置成value值

 应用与字符串时:

能做到,那如果想把int类型的值进行修改呢?

做不到:它是按字节为单位进行修改的;如果是修改成0的话就可以

所以它通常是用来进行将空间全部置为0(清理空间)

4memcpy

以字节为单位比较从desnation和source指针开始的num个字节

使用:

以上便是全部内容,有问题欢迎在评论区指正,感谢观看!


http://www.ppmy.cn/devtools/148963.html

相关文章

什么是 ERP?

目录 企业资源计划&#xff08;ERP&#xff09;的定义 ERP与财务管理的区别 ERP基础知识 ERP的业务价值 ERP简史 ERP部署模式&#xff1a;从本地部署到云端 ERP云 — 新的ERP交付模式 迁移至ERP云技术解决方案的7个原因 企业资源计划&#xff08;ERP&#xff09;的定义 …

线程-8-日志_线程池

主要看code 日志&#xff1a; 日志指标/属性 设计模式&#xff1a;策略模式 日志格式&#xff1a; [可读性很好的时间] [⽇志等级] [进程pid] [打印对应⽇志的⽂件名][⾏号] - 消息内容&#xff0c;⽀持可 变参数 [2024-08-04 12:27:03] [DEBUG] [202938] [main.cc] [16] - h…

git 常用命令和本地合并解决冲突

目录 一、常用命令 二、本地可视化合并分支解决冲突 一、常用命令 最近&#xff0c;使用mac电脑&#xff0c;无法直接使用小乌龟进行可视化操作&#xff0c;现在记录一些常用命令。 拉取&#xff1a; git clone <git url> 仅拉起某个单独分支&#xff1a; git clo…

playwright 录制

一、新建项目TestProject3 二、准备swagger 三、开始录制 打开PowerShell 7 (x64) cd D:\xxx\xxx\VS2022Projects\TestProject3\TestProject3\bin\Debug\net8.0 pwsh playwright.ps1 codegen --targetcsharp -b chromium localhost:5252/swagger/index.html #支持的语言 java…

conda快速安装并配置pycharm

1、镜像下载地址 https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/2、安装完成后配置环境变量 安装记得all users 配置环境 3、配置镜像 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https…

阿尔法linux开发板ping不通百度

我使用的阿尔法linux板子&#xff0c;发现按照《03【正点原子】I.MX6U网络环境TFTP&NFS搭建手册V1.3.2》一套操作下来&#xff0c;还是没办法实现板子上网。 我总结了下面方法&#xff0c;我如何实现联网和互ping通&#xff0c;大致总结下三步 一、pc端的wifi网络&#xf…

Flutter Web 中文字体显示异常问题

flutter web 在中文使用粗体的时候发现了两个问题 一个字的笔画颜色不相同带有 ‘口’的字 这个口由于太粗出现了实体闭合的情况 解决方案 替换字体 对于这个问题解决的办法只有替换中文字体库&#xff0c;因为只有粗体才有问题&#xff0c;所以只需要添加粗体字体即可。我…

HTML——69.表单验证属性

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>表单验证属性</title></head><body><!--input元素的type属性&#xff1a;(必须要有)--> <!--pattern属性:1.规定输入字符的模式&#xff08;如要…