本文主要介绍一些常见的字符和字符串函数及其模拟实现

所需要的头文件 #include<string.h>

目录

1、求字符串长度 strlen

1.1模拟实现 strlen(三种方法)

2、长度不受限制的字符串函数

2.1 字符串复制 strcpy

2.1.1 模拟实现 strcpy

2.2 字符串连接 strcat

2.2.1 模拟实现 strcat

2.3 字符串比较 strcmp

2.3.1 模拟实现 strcmp

3、长度受限制的字符串函数(推荐使用)

3.1 指定长度的字符串复制 strncpy

3.1.1 模拟实现 strncpy

3.2 指定长度的字符串连接 strncat

3.2.1 模拟实现 strncat

3.3 指定长度的字符串比较 strncmp

4、字符串查找函数

4.1  字符串查找 strstr

4.1.1 模拟实现 strstr

4.2 字符串分割 strtok

5、错误信息报告 strerror

6、字符分类函数

7、内存操作函数

7.1 内存拷贝 memcpy

7.1.1 模拟实现 memcpy

7.2 内存区域复制 memmove

7.2.1 模拟实现 memmove

7.3 按字节比较 memcmp

7.4 内存设置函数 memset


1、求字符串长度 strlen

size_t strlen ( const char * str );
功能介绍:求字符串长度(string length)
注意事项:字符串以'\0'作为结束的标志,strlen函数返回的是字符串中'\0'前出现的字符个数(不包含'\0'),且传参的字符串必须以'\0'结束。
注意函数的返回值为size_t (无符号的)。

1.1模拟实现 strlen(三种方法)

//1.计数器方法
size_t my_strlen(const char* str)
{assert(str);   //不能为空指针int count = 0;while (*str != '\0'){sum++;str++;}return count;
}//2.指针-指针
size_t my_strlen(char* str)
{assert(str);char* p = str;while (*p != '\0'){p++;}return p-str;
}//3.递归的方式
size_t my_strlen(char* str)
{assert(str);if (*str != '\0'){return 1 + my_strlen(str+1);}else{return 0;}
}//主函数
int main()
{char arr[] = "abcdef";size_t ret = my_strlen(arr);  //unsigned int = size_tprintf("%u\n", ret);return 0;
}

2、长度不受限制的字符串函数

2.1 字符串复制 strcpy

char * strcpy ( char * destination, const char * source );
功能介绍:字符串复制(string copy)把含有'\0'结束符的字符串复制到另一个地址空间。
注意事项:src和dest所指内存区域不可以重叠,且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针。 源字符串必须以 '\0' 结束,会将源字符串中的 '\0' 拷贝到目标空间。
目标空间必须足够大且可变,以确保能存放源字符串。

2.1.1 模拟实现 strcpy

void my_strcpy(char* dest, char* src)
{assert(dest && src);  //不能为空指针char* ret = dest;while (*dest++ = *src++);
}int main()
{char arr1[] = "abcdef";char arr2[20] = { 0 };my_strcpy(arr2, arr1);printf("%s\n", arr2);return 0;
}

2.2 字符串连接 strcat

char * strcat ( char * destination, const char * source );
功能介绍:字符串连接(string catenate)把两个char类型连接。
注意事项:把src所指向的字符串(包括“\0”)复制到dest所指向的字符串后面(删除*dest原来末尾的“\0”)。
要保证*dest足够长,以容纳被复制进来的*src。*src中原有的字符不变。返回指向dest的指针。
src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
源字符串必须以 '\0' 结束。目标空间必须有足够大且可变,能容纳下源字符串的内容。

2.2.1 模拟实现 strcat

void my_strcat(char* dest, const char* src)
{assert(dest && src);char* ret = dest;//1.找到目标空间的末尾\0while (*dest != '\0'){dest++;}//2.拷贝字符串while (*dest++ = *src++);
}int main()
{char arr1[20] = "hello ";my_strcat(arr1, "world");printf("%s\n", arr1);return 0;
}

2.3 字符串比较 strcmp

int strcmp ( const char * str1, const char * str2 );
功能介绍:字符串比较(string compare)
当s1<s2时,返回为数;当s1=s2时,返回值= 0;当s1>s2时,返回数。
即:两个字符串自左向右逐个字符相比(按ASCII值大小相比较),直到出现不同的字符或遇'\0'为止。如:1."A"<"B"          2."A"<"AB"          3."compare"<"computer"
注意事项:该函数只能比较字符串,即可用于比较两个字符串常量,或比较数组和字符串常量,不能比较数字等其他形式的参数。

2.3.1 模拟实现 strcmp

