当前位置: 首页 > news >正文

字符函数与字符串函数 和C语言内存函数<string.h>

目录

字符分类函数

字符转换函数

基础函数使用

strlen 使用和模拟与实现

strcpy 使用和模拟与实现

strcat 使用和模拟与实现

strcmp 使用和模拟与实现

进阶函数使用

strncpy 函数的使用

strncat 函数的使用

strncmp 函数的使用

strstr 使用和模拟实现

strtok 函数使用

strerror 函数使用

perror 函数使用

C语言内存函数

memcpy 使用和模拟实现

memmove 使用和模拟实现

memset 函数的使用

memcmp 函数的使用


字符分类函数

C语言中有一系列的函数是专门做字符分类的,也就是一个字符是属于什么类型的字符的。这些函数的使用都需要包含一个头文件是ctype .h

这写函数其实都比较类似,就只介绍一个

int islower ( int c );

当识别到数值为a~z的小字母,就会返回非0 数值,如果不是就返回0数值。

字符转换函数

C语言提供了2个字符转换函数:

int tolower ( int c ); //将参数传进去的大写字母转小写 int toupper ( int c ); //将参数传进去的小写字母转大写

函数使用

#include <stdio .h> #include <ctype .h> int main () { int i = 0; char str [] = "Test String.\n"; char c; while (str[i]) { c = str [i]; if (islower(c)) c = toupper(c); putchar(c); i++; } return 0; }

但其实这中其实可以通过加减32来通过改变字符英文字母大小就可以,这个函数也只是作为一个了解即可。

<string.h>介绍

string.h 的库函数里面有strcpy、strcat、strcmp、strncpy、strncat、strncmp、strstr、strtok、strerror、memcmp等等的函数,那我们来一 一介绍。

基础<string.h>函数使用

strlen 使用和模拟与实现

strlen 的介绍

strlen 是用来计算字符串的首地址到达‘\0’位置之间又多少个字符的函数

补充:准确来说strlen 不是string.h 函数里面的没有string.h 的库函数也可以使用。

size_t strlen(char* str)

放回类型:size_t (非负数的整形类型)

传参: char* (字符指针)

模拟实现:

strlen_my 函数来实现代码:

方法1:

利用循环来实习strlen的代码实现:

原理:通过循环计算当代码执行到‘\0’的时候就停止计算。

size_t strlen_my1(char* str) { size_t i = 0; for (i = 0; *(str + i) != '\0'; i++); return i; }

方法2:

利用递归的方式来实现代码:

原理:通过执行代码如果不是‘\0’就进行1+strlen(str+1),如果遇到‘\0'就停止计算,返回值为0。

size_t strlen_my2(char* str) { if (*str) { return 1 + strlen_my2(str + 1); } return 0; }

strcpy 使用和模拟与实现

strcpy 的介绍

strcpy 是一个cpy 有关的函数,通过cpy 就是拷贝的功能,可以将一个数组的内容考培到了一个数组里面。

char* strcpy(char* str1,char const* str2)

返回值:char* 返回str1 的首元素地址

传参:

char* 第一个值是载体,要被同化对象。

char const * 第二个就是内容,从const *可以从不能对*str2不能修改内容就可以看出。

模拟实现

strcpy_my 函数来实现strcpy 函数代码实现

原理:

传参不能为空地址;

循环来实现代码,遇到‘\0’循环也可以直接结束;

在代码最开始的标记好首元素地址,循环执行完也也有直接返回地址。

char* my_strcpy(char* str1, char const* str2) { char* tmp = str1; assert(str1 != NULL); assert(str2 != NULL); while (*str1++ = *str2++); return tmp; }

strcat 使用和模拟与实现

strcat 的介绍

strcat 的函数与strcpy 类似也是跟拷贝有关,但是它与strcpy拷贝不同,strcat 是在str1的字符串最后‘\0‘位置进行拷贝

char * strcat ( char * destination , const char * source );

返回值:char* destination的最开始位置

传参:

destination:指针,指向目的地空间

source:指针,指向源头数据、

