在敲代码的时候,我们常常需要用到大量的库函数,而在这些库函数中,字符与字符串相关函数以及字节操作函数十分常用。接下来,我们便仔细详解这三类库函数。
(1)字符函数
在字符函数中,分为两大类:字符分类函数以及字符转换函数。
字符分类函数:字符分类函数需要一个头文件,ctype.h。在这个头文件中,包含了以下库函数:
以上库函数差别不大,都是需要输入一个 字符或者数据,然后函数进行判断后返回,当判断为真时,则返回1,可能我们需要一个变量来接受这个返回值并打印出来。
字符转换函数:字符转换函数也需要ctype.h头文件,这个函数主要包含两个部分:tolower函数与toupper函数,他们分别能实现两个功能。tolower函数能将输入的字符中的大写转换为小写,toupper可以将输入的字符从小写转换为大写。他一次只能操控一个字符,所以如果想对字符串进行操作,则需要用到循环结构。
字符串函数
字符串是c语言的重要组成部分,如何更加快捷有效的利用字符串和操作字符串便时至关重要的了。有关于字符串的库函数拥有一个头文件string.h,这个头文件下包含了许多关于字符串的库函数,接下来我们来一一列举。
strlen:1这个库函数可能是我们使用最多的几个库函数了,他的功能就是查看这个字符串,他输入一个字符串首地址,然后自动往后进行查询,直到找到了\0,结束并返回找到的字符个数。以下是模拟实现的strlen。
size_t Mystrlen(const char* str)
{
assert(str);
int i = 0;
char* ret = str;
while (str[i] != '\0')
{
i++;
}
return i;//方法一
if (*str == '\0')
{
return 0;
}
else
return 1 + Mystrlen(str + 1);//方法二
char* p = str;
while (*p != '\0')
{
p++;
}
return p - str;//方法三
}
strcpy与strncpy:该函数的作用是将一个字符串复制到另一个字符串中,strcpy就是单纯的复制过去,而strncpy还可以指定复制多长的距离。他们的模拟实现如下图。
void mystrcpy(char* str1, const char* str2)
{
assert(str1 != null);
assert(str2 != null);
while (*str2 != '\0')
{
*str1 = *str2;
str1++;
str2++;
}//复杂版
while (*str1++ = *str2++);
}
void my_strncpy(char* str1,char* str2,char n)
{
assert(str1 != NULL);
assert(str2 != NULL);
char* ret = (char*)str2;
for (char* ret = str2; ret < str2 + n; ret++)
{
if (*ret==0 || *str1==0)
{
return 0;
}
*str1 = *ret;
str1++;
}
}
strcat与strncat:这两个函数是将一个字符串接到另一个字符串的尾部,strncat还能控制要接多长的距离,注意,不要数据溢出,刚开始定义字符串长度的时候就需要注意。以下是模拟实现:
void Mystrcat(char* str1, const char* str2)
{
assert(str1 != NULL);
assert(str2 != NULL);
while (*str1)
{
str1++;
}
if (*str1 == '\0')
{
while (*str1++ = *str2++)
{
}
}
void my_strncat(char* str1, char* str2, char n)
{
assert(str1 != NULL);
assert(str2 != NULL);
char* ret = (char*)str2;
while (*str1)
{
str1++;
}
for (char* ret = str2; ret < str2 + n; ret++)
{
if (*ret == 0)
{
*str1 = 0;
return 0;
}
*str1 = *ret;
str1++;
}
strcmp:该函数进行的是两个字符串的大小比较,他会同时从两个字符串的初始位置开始,一个一个的往后进行比较,字符串的比较依托的是ascii值,如果字符串1查询到的ascii值大于字符串2,则返回1,若小于,则返回-1,如果直到最后的\0两者都相等,则返回0.以下是模拟实现。
int my_strcmp(char* str1, char* str2)
{
assert(str1 != NULL);
assert(str2 != NULL);
while (*str1 == *str2)
{
if (*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
if (*str1 > *str2)
{
return 1;
}
if (*str1 < *str2)
{
return -1;
}
}
strstr:该函数实现的是在一个字符串中查询另一个字符串的存在。他的本意是若找到另一个字符串,则返回在第一个字符串中字符串2第一次出现的地址。若自始至终都没有找到,则返回NULL,模拟实现时,因为图方便,我便是找到返回1,没找到返回0。如果自己模拟时需要,稍作修改即可,
int my_strstr(char* str1, char* str2)
{
assert(str1 != NULL);
assert(str2 != NULL);
while (*str2)
{
char* ret = str1;
while (*str1 == *str2)
{
if (*str1 == ' ' && *str2 == ' ')
{
return 1;
}
else
{
str1++;
str2++;
}
}
if (*str1 == 0 && *str2 == ' ')
{
return 1;
}
if(*str1 != *str2)
{
str1 = ret;
str2++;
}
}
return 0;
strtok:该函数是用于在字符串中找到第一个分割符并进行分割,并用\0结尾,返回该地方的指针,一般来说strtok函数作用于临时拷贝的字符串,因为strtok会改变被操作的字符串。
上述就是字符串函数的相关知识,而下面便是到内存函数的部分了。
mencpy:该函数的作用就是将一个任意数据以字符为单位复制到另一个数据中,这个函数不同于strncpy,该函数不会因为遇到\0就停下来。下列是模拟实现的代码。对于任意输入的数据的地址,都将其强制转换为char*类型,这样子我们在不断的加1的时候,就能够做到每次操控一个字节。
void my_mencpy(const void* dest, const void* sour, size_t n)
{
char* ret = dest;
assert(dest != NULL);
assert(sour != NULL);
while (n--)
{
*(char*)dest = *(char*)sour;
dest = (char*)dest + 1;
sour = (char*)sour + 1;
}
}
menmove:该函数能够弥补memcpy的一个坏处,mencpy不能将同一数据内字节低地址的数据按字节移高地址,会出现重复使用的现象。而利用menmove就可以解决这个问题。对该函数的模拟如图所示。
void my_memmove(const void* dest, const void* sour, size_t n)
{
char* str1 = dest;
char* str2 = sour;
assert(dest != NULL);
assert(sour != NULL);
if (dest > sour)
{
(char*)str1 += n;
(char*)str2 += n;
for (; str1 >= dest; str1--)
{
*str1 = *str2;
str2++;
}
}
if (dest < sour)
{
for (; str1 < (char*)dest+n; str1++)
{
*str1 = *str2;
str2++ ;
}
}
}
如上,结束。