目录
一 字符函数
1.strlen函数(求字符串长度)
1.1 :函数介绍
1.2 strlen的三种模拟实现
1.3易错点
2 strcpy函数(拷贝字符串)
2.1函数介绍
2.2 strcpy模拟实现
2.3 strncpy函数
3 strcat函数(追加字符串)
3.1 函数介绍
3.2strcat模拟实现
3.3 strncat函数(可指定追加的字符个数)
4 strcmp函数(比较字符串)
4.1函数介绍
4.2strcmp模拟实现
4.3 strncmp函数
5 strstr函数(查找连续的子字符串)
5.1函数介绍
5.2strstr模拟实现
6 strtok函数
6.1函数介绍
7 strerror函数
7.1函数介绍
7.1.1 errno
7.2 字符分类函数
7.3 转换函数 (针对字母大小写)
二 内存函数
8 memcpy函数
8.1 函数介绍
8.2 memcpy的模拟实现
9 memmove函数
9.1函数介绍
9.2 memmove模拟实现
9.3 memmove的简要分析
10.memcmp函数的使用
size_t strlen( const char *string )
1) strlen 函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' ) 。2)参数指向的字符串必须要以 '\0' 结束。3)注意函数的返回值为 size_t(相当于unsigned int) ,是无符号数( 易错 )
#include
#include
int my_strlen(const char* s)
{
assert(s);
int count = 0;
while (*s!='\0')
{
count++;
s++;
}
return count;
}
#include
#include
int my_strlen(const char* str)
{
assert(str);
if (*str == '\0')
{
return 0;
}
else
{
return 1 + my_strlen(str+1);
}
}
#include
#include
int my_strlen(const char* str)
{
assert(str);
const char* ret = str;
while (*ret != '\0')
{
ret++;
}
return ret - str;
}
int main()
{
if (strlen("abc") - strlen("abcdef") > 0)//无符号数相减的结果也是无符号数,这里的-3会转换成无符号数--一个非常大的正数
printf(">");//这里打印的结果为>
else
printf("<=");
return 0;
}
strlen函数的返回值为无符号数,结果为负数会转换为一个特别大的正数
char *strcpy( char *strDestination, const char *strSource )
1)源字符串必须以'\0'结束,返回值为目标指针
2)会将源字符串中的'\0'也拷贝到目标空间中
3)目标空间必须足够大可改变,以确保能存放源字符串
char*strcpy(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*dest++ = *src++)
{
;
}
return ret;
}
char*strncpy(char*strDest,const char *strSource,size_t count)
比起strcpy,strncpy可以指定比较的字符个数,其余和strcpy用法一样
int main()
{
char arr1[] = "xxxxxxxxxxxx";
char arr2[] = "he";
strncpy(arr1, arr2, 5);//原本arr2只有两个字符,剩下的三个默认传'\0'
printf("%s\n", arr1);
}
char *strcat( char *strDestination, const char *strSource )
1)原字符串必须以'\0'结束,返回值为目标指针
2)目标空间必须足够大,以确保能存放源字符串
3)目标空间必须可改变
char *my_strcat(char* dest, char* src)
{
char* ret = dest;
assert(dest && src);
while (*dest != '\0')
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
char *strncat( char *strDest, const char *strSource, size_t count )
#include
#include
int main()
{
char arr1[20] = "hello\0xxxxxxxxx";
char arr2[] = "world";
strncat(arr1, arr2, 7);
printf("%s\n", arr1);//arr1变为helloworld\0xxxx
}
int strcmp( const char *string1, const char *string2 )
注意:比较对应字符的ASCII码值的大小,不是比较字符串长度
返回值
第一个字符串大于第二个字符串,则返回大于 0 的数字第一个字符串等于第二个字符串,则返回 0第一个字符串小于第二个字符串,则返回小于 0 的数字
#include
#include
int my_strcmp(const char* str1, const char* str2)
{
assert(*str1 && *str2);
while (*str1 == *str2)
{
if (*str1 =='\0')//两字符串完全相等时,str1指向'\0'时,str2也会指向'\0'
{
return 0;
}
str1++;
str2++;
}
return *str1 - *str2;
/*if (*str1 > *str2)
{
return 1;
}
else
return -1;*/
}
int strncmp( const char *string1, const char *string2, size_t count )
使用:
#include
#include
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abcdeg";
printf("%d\n", strncmp(arr1, arr2, 5));//链式访问(函数中调用函数)
return 0;
}
比较到出现对应字符不相等或者一个字符串结束或者count个字符全部比较完
返回值和strcmp相同
char* strstr(const char* str1, const char* str2)
str1为被查找的字符串,str2为要查找的字符串
返回值:
1)如果找到了,返回后面字符串在前面字符串中首次出现的地址
2)如果找不到,返回空指针
#include
#include
int main()
{
char arr1[] = "abcdefabcdef";
char arr2[] = "bcd";
char* ret = strstr(arr1, arr2);
if (NULL == ret)
printf("没找到\n");
else
printf("%s\n", ret);//结果:bcdefabcdef
return 0;
}
//char arr[]="";//空字符串
//char *p="";//空字符串;
//char*p=NULL//空指针
#include
#include
char *my_strstr(const char *str1,const char *str2)
{
assert(*str1 && *str2);
char* s1 = str1;
char* s2 = str2;
char* tmp = s1;
if (!*str2)
{
return ((char*)str1);
}//当str2字符串为""时--》\0
while (*tmp)
{
s1 = tmp;
s2 = str2;
while (*s1 && *s2 && * s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return (char*)tmp;
}
tmp++;
}
return NULL;
}
int main()
{
char arr1[] = "abbbcdef";
char arr2[] = "bbc";
char* ret = my_strstr(arr1, arr2);
if (NULL == ret)
{
printf("没找到\n");
}
else
printf("%s\n", ret);
return 0;
}
char* strtok(char* str, const char* sep)
1) sep 参数是个字符串,定义了用作分隔符的字符集合2) 第一个参数指定一个字符串,它包含了 0 个或者多个由 sep 字符串中一个或者多个分隔符分割的标记。3) strtok 函数找到 str 中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。 (注: strtok函数会改变被操作的字符串,所以在使用 strtok 函数切分的字符串一般都是临时拷贝 的内容并且可修改)4) strtok 函数的第一个参数不为 NULL ,函数将找到 str 中第一个标记, strtok 函数将保存它在字符串中的位置。5) strtok 函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。6) 如果字符串中不存在更多的标记,则返回 NULL 指针。使用:
#include
#include int main() { const char* p = "@."; char arr[] = "[email protected]"; char buf[50] = { 0 }; strcpy(buf, arr); char* str = NULL; for (str = strtok(buf, p); str != NULL; str = strtok(NULL, p)) { printf("%s\n", str); } return 0; }
char *strerror( int errnum )
用于传入错误码,打印错误信息
c语言中规定了一些错误码,而strerror函数可以帮我们把错误码翻译成错误信息
- 0 No error
- 1 Operation not permitted
- 2 No such file or directory
- 3 No such process
- .............
errno是c语言提供的一个全局变量,可以直接使用,头文件为errno.h
当库函数使用的时候,发生错误会把errno这个全局的错误变量设置为本次执行库函数产生的错误码(即产生的错误码会存放在errno这个变量里)
使用:
#include
#include
#include
int main()
{
FILE* pf = fopen("test.txt", "r");
if (NULL == pf)
{
//出错误的原因是什么
printf("%s\n", strerror(errno));
return 0;
}
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
头文件:
函数 如果他的参数符合下列条件就返回真iscntrl 任何控制字符isspace 空白字符:空格‘ ’ ,换页 ‘\f’ ,换行 '\n' ,回车 ‘\r’ ,制表符 '\t' 或者垂直制表符 '\v'isdigit 十进制数字 0~9isxdigit 十六进制数字,包括所有十进制数字,小写字母a~f ,大写字母 A~Fislower 小写字母a~zisupper 大写字母A~Zisalpha 字母a~z 或 A~Zisalnum 字母或者数字,a~z,A~Z,0~9ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印)isgraph 任何图形字符isprint 任何可打印字符,包括图形字符和空白字符
int tolower(int c)
int toupper(int c)
#include
#include
int main()
{
char ch = 0;
ch = getchar();
if (islower(ch))
{
ch = toupper(ch);//输入为小写-->大写
}
else
{
ch = tolower(ch);//输入为大写--》小写
}
printf("%c\n", ch);
return 0;
}
void *memcpy( void *dest, const void *src, size_t count )
1) 函数 memcpy 从 src 的位置开始向后复制count 个字节的数据到 dest 的内存位置。2) 这个函数在遇到 '\0' 的时候并不会停下来。3) 如果 src 和 dest 有任何的重叠,复制的结果都是未定义的。4) 返回值为dest
#include
#include
int main()
{
int arr3[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr4[5] = { 0 };
memcpy(arr4, arr3, 20);//20还可以写成5*sizeof(arr3[0])
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d\n", arr4[i]);//1 2 3 4 5
}
return 0;
}
#include
#include
void* my_memcpy(void* dest, const void* src,size_t num)
{
void* ret = dest;
assert(dest && src);
while (num--)
{
*(char*)dest = *(char*)src;
//*(char*)dest++ = *(char*)src++;//这种写法编译器不支持
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
int main()
{
int arr3[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr4[5] = { 0 };
my_memcpy(arr4, arr3 + 5, 5 * sizeof(arr3[0]));//拷贝内存时不可重叠(vs支持重叠的,其他编译器不一定)
memcpy(arr4, arr3, 20);//20还可以写成5*sizeof(arr3[0])
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d\n", arr4[i]);//1 2 3 4 5
}
return 0;
}
即如果源内存和目标内存出现重叠,memcpy就无法处理,这时我们就需要memmove函数进行处理。
void *memmove( void *dest, const void *src, size_t count )
这里的count单位为字节
可以理解为是memcpy的升级版,处理的源内存和目标内存是可以重叠的
使用:
#include
#include
int main()
{
int arr3[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr3 + 2, arr3, 20);
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d\n", arr3[i]);//1 2 1 2 3
}
}
#include
#include
void* my_memmove(void* dest, const void* src, size_t num)//num单位为字节
//src赋给dest
{
void* ret = dest;
assert(dest && src);
//前——>后
if(src > dest)
{
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 arr3[] = { 1,2,3,4,5,6,7,8,9,10 };
memmove(arr3 + 2, arr3, 20);
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d\n", arr3[i]);//1 2 1 2 3
}
}
dest
src只能从前往后依次赋值给dest 如果从后往前的话(当src指向原本是4的位置时,此时已经被赋值成6,这样打印结果就会出现问题)
src
(src ) 同理:src此时只能从后往前依次赋值给dest
dest>src时 这种情况那种顺序都行,但为了方便,和上面那种情况都归为dest>src的情况(从后往前赋值)
综上:memcpy-->拷贝不重叠的内存
memmove-->处理(重叠,不重叠都行)的内存拷贝
注意:VS2019里的memcpy比较完善,也可以处理重叠内存拷贝
int memcmp( const void *buf1, const void *buf2, size_t count )
用法:与strcmp相比,除了比较字符,还可以比较整型
比较从ptr1和ptr2指针开始的num个字节
返回值
使用:
#include
#include
int main()
{
int arr1[] = { 1,2,7,4,5 };
int arr2[] = { 1,2,3,4,5 };//这里比较的字节顺序是(VS:小端字节序方式)07 00 00 00
int ret = memcmp(arr1, arr2, 9);//7>3
printf("%d\n", ret);//打印结果为大于0的数
return 0;
}