模拟实现:

my_strcat 实现代码:

原理就还是与strcpy 保持一致,就在拷贝之前先进行移位操作。

char* my_strcat(char* str1, char const* str2) { char* tmp = str1; assert(str1 != NULL); assert(str2 != NULL); while (*str1) str1++; while (*str1++ = *str2++); return tmp; }

strcmp 使用和模拟与实现

strcmp 的介绍

strcmp 是用来比较的函数,比较标准是通过ASCII 的数值大小来比较的。

int strcmp ( const char * str1 , const char * str2 );

返回值:

标准规定:

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

第一个字符串等于第二个字符串,则返回0

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

模拟实现:

my_strcmp来实现代码:
原理:

int my_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; }

进阶<string.h>函数使用

strncpy 函数的使用

strncpy 的介绍

strncpy 函数与strcpy 函数功能类似,多了一个传参值

char * strncpy ( char * destination , const char * source , size_t num );

函数的多了一个可以可控制拷贝多少的控制:size_t num

当如果str

参数:

destination:指针,指向目的地空间

source:指针,指向源头数据

num:从source指向的字符串中最多拷贝的字符个数

返回值:

strncpy函数返回的目标空间的起始地址

函数的使用:

#include <stdio.h> #include <string.h> int main() { char str1[20] = "hello world."; char str2[20] = "world"; strncpy(str1, str2,5); printf("%s", str1); return 0; }

以为world 要我去拷贝数量应该输入的6,而输入的是5 少拷贝了一个‘\0’的字符

strncat 函数的使用

strncat 的介绍

同理strncat 函数与strcat 函数也是多一个可控制的拷贝数量

int strncmp ( const char * str1 , const char * str2 , size_t num );

功能:字符串比较;比较str1str2指向的两个字符串的内容,最多比较num字符。

参数:

str1:指针,指向一个比较的字符串

str2:指针,指向另外一个比较的字符串

num:最多比较的字符个数

函数的使用

int main() { char str1[20] = "hello"; char str2[20] = " world.\0 I love me"; strncat(str1, str2,10); printf("%s", str1); return 0; }

可以看到如果拷贝对象值中间有一个‘\0’,那么只拷‘\0’的位置就停止就不会在往后拷贝了。

strncmp 函数的使用

strncmp 的介绍

同理:strncmp也是多一个比较数量

int strncmp ( const char * str1 , const char * str2 , size_t num );

参数:

str1:指针,指向一个比较的字符串

str2:指针,指向另外一个比较的字符串

num:最多比较的字符个数

返回值:

标准规定:

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

第一个字符串等于第二个字符串,则返回0

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

函数使用

int main() { char str1[20] = "abcdef"; char str2[20] = "abcde"; int i=strncmp(str1, str2,5); printf("%d", i); return 0; }

原理解释:

以为比较的长度只有5,那么比较str1 和str2 的长度5的内容一致,那么就直接返回0。


strstr 使用和模拟实现

strstr 的介绍

strstr 的功能是查找str2指向的字符串在str1指向的字符串中第一次出现的位置。

简而言之:就是找东西的函数

参数:

str1:指针,指向了被查找的字符串

str2:指针,指向了要查找的字符串

返回值:

如果str 1指向的字符串中存在str2指向的字符串,那么返回第一次出现位置的指针

如果str 1指向的字符串中不存在str2指向的字符串,那么返回NULL

函数的使用

int main() { char str1[20] = "hello world abcde"; char str2[20] = "abcde"; int* p=strstr(str1, str2); if (p) printf("%p", p); return 0; }

模拟实现

my_strstr 函数实现

