【C语言进阶】字符串函数模拟实现
- 求字符串长度
strlen
size_t strlen(const char*string);
头文件:<string.h>
功能:
计算字符串的长度,遇到'\0'便停止,统计'\0'之前字符的个数。
模拟实现:
//创建临时变量实现
int my_strlen(char* arr)
{int count = 0;while (*arr){arr++;count++;}return count;
}//指针-指针实现
int my_strlen(char* arr)
{char* str = arr;while (*str){str++;}return str - arr;
}//递归实现
int my_strlen(char* arr)
{if (*arr != '\0')return 1 + my_strlen(++arr);elsereturn 0;
}int main()
{char arr[] = "abcdef";int ret = my_strlen(arr);printf("%d\n", ret);return 0;
}
int main()
{char arr[] = "abcdef";int ret = my_strlen(arr);printf("%d\n", ret);return 0;
}
- 长度不受限制的字符串函数
strcpy
char*strcpy(char*strDestination,const char*strSource);
头文件:<string.h>
功能:将strSource对应的字符串(源字符串)复制到strDestination对应的地址空间(目标空间)中
注意:
目标空间必须足够大
目标空间必须可以被修改
源字符串必须以 '\0' 结束
会将源字符串中的 '\0' 拷贝到目标空间
内存监视:会发现'\0'确实也拷贝到了新的数组中
模拟实现:
char* my_strcpy(char* arr1, char* arr2)
{char* str = arr1;while (*arr1++ = *arr2++){;}return str;
}int main()
{char arr1[20] = "xxxxxxxxxx";char arr2[] = "abcd";char* str=my_strcpy(arr1, arr2);printf("%s\n", str);return 0;
}
strcat
char* strcat(char* strDestination,const char* strSource);
头文件:<string.h>
功能:将strSource对应字符串(源字符串)连接到strDestination所指向字符串尾部
注意:
目标空间必须足够大
目标空间必须可变
连接会从目标空间的'\0'开始
源字符串必须以'\0'结束
源字符串的‘\0’也会被复制到目标空间
然而如果字符串自己给自己追加就会出现问题
模拟实现:
#include<assert.h>
char* my_strcat(char* arr1, const char* arr2)
{assert(arr1 && arr2);char* str1 = arr1;while (*arr1){arr1++;}while (*arr1++ = *arr2++){;}return str1;
}int main()
{char arr1[20] = "xxxxxx";char arr2[4] = "def";char* str = my_strcat(arr1, arr2);printf("%s", str);return 0;
}
strcmp
int strcmp(const char*string1, const char*string2);
头文件:<string.h>
功能:比较字符串的大小(一个个字符依次比较)
string1>string2 |
返回大于0的数字 |
string1==string2 |
返回0 |
string1<string2 |
返回小于0的数字 |
而在VS这种编译器下,
string1>string2 |
返回1 |
string1==string2 |
返回0 |
string1<string2 |
返回-1 |
模拟实现:
int my_strcmp(const char* arr1, const char* arr2)
{assert(arr1&&arr2);if (*arr1 == *arr2 && *arr1 == '\0')return 0;while (*arr1 == *arr2 ){arr1++;arr2++;}if(*arr1>*arr2)return 1;else if(*arr1<*arr2)return -1;//VS上的写法//return *arr1 - *arr2;//其他编译器上的写法
}int main()
{char arr1[] = "abcdef";char arr2[] = "abcq";int ret = my_strcmp(arr1, arr2);if (ret == 0)printf("arr1==arr2.\n");else if (ret > 0)printf("arr1>arr2.\n");elseprintf("arr1<arr2.\n");return 0;
}
- 长度受限制的字符串函数
strncpy
char*strncpy(char*strDest,constchar*strSource,size_tcount);
头文件:<string.h>
功能:
从源字符串中拷贝count个字符到目标空间
如果源字符串的长度小于count,则拷贝完后在目标的后面补'\0',直到count个为止
模拟实现:
char* my_strncpy(char* arr1, char* arr2, int num)
{assert(arr1 && arr2);char* dst=arr1;while (*arr2!='\0' && num>0){*arr1++ = *arr2++;num--;}while (num){*arr1 = '\0';arr1++;num--;}return dst;
}
int main()
{char arr1[] = "xxxxxxxx";char arr2[] = "abcd";char* str = strncpy(arr1, arr2, 6);printf("%s\n", str);return 0;
}
strncat
char* strncat(char*strDest,constchar*strSource,size_tcount);
头文件:<string.h>
功能:将源字符串的count个字符追加到目标空间对应字符串末尾(从'\0'开始)
若追加元素个数小于源字符串的长度,会在追加count个字符之后再加上一个'\0'
模拟实现:
char* my_strncat(char* arr1, const char* arr2, int num)
{assert(arr1 && arr2);char* str = arr1;while (*arr1 != '\0'){arr1++;}while (*arr2!='\0'&&num>0){*arr1++ = *arr2++;num--;}if(num==0)*arr1='\0';while (num--){*arr1++ = '\0';}return str;
}int main()
{char arr1[20] = "xxxxxxxxx";char arr2[] = "abdes";char* dst = my_strncat(arr1, arr2, 6);printf("%s\n", dst);return 0;
}
strncmp
int strncmp(constchar*string1,constchar*string2,size_tcount);
头文件:<sting.h>
功能:比较两个字符串count个字符的大小(一个个字符依次进行比较)
模拟实现:
int my_strncmp(const char* arr1, const char* arr2, int num)
{assert(arr1 && arr2);while (*arr1 == *arr2&&num>0){if (*arr1 == '\0')return 0;//if (num == 0)// return *arr1 - *arr2;arr1++;arr2++;num--;}//情况1:*arr1!=*arr2跳出循环if (num != 0)return *arr1 - *arr2;//情况2:由于num==0跳出循环else if (num == 0)return 0;
}int main()
{char arr1[] = "abcdptr";char arr2[]="abcdeh";int ret = my_strncmp(arr1,arr2,5);if (ret > 0)printf("arr1>arr2\n");else if (ret == 0)printf("arr1==arr2\n");elseprintf("arr1<arr2\n");return 0;
}
- 字符串查找
strstr
char*strstr(constchar*str1,constchar*str2);
头文件:
功能:在str1对应字符串中寻找str2对应字符串是否存在,若存在则返回str2在str1中对应位置的起始位置,若不存在则返回NULL
模拟实现:
char* my_strstr(const char* arr1, const char* arr2)
{char* pc1 = (char*)arr1, *pc2 = (char*)arr2;if (*arr2 == '\0')return pc1;while (*arr1 != '\0'){while (*arr1 == *arr2){arr1++;arr2++;if (*arr2 == '\0'){return pc1;}}arr2 = pc2;pc1++;arr1 = pc1;}return NULL;
}
int main()
{char arr1[] = "abbcdef";char arr2[] = "bcde";char* ret=my_strstr(arr1, arr2);if (ret != NULL)printf("%s\n", ret);elseprintf("no find!\n");return 0;
}
strtok
char*strtok(char*strToken,constchar*strDelimit);
头文件:<string.h>
功能:分割字符串,其中strDwlimit是存放分隔符的字符串;若找到其中的分隔符则将分隔符改为'\0'
返回值:1.字符串strToken不为空,如果找到对应的分隔符,则返回分隔符之前字符串的首地址(指向 标记开头的指针);如果到达字符串末尾'\0'则返回NULL;
2.若字符串strToken为空,则返回空指针NULL
注意:第一次传参时第一个字符指针传递字符串的地址,但在第二次及之后传参时,传递NULL,因为在找到分隔符后函数会记录并标记相关地址,以便后续查找。
- 错误信息报告
strerror
char*strerror(interrnum);
头文件:<string.h>
功能:打印错误信息
补充:C语言的库函数在运行时,如果发生错误,就会将错误码存在一个变量中,这个变量是:errno 错误码是一些数字:1 2 3 4 5 ,而我们为了明白错误,需要将错误码翻译成错误信息。使用strerroe函数就可以将错误信息的地址返回,从而打印出错误信息。
同时有一个和strerror类似的也是打印错误信息的函数perror
perror=printf+error
void perror(const char *string);
头文件:<stdio.h>or<stdlib.h>
功能:直接打印错误信息,但在打印错误信息之前会打印自定义的信息。
strerror与perror用法比较:
int main()
{//打开文件FILE* pf = fopen("test.txt", "r");if (pf == NULL)//判断是否读取成功{printf("%s\n", strerror(errno));//使用strerror函数要将错误码作为参数传参perror("fopen");//使用perror函数则直接传递自定义信息即可}//读文件//关闭文件fclose(pf);pf = NULL;return 0;
}
- 字符操作
字符分类函数
字符转换函数
int tolower(int c);//大写变小写
int toupper(int c);//小写变大写
来看一个题目:
如何将一串字符串都变为小写?
如何将一串字符串都变为大写?
- 内存操作函数
因此字符串函数是只针对字符串而言的,不具有普遍性,因此引出针对所有类型而言的内存函数
memcpy
void*memcpy(void*dest,constvoid*src,size_tcount);
头文件:<string.h>
功能:实现任意类型数据的拷贝,以src指向的地址为起点,将连续的n个字节数据,复制到以dest指向的地址为起点的内存中。
返回值:目标空间起始地址
模拟实现:
void* my_memcpy(void* dest, const void* src, size_t count)
{assert(dest && src);void* ret = dest;//写法1:通过char*型的指针分别接收源地址和目标地址,再进行操作char* dst = (char*)dest;char* str = (char*)src;while (count){*dst = *str;dst++;str++;count--;}//写法2:通过直接强制类型转换进行操作//while (count)//{// *(char*)dest = *(char*)src;// dest = (char*)dest + 1;// src = (char*)src + 1;// //(char*)dest++;// //这种强制类型转换只是临时的,在转换之后便会复原// //因此是错误的// count--;//}return ret;
}
int main()
{int arr1[10] = { 1,2,3,4,5,6,7 };int arr2[10] = { 0 };void* ret = my_memcpy(arr2, arr1, 16);for (int i = 0; i < 4; i++){printf("%d ", arr2[i]);}return 0;
}
这种写法很可能在某些情况下出现问题:
当src与dest所指向的内容有所重叠的时候,如果还是按照从前向后的顺序可能拷贝不成功
eg:将arr1数组中的1,2,3,4,5拷贝至3,4,5,6,7时
出现这种情况的原因是在从前向后拷贝时会把还未拷贝的数据覆盖,从而导致无法达到预期效果
我们来分析一下dest与src位置与拷贝顺序的关系,会发现可以分为三种情况:
当dest在src之前时,由前至后拷贝
当dest在src所指向要拷贝内容的起始位置与终端位置之间时,由后至前拷贝
当dest在src所指向要拷贝内容的末端位置之后时,由前至后拷贝与由后至前拷贝都是可行的
由此我们引出memmove函数
memmove
void*memmove(void*dest,constvoid*src,size_tcount);
头文件:<string.h>
功能:拷贝src在内存对应内容的count个字节到dest中,可以实现重叠内存的拷贝。
模拟实现:由于上面提到三种情况中,第二种和第三种都可以用由后->前的思路来实现,为了简便我们分为dest<src和dest>=src两种情况考虑
void* my_memcpy(void* dest, const void* src, size_t count)
{assert(dest && src);void* ret = dest;//由前->后if (dest < src){while (count){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;count--;}}//由后->前else{while (count--){*((char*)dest + count) = *((char*)src + count);}//最后因此count为1判断为真,之后--变为0进入循环,第一个字节也有拷贝过去}return ret;
}
int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };void* ret = my_memcpy(arr1 + 2, arr1, 20);for (int i = 2; i < 7; i++){printf("%d ", arr1[i]);}return 0;
}
但很多编译器上也将memcpy设置为可重叠拷贝的函数,使用时可以选择都用memmove函数,也可以选择在重叠时用memmove,不重叠用memcpy。
memset
void* memset(void* dest,int c,size_t count);
头文件:<string.h>or<memory.h>
功能:内存设置函数,以字节为单位来设置内存中的数据,将dest在内存中对应count个字节的内容改为c
使用:
int main()
{char arr[] = "hello world";memset(arr, 'x', 5);printf("%s\n", arr);memset(arr+6, 'y', 5);printf("%s\n", arr);//int arr[10] = { 0 };//memset(arr, 0, 40);//一般初始化为0如果初始化内容超过一字节在使用时可能会出现问题return 0;
}
memcmp
int memcmp(const void*buf1,const void*buf2,size_t count);
头文件:<string.h>or<memory.h>
功能:比较buf1与buf2内存块的count个字节的内容
前两个参数就是要比较的内存块的地址;
第三个参数就是要比较的字节数。
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 1,2,3,0,0 };int ret = memcmp(arr1, arr2, 12);printf("%d\n", ret);return 0;
}
//前12个字节的内容都一样,所以返回0
注意:这里比较的以字节为单位的,所以是要牵扯到大小端存储的
不太了解大小端的宝宝们可以看看这篇文章http://t.csdn.cn/5QaTY
以arr1数组为例:
若是小端存储则:
若是大端存储则:
12字节无论是大端还是小端都是相等的
若是访问11字节内容:
小端存储:
大端存储:
【C语言进阶】字符串函数模拟实现相关推荐
- 【C语言】字符串函数详解
hello~~,我是~小鹿 ,这是我的第一篇博客,没有循序渐进从基础开始写,只是最近在学习这里就写了,比较随心吧.希望这一篇博客能够给你带来帮助,之后也会继续写的,只是可能没有循序渐进,会比较杂七杂八 ...
- C语言常用字符串函数strlen、strcpy、strcat、strcmp、strchr
C语言常用字符串函数,求串长strlen(char *s).串复制strcpy(char *s1,char *s2).串连接strcat(char *s1,char *s2).串比较strcmp(ch ...
- C语言进阶——字符函数和字符串函数
作者:敲代码の流川枫 博客主页:流川枫的博客 专栏:C语言从入门到进阶 语录:Stay hungry stay foolish 工欲善其事必先利其器,给大家介绍一款超牛的斩获大厂offer利器--牛客 ...
- C语言常用字符串函数及模拟实现
字符串函数总结及模拟实现 1. 字符串函数总结
- C语言常用字符串函数——头文件 <string.h> 到底有什么?
1. strlen -- 求字符串长度 1.1 strlen 的声明与用处 strlen ,我们有一些英语基础的话不难通过字面意思来知道这个函数是干嘛用的,str 表 string ,字符串的意思,l ...
- C语言常用字符串函数详解
在C语言标准库里面,存在一个对字符串数组进行操作的函数的头文件为string.h. 常用的字符串函数有strlen,strcpy,strcat等等. 了解这些字符串函数是如何实现的可以有助于更好的使用 ...
- 超详细C语言的字符串函数讲解
字符串函数 前言 C语言中对字符和字符串的处理很是频繁,但是C语言本身是没有字符串类型的,字符串通常放在常量字符串中或者字符数组中.字符串常量 适用于那些对它不做修改的字符串函数 接下来本文就是对于介 ...
- 【C语言】字符串函数strtok 按照指定字符串分割
C语言字符串函数 strtok() 函数原型 char *strtok(char *str,const char *delimiters); 参数 str,待分割的字符串 delimiters,分隔符 ...
- c语言处理字符串函数的头文件,C语言字符处理函数 - 20131125的个人空间 - OSCHINA - 中文开源技术交流社区...
C语言提供了丰富的字符串处理函数, 大致可分为字符串的输入.输出.合并.修改.比较.转换.复制.搜索几类. 使用这些函数可大大减轻编程的负担.用于输入输出的字符串函数,在使用前应包含头文件" ...
最新文章
- php会员中心模板,会员中心模板
- 李彦宏候选中国工程院院士
- python contains_Python中有判断字符串包含(contains)子串的方法吗?
- Buffer Status Report(BSR)
- Java学习必不可少的网站,快收藏起来!
- 信息学奥赛一本通 1164:digit函数
- 数据库流行度9月排行榜:Oracle 的老骥伏枥和 MongoDB 逆风飞扬
- 字符串里面的单词反转
- ios12安装描述文件失败问题
- Could not open client transport with JDBC Uri: jdbc:hive2://slaver2:10000: java.net.ConnectException
- python日期运算_Python:日期计算器
- 新手小白想要成为软件测试工程师,必须要学会的这些基础知识!
- Okra框架(三) 搭建HTTP服务器
- matlab能画五维吗,进化算法之粒子群算法和Matlab实现(多维)
- html打印指定区域
- js判断是否为数字的几种方式
- Windows安装 hadoop 环境
- 微信小程序 Wxs篇
- pdf拆分成一页一个文件,详细步骤
- Oracle数据库查询被锁的表以及解锁表操作