文章目录
- 字符串函数
- strlen函数
- 模拟实现
- strcpy函数
- 模拟实现
- strcat函数
- 使用
- 模拟实现
- strcmp函数
- 使用
- 模拟实现
- strncpy函数
- 使用
- 模拟实现
- strstr函数
- 使用
- 模拟实现
- strtok函数
- 使用
- strerror函数
- 使用
- 内存函数
- memset函数
- 使用
- memcmp函数
- memcpy函数
- 使用
- 模拟实现
- memmove函数
- 使用
- 模拟实现
- 总结
字符串函数
strlen函数
size_t strlen ( const char * str );
返回值是size_t
头文件——#include<string.h>
计算字符串的长度
不包括\0
模拟实现
计数器
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{assert(str);size_t count = 0;while (*str != '\0'){count++;str++;}return count;
}
int main()
{char arr[] = { "abcdefg" };size_t n = my_strlen(arr);printf("%u\n", n);return 0;
}
指针-指针
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{assert(str);char* p = str;while (*p!='\0'){p++;}return p - str;
}int main()
{char arr[] = { "abcdefg" };size_t n = my_strlen(arr);printf("%u\n", n);return 0;
}
递归
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<assert.h>
size_t my_strlen(const char* str)
{assert(str);if (*str == '\0')return 0;elsereturn 1 + my_strlen(str+1);}
int main()
{char arr[] = { "abcdefg" };size_t n = my_strlen(arr);printf("%u\n", n);return 0;
}
strcpy函数
char * strcpy ( char * destination, const char * source );
dst是目标空间,src是要复制的内容
拷贝内容到指定对象中
要确保指定对象有足够大的空间
去容纳,否则可能会导致缓冲区溢出
目标空间必须可修改,不可以是常量字符串;
源字符串必须以\0结束
复制会把src指向的字符串包括\0复制过去
模拟实现
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{assert(dest && src);//确保不是野指针char* dest_ptr = dest;//初始化目标字符串的指针//遍历源字符串while (*src!='\0'){*dest_ptr++ = *src++;}//添加空终止字符*dest_ptr = '\0';return dest;
}int main()
{char src[] = "hahahaha";char dest[20];my_strcpy(dest, src);printf("%s\n", dest);return 0;
}
strcat函数
追加内容,连接两个字符串
会将src指向的字符串(不包括\0)复制过去
所以不能追加自己本身,会死循环
目标空间足够大
复制完后dest会自动添加’\0’;
使用
#include<stdio.h>
#include<string.h>
int main()
{char src[] = "hahahaha";char dest[20] = "lololo ";strcat(dest, src);printf("%s\n", dest);return 0;
}
模拟实现
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{assert(dest && src);char* dest_end = dest;while (*dest_end != '\0'){dest_end++;}while (*src){*dest_end++ = *src++;}*dest_end = '\0';return dest;
}
int main()
{char src[] = "hahahaha";char dest[20] = "yayaya ";my_strcat(dest, src);printf("%s\n", dest);return 0;
}
strcmp函数
int strcmp ( const char * str1, const char * str2 );
== 返回值==
比较字符串的大小
,逐个逐个比,比较的是ASCII值
使用
#include<stdio.h>
#include<string.h>
int main()
{char* p = "abc";char* q = "abd";int ret=strcmp(p,q);printf("%d", ret);return 0;
}
#include<string.h>
#include<assert.h>
int main()
{char* p = "abcf";char* q = "abc";int ret=strcmp(p,q);printf("%d", ret);return 0;
}
模拟实现
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char* s1, char* s2)
{assert(s1 && s2);while(*s1==*s2){if(*s1=='\0')return 0;s1++;s2++;}/*if (*s1 > *s2){return 1;}elsereturn -1;*/return *s1 - *s2;
}
int main()
{char* p = "abc";char* q = "abd";int ret=my_strcmp(p, q);/*printf("%d", ret);*/if (ret > 0){printf("p>q\n");}else if (ret == 0){printf("p=q\n");}else{printf("p<q\n");}return 0;}
strncpy函数
长度受限制
char * strncpy ( char * destination, const char * source, size_t num );
复制完成后dest目标字符串不会自动添加\0;需要手动确保dest以\0结尾
注意
如果src包含空字符,strcpy会停止复制,可能会导致目标字符串没有正确以空字符结尾
使用
#include<stdio.h>
#include<string.h>
int main()
{char src[] = "hahahaha";char dest[20];strncpy(dest, src, 5);dest[5] = '\0';printf("%s\n", dest);return 0;
}
模拟实现
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src,int n)
{assert(dest && src);char* dest_ptr = dest;while ((*src != '\0')&& n>0){*dest_ptr++ = *src++;--n;}if (*src == '\0'){while (n > 0){*dest_ptr++ = '\0';--n;}}*dest_ptr = '\0';return dest;
}int main()
{char src[] = "hahahaha";char dest[20];my_strcpy(dest, src,5);printf("%s\n", dest);return 0;
}
strstr函数
const char * strstr ( const char * str1, const char * str2 );
char * strstr ( char * str1, const char * str2 );
字符串查找
用于在字符串中搜索子字符串,并返回子字符串第一次出现的位置。如果找不到子字符串,则返回 false
使用
int main()
{const char* p = "abcdff";;char* ret=strstr(p, "bcd");if (ret != NULL){printf("存在");}elseprintf("不存在");return 0;
}
模拟实现
#include<stdio.h>
#include<assert.h>
char* my_strstr(const char* s1, const char*s2)//const确保s1.s2不动,刚开始的起始位置不变,要创建新的
{assert(s1 && s2);const char* str1 = s1;const char* str2 = s2;const char* p = s1;while (*p){str1= p;//p赋值给srt1,p就不动先str2 = s2;while (str1!='\0'&&str2!='\0' && *str1 == *str2){str1++;str2++;}if (*str2 == '\0'){return p;//返回搜索到的起始位置}p++;}
}
int main()
{char arr1[] = { "hellowuwen" };char arr2[] = { "lo" };char* ret = my_strstr(arr1, arr2);if (ret == NULL){printf("子串不存在\n");}else{printf("%s\n",ret);}return 0;
}
strtok函数
char * strtok ( char * str, const char * delimiters );
delim为分隔符字符(如果传入字符串,则传入的字符串中每个字符均为分割符)
函数返回值
:
成功:返回被分割出的字符串
失败:NULL
传入NULL,会在原来保存的位置继续往下找
使用
#include<stdio.h>
#include<string.h>
int main()
{const char* sep = ",.";char arr[] = "anfnvbj,nsndu.vns";char copy[30] = { 0 };strcpy(copy, arr);//char* ret = strtok(copy, sep);//if(ret!=NULL)//printf("%s\n", ret);//有记忆功能,就像static静态变量一样,出了函数变量不销毁,一直都在//ret=strtok(NULL, sep);//传NULL是为了继续往下找//printf("%s\n", ret);//ret = strtok(NULL, sep);//printf("%s\n", ret);//简化char* ret = NULL;for (ret = strtok(copy, sep); ret != NULL; ret = strtok(NULL, sep)){printf("%s\n", ret); }return 0;
}
strerror函数
char * strerror ( int errnum );
返回错误信息
必须包含的头文件include<error.h>
C语言的库函数,返回失败都会设置错误码
使用
举例,打开文件
FILE * fopen ( const char * filename, const char * mode );
一定要有#include<errno.h>
#include<errno.h>
int main()
{FILE* pf = fopen("test.text", "r");//同个文件夹里的相对路径if (pf == NULL){printf( "%s\n",strerror(errno));return 1;}else{}return 0;}
内存函数
memset函数
void * memset ( void * ptr, int value, size_t num );
用于将一段内存中的所有字节设置为特定的值。
初始化数组或者内存块
以字节为单位
来进行初始化
使用
#include<stdio.h>
#include<string.h>
int main()
{char arr[] = "hello wuwen";memset(arr + 6, 'd', 4);printf("%s\n", arr);
}
memcmp函数
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
size_t num是要比较的最大字节数
区别strcmp
:strcmp只作用与字符串,memcmp作用于任何类型
#include<stdio.h>
#include<string.h>
int main()
{int arr1[] = { 1,2,3,4,5 };int arr2[] = { 1,4,2 };int ret=memcmp(arr1, arr2, 12);if (ret < 0){printf("arr1<arr2");}else if (ret == 0){printf("arr1=arr2");}elseprintf("arr1>arr2");return 0;
}
memcpy函数
void * memcpy ( void * destination, const void * source, size_t num );
size_t num是要复制的字节数
使用
#include<stdio.h>
#include<string.h>
int main()
{int arr[] = { 1,2,3,4,5 };int dest[6] = { 0 };memcpy(dest, arr,20);for (int i = 0; i < 5; i++){printf("%d ", dest[i]);}return 0;
}
但是要在原数组里复制可行吗?
eg:memcpy(arr,arr+2,12),打印出来是3,4,5,4,5
也就是说在vs里对于内存覆盖的复制是可行的,但实际上呢
我们通过测试会发现,memcpy不能复制源和目标内存区域重叠的数组
模拟实现
#include<stdio.h>
#include<assert.h>
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;//dest是void*类型,不能直接解引用,不能直接+-;src=(char*)src+1;}return ret;//不能直接return dest,dest已经被++了//由于返回是目的的地址,所以要保存一下
}
int main()
{int src[] = { 1,2,3,4,5,6,7,8,9,10 };int dest[20] = { 0 };my_memcpy(dest, src, 24);for (int i = 0; i < 6; i++){printf("%d ", dest[i]);}return 0;
}
测试下能不能复制同内存的
本应该是1 2 1 2 3 4 5 6 9 10
所以有可能会复制不了,这是从前往后复制的,那从后往前呢?
是可以的,这就相当于是memmove
memmove函数
void * memmove ( void * destination, const void * source, size_t num );
memmove很好的解决了memcpy内存覆盖的问题
使用
#include<stdio.h>
#include<string.h>
int main()
{int src[] = { 1,2,3,4,5,6,7,8,9,10 };//int dest[20] = { 0 };memmove(src+2, src, 24);for (int i = 0; i < 10; i++){printf("%d ", src[i]);}return 0;
}
如何实现呢?
看重叠部分是被拷贝数据的前半部分还是后半部分
模拟实现
#include<stdio.h>
#include<assert.h>
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;//dest是void*类型,不能直接解引用,不能直接+-;src = (char*)src + 1;}}else{while (num--){*((char*)dest + num) = *((char*)src + num);}}return ret;
}
int main()
{int src[] = { 1,2,3,4,5,6,7,8,9,10 };//int dest[20] = { 0 };my_memmove(src+2, src, 24);for (int i = 0; i < 10; i++){printf("%d ", src[i]);}return 0;
}
总结
看完相信你对字符串函数和内存函数有了一定认识,有什么问题欢迎在评论区指出来~