char* my_strstr(char const* str1, char const* str2) { assert(str1 != NULL); assert(str2 != NULL); const char* const ret = str2;//标记好str2 的初始位置 char* tmp = str1; int input = 0;//设置查找标记 while (*str1) { tmp = str1;//标记好初始位置 str2 = ret; while (*str1++ == *str2++) { if (!*str2)//所有的数值查找到‘\0’,就标记好查找结束 { input = 1;//标记查找到的证明 break; } } if (input) return tmp;//返回标记1位置 tmp++; str1 = tmp; } return NULL; } int main() { char str1[20] = "hello world abcde "; char str2[20] = "world"; int* p=my_strstr(str1, str2); if (p) printf("%p", p); return 0; }


strtok 函数使用

strtok 的介绍

strtok 的函数的功能是分割字符串的功能

char *strtok(char *str , const char *delim);

参数

1.str:首次调用时传入待分割的字符串;后续调用传入NULL,表示继续分割同一个字符串。

2.delim:包含所有可能分隔符的字符串(每个字符均视为独立的分隔符)。

返回值

成功时返回指向当前子字符串的指针。

没有更多子字符串时返回NULL

使用步骤

1.首次调用:传入待分割字符串和分隔符。

2.后续调用:传入NULL和相同的分隔符,继续分割。

3.结束条件:当返回NULL时,表示分割完成。

注意strtok 具有一定的破坏性,会把原先的数组改的面目全非,为了防止代码对于原先字符串的破坏,要进行一个拷贝操作strcpy 。

函数的运用

展示1:

int main() { char str1[20] = "2026 5 10 21 28"; char str2[] = " "; char cpy[30] = {0}; strcpy(cpy, str1); for (char* str = strtok(cpy, str2); str != NULL; str = strtok(NULL, str2)) { printf("%s\n", str); } return 0; }

展示2:

int main() { char str1[50] = "https://hello.world.com/";//分割内容 char str2[] = ":./";//分割标准 char cpy[30] = {0}; strcpy(cpy, str1); for (char* str = strtok(cpy, str2); str != NULL; str = strtok(NULL, str2)) { printf("%s\n", str); } return 0; }


strerror 函数使用

strerror的介绍

strerror 函数就像名字一样,error 是跟报错有关的代码

char* strerror ( int errnum );

传参:

int 对应的数值输出对应的报错

for (int i = 0; i <= 10; i++) { printf("%s\n", strerror(errno)); }

//0 : No error 无错误
//1 : Operation not permitted 操作不被允许
//2 : No such file or directory 没有该文件或目录
//3 : No such process 没有给进度
//4 : Interrupted function call 函数调用中断
//5 : Input / output error 输入/输出错误
//6 : No such device or address 没有该设备或地址
//7 : Arg list too long 参数列数表过长
//8 : Exec format error 可执行格式错误
//9 : Bad file descriptor 错误的文件描述符
//10 : No child processes 没有子进度

怎么多的数值,我们也不可能一个一个去记住,所有就有<errno.h>这个库函数,来辅助程序员,当代码发生对应的错误的时候就会把对应代码报错信息,就会存进errno这个数值里面。

函数使用

#include <stdio.h> #include <errno.h> #include <stdlib.h> int main() { int* arr = (int*)malloc(sizeof(int) * INT_MAX); if (arr == NULL) { printf("error:%s\n", strerror(errno)); return 1; } return 0; }

这里也报错输出了:内存空间不足的报错信息。

那有点人还是说,太麻烦了,那么有没有更加方便的函数呢?当然还有一个更加方便的函数。

perror 函数使用

他就是strerror 和errno 的结合体,可以不需要<string.h>和<errno.h>库函数就可以使用,没有任何限制就可以直接使用。

所以这个函数就是程序员最常用的报错代码之一了。

int main() { int* arr = (int*)malloc(sizeof(int) * INT_MAX); if (arr == NULL) { perror("error"); return 1; } return 0; }

其实就等价于刚才这段代码

printf("error:%s\n", strerror(errno));

注意perror 会自动多加有一个" : "(冒号)在里面。

C语言内存函数 <string.h>

memcpy 使用和模拟实现

memcpy 的介绍

memcpy 的函数其实还是与cpy 拷贝有关,类似于strncpy的功能,但是这个函数的传参第三个值的意义就有所不同了。

void * memcpy (void * destination , const void * source , size_t num );

功能:

memcpy是完成内存块拷贝的,不关注内存中存放的数据是啥

函数memcpysource的位置开始向后复制num个字节的数据到destination指向的内存位置。

如果sourcedestination有任何的重叠,复制的结果都是未定义的。(内存重叠的情况使用memmove就行)

参数:

destination:指针,指向目标空间,拷贝的数据存放在这里

source:指针,指向源空间,要拷贝的数据从这里来

num:要拷贝的数据占据的字节数

返回值:

拷贝完成后,返回目标空间的起始地址

函数使用

展示1:

int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 }; int arr2[10] = { 0,9,8,7,6,5,4,3,2,1 }; memcpy(arr2, arr1, 24); for (int i = 0; i < 10; i++) { printf("%d ", arr2[i]); } return 0; }

