目录
前言
字符函数
1strlen
模拟实现
2strcpy
模拟实现
3strcat
模拟实现
4strcmp
模拟实现
5strncpy
模拟实现
6strncat
模拟实现
7strncmp
模拟实现
8strstr
模拟实现
9strtok
10strerror
11大小写字符转换函数
内存函数
1memcpy
模拟实现
2memmove
模拟实现
3memset
4memcpy
前言
C语言对应字符串的处理很繁琐(比如经常要知道它们的长度啦,拷贝啦,移动啦): 所以专门提供了一些列字符(串)函数来方便使用者处理使用~
而我们在学习各种函数时,推荐cplusplus.com来进行学习使用~
字符函数
1strlen
a计算的是字符串总长度(不包含\0)
b参数传的是字符串首元素地址,返回类型是size_t (无符号整数)
如果你对它返回类型一知半解,那么下面的这道题你一定会做错!
#include <stdio.h>
int main()
{const char* str1 = "abcdef";const char* str2 = "bbb";if (strlen(str2) - strlen(str1) > 0){printf("str2>str1\n");}else{printf("srt1>str2\n");}return 0;
}
第一眼感觉 strlen(str2) - strlen(str1) = 3 - 6 <0 所以返回的是 str>2str1
但实际上是两个无符号整数相减,结果还是正整数!
模拟实现
//计数器
int Strlen1(char* s)
{int cnt = 0;while (*s != '\0'){cnt++;s++;}return cnt;
}//递归
int Strlen2(char* s)
{if (*s == '\0') return 0;return 1 + Strlen2(++s);//先s移动再递归!
}//指针-指针
int Strlen3(char* s)
{char* begin = s, * end = s;while (*end != '\0') end++;return end - begin;
}
2strcpy
a 源字符串(第二个参数)必须以 '\0' 结束;
否则会不断给目的字符串复制,des字符串复制超过最大空间后,就会越界访问(程序崩溃)
b复制会将源字符串中的 '\0' 拷贝到目标空间。
c目标空间必须足够大,以确保能存放源字符串;小于(源字符串的长度+1)同样崩
所以目标空间必须可变,如char*类型
模拟实现
char* Strcpy(char* desnation, const char* source)
{char* ret = desnation;while (*desnation++ = *source++)//拷贝了source的'\0'后循环停止{}return ret;
}
3strcat
a源字符串必须以 '\0' 结束。
b目标空间必须有足够的大,能容纳下源字符串的内容。
c目标空间必须可修改。
自己给自己追加,如何?
理论上会一直遇不到‘\0’,直到越界访问程序崩溃! 但实际上库函数是可以实现自己给自己追加,但还是不推荐这样做~
模拟实现
char* Strcat(char* desnation, const char* source)
{char* ret = desnation;while (*desnation != '\0'){desnation++;}//des指向'\0'while (*desnation++ = *source++){}return ret;
}
4strcmp
该函数用来进行两个字符串的比较大小:从第一个字符开始比,如果相同就往下一个比...
返回值:
>0 说明str1比str2大
=0 说明str1与str2一样大
<0 说明str1比str2小
模拟实现
int 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;return *str1 - *str2 >0 ? 1 : -1;
}
以上的strcpy,strcat和strcmp都是不受长度限制的函数,同时使用时必须先考虑字符串长度大小, 而接下来的函数则是受长度限制的函数,相对安全些~
5strncpy
与strcpy功能类似,但加了一个num参数,表示你当前要拷贝多少个字符(‘\0’算在内)
模拟实现
char* Strncpy(char* desnation, const char* source,int num)
{char* ret = desnation;while ((num--)&&(*desnation++ = *source++))//拷贝了source的'\0'后循环停止{}return ret;
}
6strncat
与strcat是类似的:但你可以选择追加num个字符(‘\0’不算在内),追加完后自动加'\0'!
模拟实现
char* Strncat(char* desnation, const char* source,int num)
{char* ret = desnation;while (*desnation != '\0'){desnation++;}while ((num--)&&(*desnation++ = *source++)){}*desnation = '\0';//不管source指没指向'\0'都要添加return ret;
}
7strncmp
与strcmp是类似的:但你可以自己选择num个字符进行比较
模拟实现
int Strncmp(const char* str1, const char* str2,int num)
{while ((--num)&&(*str1 == *str2)){if (*str1 == '\0') return 0;str1++;str2++;}if (*str1 == *str2) return 0;else return *str1 - *str2 > 0 ? 1 : -1;
}
8strstr
从str1中找包含str2的子串,找到了就返回str1出现子串的第一个位置的地址~
模拟实现
const char* Strstr(const char* str1, const char* str2)
{if (*str2 == '\0') return str1;//边界情况//匹配过程每次比较时的开始位置const char* p1 = str1;//进行移动判断字符是否相等const char* m1;const char* m2;while (*p1 != '\0'){m1 = p1, m2 = str2;while (*m2 != '\0' && *m1 == *m2){m1++;m2++;}if (*m2 == '\0') return p1;p1++;}return NULL;
}
9strtok
a delimiters是一个标记符集合;
b 将str中出现的标记符进行替换成“\0”(调用一次只会替换一个);
c 如果替换操作完成,返回替换开始前的地址;替换失败(找不到标记符),返回NULL;
d 也就是说:str传进来的参数是要被进行修改的,所以使用前要先将内容进行拷贝一份;
e 调了一次后,接下来要把str置NULL(因为strtok已经记住了下次从什么位置开始替换)
int main()
{char str[] = "zzj@qq.com";char arr[20];strcpy(arr, str);/*char* pch;pch = strtok(arr, ".@");while (pch != NULL){printf("%s\n", pch);pch = strtok(NULL, ".@");}*/for (char* pch = strtok(arr, ".@"); pch != NULL; pch = strtok(NULL, ".@")){printf("%s\n", pch);}return 0;
}
10strerror
返回错误码所对应的信息字符串,我们需要再用printf进行打印出来
相对类似的还有 perror 它不用printf打印方便些:
11大小写字符转换函数
小转大:toupper 大转小:tolower
内存函数
为了防止拷贝内容不只有字符串(可以用strncpy),所以需要内存函数来实现
1memcpy
从source中复制num个字节到destination中;
模拟实现
void* Memcpy(void* de, void* so, size_t num)
{while (num--){*((char*)de) = *((char*)so);//前置++在vs或许能过,但在别的平台就不能保证(++优先级高于强转)//++(char*)de;//++(char*)so;de=(char*)de+1;so=(char*)so+1;}
}
能不能实现在同一个数组进行拷贝?
如果用我们模拟实现出来的函数,是不行的:拷贝时会把后面的数给覆盖掉!
标准规定:使用非一块空间复制用memcpy;使用同一块空间复制用memmove
但是如果用memcpy呢?
居然是可以!难道是我们实现出来的代码有问题? 当然不是:我们实现出来的按照标准来说是合格了的;但在VS平台中实现的memcpy不仅是符合标准的,而且还把它给加强了,只能说是满分级别的标准~
2memmove
与memcpy的参数是一样的,通常用来解决同一块空间进行复制
模拟实现
解决上面数据被覆盖的问题,我们可以选择从后先前拷贝,那是不是所有的情况都适合?
如果是上面的情况,从后先前拷贝也出现了数据被覆盖的问题,这时选择从前向后拷贝更合适~
所以要分情况进行讨论:来决定用那种拷贝方式
3memset
以字节为单位:将num个字节设置成value值
应用与字符串时:
能做到,那如果想把int类型的值进行修改呢?
做不到:它是按字节为单位进行修改的;如果是修改成0的话就可以
所以它通常是用来进行将空间全部置为0(清理空间)
4memcpy
以字节为单位比较从desnation和source指针开始的num个字节
使用:
以上便是全部内容,有问题欢迎在评论区指正,感谢观看!