目录
一、函数的组成和介绍
1.strlen
size_t strlen ( const char * str );
函数组成
输入:const char* str: 指向要求长度的字符串元素首地址。
返回值:szie_t(无符号整型): 是传入指针指向的字符串的长度。
介绍
返回str指向的字符串的长度。
2.strcpy
char* strcpy(char * destination, const char * source );
函数组成
输入:1.char* destination: 需要拷贝的目标地址。
2.const char* source: 被拷贝的源地址。
返回值: char*: 指向要拷贝元素的目标数组的地址(destination)。
介绍
拷贝source指向的字符串到destination指向的地址。
3.strcat
char* strcat (char * destination, const char * source );
函数组成
输入:1.char* destination: 需要拷贝的目标地址。
2.const char* source: 被附加的源地址。
返回值: char*: 指向要附加元素的目标数组的地址(destination)。
介绍
附加source到destination的后方,覆盖最后的'\0',并在附加结束后在末尾添'\0'。
4.strcmp
int strcmp (const char * str1, const char * str2 );
函数组成
输入:1.const char* str1: 指向要判断的第一个字符串的首元素地址。
2.const char* str2: 指向要判断的第二个字符串的首元素地址。
返回值:int : 1.str1 < str2,返回<0的数值(Visual Studio 中为 -1)
2.str1 = str2,返回0
3.str1 > str2,返回>0的数值(Visual Studio 中为 1)
介绍
依次比较str1指向的字符串和str2指向的字符串的每一位,如果相同则继续往下比较,比较到'\0'仍旧相同,那么返回0; 如果有一次str1中的元素的ASCLL码值比str2的大返回一个大于0的值; 反之返回小于0的值。
5.strncpy
char * strncpy ( char * destination, const char * source, size_t num );
函数组成
输入:1.char* destination: 需要拷贝的目标地址。
2.const char* source: 被拷贝的源地址。
3.size_t num: 要拷贝的元素的个数。
返回值:char*: 指向要拷贝元素的目标数组的地址(destination)。
介绍
贝source指向的字符串的num个元素到destination指向的地址。
有以下情况:1. num大于source的长度,多的部分会以'\0'填充直到num个。
2. num小于source的长度,拷贝source的前num个元素。
(情况2)注意:num小于source的长度时最后不会填充'\0'。
6.strncat
char * strncat ( char * destination, const char * source, size_t num );
函数的组成
输入:1.char* destination: 需要拷贝的目标地址。
2.const char* source: 被拷贝的源地址。
3.size_t num: 要拷贝的元素的个数。
返回值:char*: 指向要拷贝元素的目标数组的地址(destination)。
介绍
附加source的num个元素到destination的后方,覆盖最后的'\0'。
有以下情况:1. num大于source的长度,附加source元素直达末尾, 并加上'\0'。
2. num小于source的长度,附加num个source元素,并加上'\0'。
注意:拷贝的目标地址需要有字符串、有足够的空间。
7.strncmp
int strncmp ( const char * str1, const char * str2, size_t num );
函数组成
输入:1.const char* str1: 指向要判断的第一个字符串的首元素地址。
2.const char* str2: 指向要判断的第二个字符串的首元素地址。
3.size_t num: 比较的最多个数。
返回值:int : 1.str1 < str2,返回<0的数值(Visual Studio 中为 -1)
2.str1 = str2,返回0
3.str1 > str2,返回>0的数值(Visual Studio 中为 1)
介绍
比较str1和str2指向的字符串最多num个元素。
有以下情况:
1.有一次str1中的元素的ASCLL码值比str2的大返回一个大于0 的值。
(包括结束标志的比较)
2.有一次str1中的元素的ASCLL码值比str2的小返回一个小于0 的值。
(包括结束标志的比较)
3.直到num个或同时到达两个字符串结束标志也没有出现上述情况则返回0。
(实际上同时到达结束标志也进行了比较)
8.strstr
char * strstr ( const char * str1, const char * str2);
函数组成
输入:1.const char* str1: 指向包含str2的被搜索字符串的首元素地址。
2.const char* str2: 指向要查找的字符串的首元素地址。
返回值:char* : 1.找到了返回指向str2第一次出现在str1中的字符串的首元素地址的指针。
2.找不到返回NULL。
介绍
查找str2第一次出现在str1的位置,返回一个指向该位置首元素的指针,未找到返回NULL。
9.strtok
char * strtok ( char * str, const char * sep );
函数组成
输入:1.char* str: 要被分割的目标字符串的指针。
2.const char* sep: 指向分割符组成的字符串的指针。
介绍
sep指向的字符串内,存在若干个标记(分割符);函数的作用是对str指向的字符串按分隔符进行分割。具体分割方式如下:
1.查找开头,第一次传入时,a.从str头部开始,找到第一个不是分隔符的字符作为开头。
b.不是第一次传入,会从上一次结尾标记开始查找
2.查找结尾,查找从开头开始第一个分隔符或者是结尾标志作为结尾,并作为标记记录。
3.替换结尾字符并返回开头字符的地址。
提醒:在两个连续的分隔符中间不会进行分割(从1.查找开头可以看出)
10.strerror
char * strerror ( int errnum );
函数组成
输入:int errnum: 错误码,里面的值会随错误产生改变。
返回值: 返回指向错误信息的字符串指针。
介绍
配合返回错误信息字符串的首元素地址,主要配合printf打印错误信息,提高交互性。
11.字符分类函数
函数 | 如果他的参数符合下列条件就返回真 |
---|---|
iscntrl | 控制字符 (在ASCII码中,第0~31号及第127号(共33个)是控制字符) |
isspace | 空白字符:空格‘ ’,换页‘\f’,换行'\n', 回车‘\r’,制表符'\t'或者垂直制表符'\v' |
isdigit | 十进制数字 0~9 |
isxdigit | 十六进制数字 包括所有十进制数字,小写字母a~f,大写字母A~F |
islower | 小写字母 a~z |
isupper | 大写字母 A~Z |
isalpha | 字母 a~z或A~Z |
isalnum | 字母或者数字 a~z,A~Z,0~9 |
ispunct | 标点符号,任何不属于数字或者字母的图形字符 (可打印) |
isgraph | 图形字符 略 |
isprint | 可打印字符 包括图形字符和空白字符 |
12.字符转换函数
int tolower ( int c );
int toupper ( int c );
函数组成
输入:c: 对应字符的ASCLL码值。
返回值: 转换后的ASCLL码值。
介绍
大小写转换,虽然函数组成是传入int的ASCLL,实际上直接传入字符和直接使用返回值 作为字符也是可以的(隐式转化)。
13.memcpy
void * memcpy ( void * destination, const void * source, size_t num );
函数组成
输入:1.void * destination: 指向要复制的目的空间的开头地址。
2.const void * source:指向要被复制的源空间的开头地址。
3.size_t num: 要复制的字节数。
返回值: destination指向的地址。
介绍
与strncpy相似,不过是对每个字节进行复制,如果destination和source,在num个字节内有重叠,其复制结果是不确定的,一般的要求只是和strncpy一样,重复的位置被覆盖而达不到预期效果, 如有重叠可使用memmove函数,不过Visual Studio 2019中本函数没用这种问题。
14.memmove
void * memmove ( void* destination, const void * source, size_t num );
函数组成
输入:1.void * destination: 指向要复制的目的空间的开头地址。
2.const void * source:指向要被复制的源空间的开头地址。
3.size_t num: 要复制的字节数。
返回值: destination指向的地址。
介绍
与memcpy的差别在于memmove能够处理重叠地址。
15.memcmp
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
函数的组成
输入:1.const void* ptr1: 指向要判断的第一个空间的首地址。
2.const void* ptr2: 指向要判断的第二个空间的首地址。
3.size_t num: 要比较的字节数。
返回值:int : 1.ptr1 < ptr2,返回<0的数值(Visual Studio 中为 -1)
2.ptr1 = ptr2,返回0
3.ptr1 > ptr2,返回>0的数值(Visual Studio 中为 1)
介绍
比较ptr1和ptr2指向的空间最多num个字节。
有以下情况:1.有一次ptr1中的字节比ptr2的大,ptr1 > ptr2。
2.有一次ptr1中的字节比ptr2的小,ptr1 < ptr2。
3.比较了num个字节都没有出现1,2情况,ptr1=ptr2;
二、函数的实现
所有实现仅供参考,并非唯一,也并不能保证绝对正确,请自行斟酌。
1.strlen
size_t mystrlen(const char* arr)
{
assert(arr);
int i = 0;
while (*arr++)
{
i++;
}
return i;
}
有三种方式实现:1.计数器方法(本方法)
2.递归:没有递归到‘\0’就继续继续递归并返回1。
3.指针-指针:找到最后一位的指针,尾指针减头指针。
注意(3.):有类型指针相减返回的是两个指针中间该类型元素个数。
2.strcpy
char* mystrcpy(char* arr, const char* brr)
{
assert(arr);
char* farr = arr;
while (*brr != 0)
{
*arr++ = *brr++;
}
*arr = '\0';//末尾标志
return farr;
}
3.strcat
char* mystrcat(char* arr, char* brr)
{
char* harr = arr;
assert(arr);
assert(brr);
while (*arr)//这里不能用++
{
arr++;
}
while (*brr)
{
*arr++ = *brr++;
}
*arr = '\0';
return harr;
}
第一个循环是找打arr的末尾位置,注释部分是不能使用while(*arr++)这样在'\0'时arr还会++,导致指向'\0'下一位。
第二个循环是复制。
4.strstr
char* mystrstr(const char* str1, const char* str2)
{
assert(str1);
assert(str2);
char* hstr1 = str1;
char* s1;
char* s2;
while (*hstr1)
{
s1 = hstr1;
s2 = str2;
while (*s2 && *s1 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return hstr1;
}
hstr1++;
}
return NULL;
}
本实现方法为暴力查找法,并不推荐,有更好的KMP算法。(如下)
5.strcmp
int mystrcmp(const char* arr, const char* brr)
{
assert(arr);
assert(brr);
while (*arr == *brr)
{
if (*arr == '\0')//进到里面arr == brr,满足if说明同时到了结束
{
return 0;
}
arr++;
brr++;
}
return *arr - *brr;
}
如果没有退出while循环,说明它们两个始终相同(两个同时是‘\0’也会进入循环),退出循环说明有两方不同,直接相减可得到相差的ASCLL码值,作为返回值。
6.memcpy
void* mymemcpy(void* dest, const void* source, size_t num)
{
void* hp = dest;
assert(dest && source);
while (num--)
{
*(char*)dest = *(char*)source;
dest = (char*)dest + 1;
source = (char*)source + 1;
}
return hp;
}
除了类型转换与strncpy没有本质区别。(本实现没有像vs中一样解决重叠问题)
7.memmove
void* mymemmove(void* dest, const void* source, size_t num)
{
assert(dest && source);
void* hp = dest;
int f = 0;
if (dest > source)//源地址在前面,从后往前走
{
while (num--)
{
*((char*)dest + num) = *((char*)source + num);
}
}
else//从前往后走
{
while (num--)
{
*(char*)dest = *(char*)source;
dest = (char*)dest + 1;
source = (char*)source + 1;
}
}
return hp;
}
和memcpy类似,不过需要判断dest和source是否重叠,怎样重叠来选择是从后往前复制,还是从前往后复制,来避免重叠导致的错误。
1.来源在目标的前方,我们选择从后往前复制,这样复制时不会把目标未来要使用的覆盖。
2.来源在目标的后方,选择从前往后复制。
例:
上图是来源在后方我们拷贝4个字节内容,可以看到如果是a.从前往后第四次是需要覆盖掉source的第一位的,如果是b.从后往前第一次就会用第四位覆盖掉source的第一位,这样在使用source进行拷贝时候source的内容已经是被改变的source+3的内容了。