可看到arr2 对前面6个整形int 类型进性修改数值,而且刚好他的修改数值24,是6*4=24个字节的大小,那么其实修改数量的就是字节位置修改数值。

模拟实现

void* my_memcpy(void* str1, void const* str2, size_t size) { void* tmp = str1; assert(str1); assert(str2); while (size--) { *(char*)str1 = *(char*)str2; str1 = (char*)str1 + 1; str2 = (char*)str2 + 1; } return tmp; } int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 }; int arr2[10] = { 0 }; my_memcpy(arr2, arr1, 24); for (int i = 0; i < 10; i++) { printf("%d ", arr2[i]); } return 0; }

memmove 使用和模拟实现

memmove 的介绍

memmove 函数其实就是strncat 的翻版,但是以为无需考虑'\0'的问题,就其实功能还是与memcpy 一致 ,他们本质区别在于memmove可以处理内存地址重叠问题,但你如果真的去使用的话两个都是可以处理这类问题,但还是记住一些memmove 可以处理重叠问题就可以。

void * memmove ( void * destination, const void * source, size_t num );

函数使用

展示1:

#include <stdlib.h> int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 }; memmove(arr1+2, arr1, 24); for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }

展示2:

int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 }; memmove(arr1, arr1+2, 24); for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }

模拟实现

my_memmove 代码展示:

