常用字符串函数实现!拥有自己的“库”!
复习几个常用的字符串,枯燥之余想到了一种更有趣的复习方法,那就是自己写这些常用的字符串函数,虽然对于大佬们来说已经是稀松平常,但对于我来说,看见自己写的.h文件被#include,是一种很幸福的感觉。
今天就分享一下几个常用字符串函数,它们分别是 strlen、strcat、strcpy、strncpy、strcmp、strlwr、strupr。
首先打开你的编辑器,创建一个新的文件,保存时记得后缀是.h
写上这三行代码:
然后就可以在中间写函数了。
一、strlen
C 库函数 size_t strlen(const char *str) 计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。
可以看到,strlen的返回值是 size_t类型,size_t是什么类型呢?
于是可以从官方的string.h中找到这样一个语句:
可以看到 size_t其实就是unsigned int类型
于是,我们可以写出这这样一行函数声明:
size_t mylen(const char *a);
计算字符串长度,直到空字符结束,但不包括空字符,所以:
size_t mylen(char *a) {
size_t n;
for(n=0;a[n];n++);//不计算'\0',所以n从0开始加到'\0'就完事
return n;
}
二、strcat
C 库函数 char *strcat(char *dest, const char *src) 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。
返回的是一个指针,需要传入两个指针,于是可以写出如下函数声明:
char* mycat(char *a, const char *b);
要把b串追加到a串后面,那么b串第一个字符的位置就是a串最后那个'\0'的位置。于是:
char* mycat(char *a, const char *b); {
int cnt,i;//a串和b串的计数器
for(cnt=0;a[cnt];cnt++);//先让cnt指向a串的'\0'
for(i=0;b[i];i++) {
a[cnt++] = b[i];//从a串的'\0'位置开始追加b串
}
a[cnt] = '\0';//需要手动补上结束标志'\0'
return a; //返回已经处理好的字符串的地址
}
三、strcpy
C 库函数 char *strcpy(char *dest, const char *src) 把 src 所指向的字符串复制到 dest。
需要注意的是如果目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况。
返回一个指针,需要传入两个指针,所以可以写出如下函数声明:
char* mycpy(char *a, const char *b);
要把b串拷贝到a串,就用b串把a串覆盖掉,并在末尾加上一个'\0'。于是:
char* mycpy(char *a, const char *b) {
int cnt;//设置一个计数器控制下标
for(cnt=0;b[cnt];cnt++)
a[cnt] = b[cnt];//用b串把a串覆盖掉
a[cnt] = '\0';//手动添加一个'\0'
return a;//返回已经处理好的字符串的地址
}
四、strncpy
C 库函数 char *strncpy(char *dest, const char *src, size_t n) 把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用空字节填充。
c库里面的声明是这样的:
相当于上面strcpy的升级版,strncpy可以指定拷贝多少个字符。
返回一个指针,需要传入两个指针和一个size_t(实际上是无符号整数),于是函数声明就来了:
char* myncpy(char *a, const char *b, size_t n);
把b串的前n个字符拷贝到a中,和strcpy一样,直接把a覆盖了就行了,于是:
char* myncpy(char *a, const char *b, size_t n) {
int cnt;//计数器控制下标
for(cnt=0;cnt<n && b[cnt];cnt++) //还没有复制到n个字符且没有指向b串的'\0'时
a[cnt] = b[cnt];//同位置上b把a覆盖
a[cnt] = '\0';//添加上一个字符串结束标志
return a;//返回已经处理好的字符串的地址
}
五、strcmp
C 库函数 int strcmp(const char *str1, const char *str2) 把 str1 所指向的字符串和 str2 所指向的字符串进行比较。
可以看到,返回值为int,是要用这个返回的int来表示str1和str2的大小关系,这个函数有点特别,通常来讲有以下三种情况:
-
当 str1 == str2 时,返回值为 0
-
当 str1 > str2 时,返回值为1
-
当 str1 < str2 时,返回值为-1
但有的编译器在两个字符串不相等时返回的是第一个不相等的字符串的ASCII码的差值,原因可能是这样:
大部分情况是0,1,-1。
于是开始写函数声明:
int mycmp(const char *a, const char *b);
strcmp的比较规则是:从左至右逐个字符按ASCII码值相比,直到出现不同的字符或遇到'\0'为止。
比较的不是总大小!
逐个比较,返回0,1,-1。于是:
int mycmp(const char *a, const char *b) {
int cnt;//计数器控制下标
int i = 0; //作判断标志
for(cnt=0;a[cnt] || b[cnt];cnt++) {
//当a,b串都不为空时执行以下语句
if(a[cnt] > b[cnt]) {
i = 1;//若想要返回ASCII码之差,改为i=a[cnt]-b[cnt];即可
break;
}
else if(a[cnt] < b[cnt]) {
i = -1;//同上
break;
}
}
return i;
}
六、strlwr
C库函数 char *strlwr(char *str)用于将字符串str中的字符转换为小写,只转换str中出现的大写字母,不改变其它字符。
传入指针返回指针,即要对字符串进行操作,还要返回操作完后的字符串,于是可以写出如下函数声明:
char* mylwr(char *a);
大写转换小写思路就很简单了,逐个扫描,出现大写字母时就将其转换成小写,利用ASCII码很容易就实现了,大小写的ASCII码差值正好为32,所以我们来点有意思的操作:
char* mylwr(char *a) {
char *b = a;//因为要对a进行操作,所以用b记录一下字符串的地址
for(;*a;a++) {
//当a所指向的位置不为'\0'时,继续操作
if(*a >='A' && *a <= 'Z') //判断a位置上的字符是否为大写字母
*a += 32;//大写字母的ASCII码加上32恰好是其对应的小写字母
}
return b;//返回字符串的地址
}
七、strupr
C库函数 char *strupr(char *str)用于将字符串str中的字符转换为大写,只转换str中出现的小写字母,不改变其它字符。
传入指针返回指针,即要对字符串进行操作,还要返回操作完后的字符串,于是可以写出如下函数声明:
char* myupr(char *a);
和刚刚strlwr的思路一样,只不过变成了小写转大写,大转小加32,那么小转大就减32咯。于是:
char* myupr(char *a) {
char *b = a;//记录字符串地址
for(;*a;a++) {
//当字符串还未遍历完,即a所指向的位置不为'\0'时
if(*a >='a' && *a <= 'z')
*a -= 32;//利用ASCII码
}
return b;//返回字符串的地址
}
结束
做完了以上步骤后,文件是这样的:
这时候我们写一个.c文件来测试一下:
一定记得要把.h文件和测试的.c文件放在同一目录下并用#include”“将其写在代码最上面。
使用:
和使用C库函数一样,如使用mylen:
#include<stdio.h>
#include"mystr.h"
#define MAX 50
int main(int argc, char** argv) {
char a[MAX], b[MAX];
gets(a);
printf("%zd",mylen(a));
return 0;
}
输入:
abcde
输出:
5
然后就可以愉快的用自己的”库“了!