int my_strcmp(const char* str1, const char* str2)
{assert(str1 && str2);while (*str1 == *str2){if (*str1 == '\0')return 0;   //相等str1++;str2++;}//不相等if (*str1 > *str2)return 1;elsereturn -1;//简便写法:return (*str1 > *str2);
}int main()
{char arr1[20] = "zhangsan";char arr2[20] = "zhangsanfeng";int ret = my_strcmp(arr1, arr2);if (ret < 0)printf("<\n");else if (ret == 0)printf("==\n");elseprintf(">\n");return 0;
}

3、长度受限制的字符串函数(推荐使用)

3.1 指定长度的字符串复制 strncpy

char * strncpy ( char * destination, const char * source, size_t num );
功能介绍:把src所指向的字符串中以src地址开始的前n个字节复制到dest所指的数组中,并返回被复制后的dest注意事项:
1)source串长度<=dest串长度(这里的串长度包含串尾NULL字符)
2)source串长度>dest串长度
    综上,一般情况下,使用strncpy时,建议将n置为dest串长度(除非你将多个source串都复制到dest数组,并且从dest尾部反向操作),复制完毕后,为保险起见,将dest串最后一字符置NULL,避免发生在第2)种情况下的输出乱码问题。当然,无论是strcpy还是strncpy,保证dest串容量(能容纳下source串)才是最重要的。

3.1.1 模拟实现 strncpy

#include<stdio.h>
#include<assert.h>
void my_strncpy(char* dest, char* src, size_t n)
{assert(dest && src);  //不能为空指针int i = 0;char* ret = dest;while (*dest){*dest++ = *src++;i++;if (i == n)break;};
}int main()
{char arr1[] = "abcdef";char arr2[] = "hello world";my_strncpy(arr2, arr1, 5);printf("%s\n", arr2);return 0;
}

运行截图: 

3.2 指定长度的字符串连接 strncat

char * strncat ( char * destination, const char * source, size_t num );
功能介绍:把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止。
注意事项:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。strncat将会从字符串src的开头拷贝n个字符到dest字符串尾部,dest要有足够的空间来容纳要拷贝的字符串。如果n大于字符串src的长度,那么仅将src指向的字符串内容追加到dest的尾部。
strncat会将dest字符串最后的'\0'覆盖掉,字符追加完成后,再追加'\0'。

3.2.1 模拟实现 strncat

void my_strncat(char* dest, const char* src, size_t n)
{assert(dest && src);char* ret = dest;int i = 0;//1.找到目标空间的末尾\0while (*dest != '\0'){dest++;}//2.拷贝字符串while (*dest++ = *src++){i++;if (i == n)break;}
}int main()
{char arr1[20] = "hello ";my_strncat(arr1, "world", 3);printf("%s\n", arr1);return 0;
}

运行截图:

3.3 指定长度的字符串比较 strncmp

int strncmp ( const char * str1, const char * str2, size_t num );
功能介绍: str1 和 str2 进行比较,最多比较前 n 个字节。
当s1<s2时,返回为数;当s1=s2时,返回值= 0;当s1>s2时,返回数。

4、字符串查找函数

4.1  字符串查找 strstr

const char * strstr ( const char * str1, const char * str2 );char * strstr (       char * str1, const char * str2 );
功能介绍:用于判断字符串str2是否是str1的子串。
如果是,则该函数返回str1字符串从str2第一次出现的位置开始到 str1结尾的字符串;
否则,返回NULL。

4.1.1 模拟实现 strstr

思路:

//1.暴力求解
char* my_strstr(const char* str1, const char* str2)
{assert(str1 && str2);const char* s1 = str1; //待匹配原串的指针const char* s2 = str2; //待匹配子串的指针const char* p = str1;  //匹配位置开始的指针while (*p){s1 = p;s2 = str2;while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2){s1++;s2++;}if (*s2 == '\0'){return (char*)p;}p++;}return NULL;
}int main()
{//char arr1[] = "hins@qq.com";//char arr2[] = "qq";char arr1[] = "abbbcdef";char arr2[] = "bbc";char* ret = my_strstr(arr1, arr2);if (ret == NULL){printf("子串不存在\n");}else{printf("%s\n", ret);}return 0;
}
//2、KMP匹配算法 略

4.2 字符串分割 strtok