void* my_memmove(void* str1, void const* str2, size_t size) { void* tmp = str1; assert(str1); assert(str2); if (str1 < str2) { //从前往后走 while (size--) { *(char*)str1 = *(char*)str2; str1 = (char*)str1 + 1; str2 = (char*)str2 + 1; } } else if(str1 > str2) { //从后往前走 int size_my = size; while (--size) { str1 = (char*)str1 + 1; str2 = (char*)str2 + 1; } size = size_my; while (size--) { *(char*)str1 = *(char*)str2; str1 = (char*)str1 - 1; str2 = (char*)str2 - 1; } } else { return tmp; } return tmp; } int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 }; my_memmove(arr1+2, arr1, 24); for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }

为什么需要花费大费周章的去搞是从前往后走还是从后往前走的情况呢?

以为如果不去细分的话就发生数据混乱的情况。

宏观模拟实现:

当str2在绿色位置的时候就是不会发生内存地址重叠的情况,该情况无论是从头往前走还是从尾后往走都不会发生冲的情况,所以str2在红色区域的时候,就是需要从后往前走的情况,而黄色区域的是需要从前往后走的情况。

从前往后走:

从后往前走:

memset 函数的使用

memset 的介绍

void * memset (void * ptr , int value , size_t num );

功能:

memset函数是用来设置内存块的内容的,将内存中指定长度的空间设置为特定的内容。

memset的使用需要包含

参数:

ptr:指针,指向要设置的内存空间,也就是存放了要设置的内存空间的起始地址。

value:要设置的值,函数将会把value值转换成unsigned char的数据进行设置的。也就是以字节为单位来设置内存块的。

num:要设置的内存长度,单位是字节。

返回值:返回的是要设置的内存空间的起始地址。

函数使用

int main() { int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 }; memset(arr1, 0x12, 4); //12121212 for (int i = 0; i < 10; i++) { printf("%d ", arr1[i]); } return 0; }

可以看出该函数是针对的是一个字节为的进行一个一个的修改内容,四个字节每一个字节位置都附上十六进制的0x12 ,0x12121212 的对应的十进制数量就是3 0317 4162。

memcmp 函数的使用

memcmp 的介绍

memcmp 就是cmp针对一个字节位的比较,功能还是与其他的cmp 都是一样的。

int memcmp ( const void * ptr1 , const void * ptr2 , size_t num );

功能:

比较指定的两块内存块的内容,比较从ptr 1ptr2指针指向的位置开始,向后的num个字节

memcmp的使用需要包含

参数:

ptr1:指针,指向一块待比较的内存块

ptr2:指针,指向另外一块待比较的内存块

num:指定的比较长度,单位是字节

函数使用

int main() { int arr1[10] = { 1,2,3,4,5 }; int arr2[10] = { 1,2,3,4,4 }; printf("%d", memcmp(arr1, arr2, 16)); return 0; }

int main() { int arr1[10] = { 1,2,3,4,5 }; int arr2[10] = { 1,2,3,4,4 }; printf("%d", memcmp(arr1, arr2, 20)); return 0; }

当然string.h 的介绍也不仅如此,做一个简单的介绍,我的介绍结束感谢观看。

悠仁さん

http://www.jsqmd.com/news/801622/

相关文章:

  • Source Han Serif CN技术深度解析:企业级字体架构与性能优化实战指南
  • Archon:为AI智能体注入“纪律”的认知内核框架解析
  • 从临床试验到互联网AB测试:边缘结构模型(MSM)如何解决‘时依性混杂’这个老大难问题
  • SourceTree实战指南:精准回滚至任意历史提交节点
  • 5分钟掌握uBlock Origin:让浏览器告别广告与追踪
  • 量子计算VQE算法在氢分子模拟中的实践与优化
  • 别只装客户端!RoboMaster机甲大师实战前必做的3项电脑环境检查(驱动、网络、USB口)
  • 第七部分-容器安全与监控——34. 容器监控
  • 别再只复制粘贴了!深入理解阿里云IoT设备三元组:ProductKey、DeviceName、DeviceSecret的安全与管理实践
  • 别再怕触电了!手把手教你安全调试220V阻容降压电路(附实物接线图)
  • 告别串口助手!用STM32F103+DHT11做个OLED屏显温湿度计,附电路与程序
  • Android Studio可视化布局神器:ConstraintLayout Barrier的拖拽式实战教程
  • 基于FastAPI逆向封装Qwen官方接口,实现本地化AI对话API服务
  • SSRS报表中数据合并的艺术
  • 长期使用Taotoken聚合API的稳定性与可靠性观察
  • 淘金币自动化脚本:解放双手的终极指南
  • 在MATLAB与Unreal Engine中搭建自动驾驶高保真仿真环境
  • WarcraftHelper:如何让经典魔兽争霸3在现代系统上流畅运行?
  • Windows 11安卓子系统完整指南:让你的电脑秒变手机应用中心
  • 明日方舟基建自动化管理终极指南:如何用Arknights-Mower彻底解放双手
  • 从MATLAB报错‘错误使用open(第136行)’到函数命名冲突的深度排查
  • C++中vector与string的关键应用及区别解析
  • 1.Python中ORM基础启动连接步骤
  • Windows密码忘了怎么办?一分钟看懂Windows密码底层机制:无需重装系统也能无痕找回登录密码
  • 告别ImageNet!用CLIP+Prompt工程,5分钟搞定你的第一个零样本图像分类器
  • 2026花洒品牌排行榜推荐:口碑好高性价比国产花洒选购指南 - 博客湾
  • 终极免费工具:WindowResizer让你完全掌控Windows窗口大小
  • XUnity.AutoTranslator:Unity游戏实时本地化引擎的技术架构与实践
  • 厌氧发酵罐主流供应商硬核横评:佳德精密 vs 有道生工,谁才是你的“天选”方案? - 品牌推荐大师1
  • 【LLC】逻辑链路控制:数据链路层的“统一翻译官”与异构网络互联的幕后功臣