char * strtok ( char * str, const char * delimiters );
功能介绍:分解字符串(string token)为一组字符串。s为要分解的字符串,delim为分隔符字符(如果传入字符串,则传入的字符串中每个字符均为分割符)。首次调用时,s指向要分解的字符串,之后再次调用要把s设成NULL。strtok用来将字符串分割成一个个片段。参数s指向欲分割的字符串,参数delim则为分割字符串中包含的所有字符。当strtok在参数s的字符串中发现参数delim中包含的分割字符时,则会将该字符改为\0 字符。在第一次调用时,strtok必需给予参数s字符串,往后的调用则将参数s设置成NULL。每次调用成功则返回指向被分割出片段的指针。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
注意事项:strtok函数会破坏被分解字符串的完整,调用前和调用后的s已经不一样了.所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。
//使用方法
int main()
{const char* sep = "@.";char email[] = "hins@qq.com.net";//char* ret = my_strstr(arr1, arr2);char cp[30] = { 0 };strcpy(cp, email);char* ret = NULL;for (ret = strtok(cp, sep); ret != NULL; ret = strtok(NULL, sep)){printf("%s\n", ret);}//下面的版本太啰嗦//char* ret = strtok(cp, sep);//printf("%s\n", ret);//ret = strtok(NULL, sep);//printf("%s\n", ret);//ret = strtok(NULL, sep);//printf("%s\n", ret);//ret = strtok(NULL, sep);//printf("%s\n", ret);return 0;
}

运行截图:

5、错误信息报告 strerror

char * strerror ( int errnum );
通过标准错误的标号,获得错误的描述字符串 ,将单纯的错误标号转为字符串描述,方便用户查找错误。必须包含的头文件:#include <errno.h>    #include <string.h>
返回错误码,所对应的错误信息。
//示例代码
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main ()
{FILE *fp;fp = fopen("file.txt","r");if( fp == NULL ) {printf("Error: %s\n", strerror(errno));}return(0);
}

运行截图:

示例错误码: 

6、字符分类函数

需要头文件 #include<ctype.h>

函数 如果他的参数符合下列条件就返回真
iscntrl 任何控制字符
isspace 空白字符:空格‘ ’,换页‘\f’,换行'\n',回车‘\r’,制表符'\t'或者垂直制表符'\v'
isdigit 十进制数字 0~9
isxdigit 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F
islower 小写字母a~z
isupper 大写字母A~Z
isalpha 字母a~z或A~Z
isalnum 字母或者数字,a~z,A~Z,0~9
ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)
isgraph 任何图形字符
isprint

任何可打印字符,包括图形字符和空白字符

字符转换函数
tolower 字符转小写
toupper 字符转大写

7、内存操作函数

7.1 内存拷贝 memcpy

void * memcpy ( void * destination, const void * source, size_t num );
功能介绍:内存拷贝(memory copy)从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中。Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination.
注意事项:
1.source和destin所指的内存区域可能重叠,但是如果source和destin所指的内存区域重叠,那么这个函数并不能够确保source所在重叠区域在拷贝之前不被覆盖。而使用memmove可以用来处理重叠区域。函数返回指向destin的指针。
2.如果目标数组destin本身已有数据,执行memcpy()后,将覆盖原有数据(最多覆盖n)。如果要追加数据,则每次执行memcpy后,要将目标数组地址增加到你要追加数据的地址。
3. void*又称泛型指针,什么类型都可以接收。

注意:source和destin都不一定是数组,任意的可读写的空间均可。

7.1.1 模拟实现 memcpy

void* my_memcpy(void* dest, const void* src, size_t num)
{assert(dest && src);void* ret = dest;while (num--) {*(char*)dest = *(char*)src;   //一个字节一个字节的拷贝比较保险dest = (char*)dest + 1;src = (char*)src + 1;}return ret;
}
int main()
{int arr1[] = { 0,1,2,3,4,5,6,7 };int arr2[10] = { 0 };my_memcpy(arr2, arr1, 28);return 0;
}

7.2 内存区域复制 memmove

void * memmove ( void * destination, const void * source, size_t num );
功能介绍:由src所指内存区域复制num个字节到dest所指内存区域memmove用于拷贝字节,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,但复制后源内容会被更改。但是当目标区域与源区域没有重叠则和memcpy函数功能相同。
注意事项:和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。

原理分析:

7.2.1 模拟实现 memmove

void* my_memmove(void* dest, const void* src, size_t num)
{assert(dest && src);void* ret = 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 ret;
}
int main()
{int arr1[] = { 1,2,3,4,5,6,7 ,8,9,10 };my_memmove(arr1+2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}return 0;
}

运行截图:

7.3 按字节比较 memcmp

int memcmp ( const void * ptr1, const void * ptr2, size_t num );
功能介绍:字节比较函数(memory compare)把存储区 str1 和存储区 str2 的前 n 个字节进行比较。该函数是按字节比较的,位于string.h。
  • 如果返回值 < 0,则表示 str1 小于 str2。

  • 如果返回值 > 0,则表示 str2 小于 str1。

  • 如果返回值 = 0,则表示 str1 等于 str2

7.4 内存设置函数 memset

void * memset ( void * ptr, int value, size_t num );
功能介绍:内存设置(memory set)是将某一块内存中的内容全部设置为指定的值,这个函数通常为新申请的内存做初始化工作。(以字节为单位初始化)

OK,以上就是本期知识点“常见字符和字符串函数及其模拟实现”的知识啦~~,感谢友友们的阅读。后续还会继续更新,欢迎持续关注哟~

【C语言详解】——常见字符和字符串函数及其模拟实现相关推荐

  1. smali语言详解之一般/构造方法(函数)的声明与返回值关键字

    smali语言详解之一般/构造方法(函数)的声明与返回值关键字 一. smali语言的方法声明格式 .method与.end method成对出现,类似于java中的花括号 1.1.非静态的一般方法 ...

  2. C语言 详解如何编写闪烁显示字符串的函数

    如果要实现指定字符串在标准输出流(一般为显示器)上闪烁,可以定义如下函数: void bput(const char*s,int appe,int disa,int repe) 字符串s出现appe秒 ...

  3. c语言fputc输入字符串,C语言fgetc和fputc函数用法详解(以字符形式读写文件)

    C语言fgetc和fputc函数用法详解(以字符形式读写文件),文件,字符,指针,函数,字节 C语言fgetc和fputc函数用法详解(以字符形式读写文件) 易采站长站,站长之家为您整理了C语言fge ...

  4. c语言 字符串 strncpy,详解c语言中的 strcpy和strncpy字符串函数使用

    详解c语言中的 strcpy和strncpy字符串函数使用 strcpy 和strcnpy函数--字符串复制函数. 1.strcpy函数 函数原型:char *strcpy(char *dst,cha ...

  5. c语言多组数据判断回文字符串,详解判断回文字符串跟回文数算法的C语言代码...

    详解判断回文字符串和回文数算法的C语言代码! 一.判断一个字符串是否为回文字符串 #include #include #include //包含strlen #define YES 1 #define ...

  6. c++指针详解_c语言详解sizeof

    一.sizeof的概念 sizeof是C语言的一种单目操作符,如C语言的其他操作符++.--等. 它并不是函数. sizeof操作符以字节形式给出了其操作数的存储大小. 操作数可以是一个表达式或括在括 ...

  7. HTML超文本标记语言详解

    HTML超文本标记语言详解 Hyper Text Markup Language(超文本标记语言) 现在的开发版本一般为HTML5+CSS3 W3C标准:World Wide Web Consorti ...

  8. Drools 规则语言详解(上)

    http://www.blogjava.net/guangnian0412/archive/2006/06/09/51574.html http://www.blogjava.net/guangnia ...

  9. 邻接矩阵用c语言,邻接矩阵无向图(一)之 C语言详解

    本章介绍邻接矩阵无向图.在"图的理论基础"中已经对图进行了理论介绍,这里就不再对图的概念进行重复说明了.和以往一样,本文会先给出C语言的实现:后续再分别给出C++和Java版本的实 ...

最新文章

  1. 12月26日二周二次【Python基础语法】
  2. 提高代码质量:如何编写函数
  3. 加州大学新算法:让智能汽车更精准检测行人
  4. 傅立叶变换物理意义解析进阶
  5. Jupyterlab 插件安装后侧边栏找不到的解决
  6. c++和python的区别、javascript_python和c++的区别
  7. 基于WASM的无侵入式全链路A/B Test实践
  8. 一个好用的 SAP UI5 本地打包(build)工具,自动生成Component-preload.js
  9. C/C++新建注册表项实例
  10. 解决hive交互模式退格键乱码
  11. 从零开始搭建系统2.4——Jenkins安装及配置
  12. 伴随矩阵,可逆矩阵相关思路分析之一
  13. 中国现代远程与继续教育网 统考 大学英语(B)考试大纲
  14. java导入文件太大 处理速度慢_java – 处理大文件时IntelliJ非常慢
  15. 好的技术领导与差的技术领导,千万不要对号入座,你会死的很惨!
  16. windowns 程序图标变白色
  17. linux kvm切换器,PS2系列KVM切换器
  18. 女人心疼男人的10种方式
  19. Aspect Ratio Fitter 重温总结(多图)
  20. Android录像时添加时间水印

热门文章

  1. 服务器应用程序不可用,错误:0x80070005拒绝访问。
  2. 刷脸支付代理可靠吗?挣钱吗?
  3. 对话机器人的个性设计指南
  4. iis怎么切换网站php版本,iis怎么支持php多版本
  5. 有人到农村收“废旧手机”,用手机换盆,收来做什么?
  6. Windows下启动rocketMq
  7. ArcEngine C# GIS开发入门作业 (二)Ex03——基本应用程序生成,右击菜单实现:显示、移除和打开属性表功能
  8. 【Windows】Redis集群部署
  9. Rancher被Gartner评为“四大最酷云基础设施供应商”之一!
  10. ADODB类库——数据库管家