目录
1.strlen函数
1.1.strlen函数介绍
size_t strlen ( const char * str );
1. 字符串以 '\0' 作为结束标志, strlen 函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )2. 参数指向的字符串必须要以 '\0' 结束。3.注意函数的返回值为 size_t ,是无符号的( 易错 )
#include<stdio.h>
#include<string.h>
int main()
{
int len=strlen("abcdef");
printf("%d\n",len);
return 0;
}
1.2.strlen函数模拟实现
模拟实现方法:1.计数器的方法2.递归方法3.指针-指针
#include<stdio.h>
int my_strlen(const char* str)
{
assert(str);
int count = 0;
while (*str)
{
count++;
str++;
}
return count;
}
int main()
{
int len = my_strlen("abcdef");
printf("%d\n", len);
return 0;
}
注:
![](https://i-blog.csdnimg.cn/blog_migrate/1ecd05f0eb3782fc87fe9dc8fd31a91b.png)
模拟实现2:(递归方法)
#include<stdio.h>
int my_strlen(const char* str)
{
assert(str);
if (*str == '\0')
return 0;
else
return 1 + my_strlen(str + 1);
}
int main()
{
int len = my_strlen("abcdef");
printf("%d\n", len);
return 0;
}
模拟实现3:(指针-指针)
#include<stdio.h>
int my_strlen(char* s)
{
assert(str);
char* p = s;
while (*p != '\0')
p++;
return p - s;
}
int main()
{
int len = my_strlen("abcdef");
printf("%d\n", len);
return 0;
}
2.strcpy函数
2.1.strcpy函数介绍
char* strcpy ( char * destination , const char * source )
源字符串必须以 '\0' 结束会将源字符串中的 '\0' 拷贝到目标空间目标空间必须足够大,以确保能存放源字符串目标空间必须可变(只读数据区的内容不可更改)
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[]="abcdef";
char arr2[20]={0};
strcpy(arr2,arr1);
printf("%s\n",arr2);
return 0;
}
2.2.strcpy函数模拟实现
#include<stdio.h>
#include <string.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*src)
{
*dest = *src;
dest++;
src++;
}
*dest = *src;
return ret;
}
int main()
{
char arr1[] = {'a', 'b', 'c', 'd', 'e', 'f', '\0'};
char arr2[20] = "xxxxxxxxxxxx";
my_strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}
模拟实现2:(改进版)
#include<stdio.h>
#include <string.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src)
{
assert(dest && src);
char* ret = dest;
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[] = {'a', 'b', 'c', 'd', 'e', 'f', '\0'};
char arr2[20] = "xxxxxxxxxxxx";
my_strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}
3.strcat函数
3.1.strcat函数介绍
char * strcat ( char * destination , const char * source );
功能:将源字符串的内容追加到目标字符串的后面源字符串和目标字符串都必须以 '\0' 结束。目标空间必须有足够的大,能容纳下源字符串的内容。目标空间必须可修改。
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[30]="hello";
char arr2[]="word";
strcat(arr1,arr2);
printf("%s\n",arr1);
return 0;
}
3.2.strcat函数模拟实现
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
//1. 目标空间中的\0
while (*dest)
{
dest++;
}
//2. 追加内容到目标空间
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[30] = "hello";
char arr2[] = "world";
my_strcat(arr1, arr2);
printf("%s\n", arr1);
return 0;
}
注:
1.若想知道编译器函数库中某函数是怎样实现的,通过以下步骤可观察(以strcat函数为例)
![](https://i-blog.csdnimg.cn/blog_migrate/ccb786e29c56b5ad79c89f8c1805a426.png)
步骤二:单机鼠标右键,点击打开路径
![](https://i-blog.csdnimg.cn/blog_migrate/2bad8e35f9101171fcd10b882d113b64.png)
步骤三:找到.c文件所在文件夹,将该文件拖入vs编译器窗口
![](https://i-blog.csdnimg.cn/blog_migrate/c626ad5332afdce590fe62e1fdf668da.png)
步骤四:这里就是函数库中要找函数的实现代码
![](https://i-blog.csdnimg.cn/blog_migrate/dbf2ebd5dd1780dd0a9af9970192fc77.png)
2.通过上面方法找到的.c源文件其实是vs编译器给出的参考代码(有些函数可能编译器没有给出参考代码,因此找不到.c文件),代码中真正使用函数时通过头文件包含进行调用,其实是从静态库中进行调用的(从msdn等地方可以查到对应函数静态库名字,如下图)
4.strcmp函数
4.1.strcmp函数介绍
int strcmp ( const char * str1 , const char * str2 );
返回:从起始地址开始比较:第一个字符串大于第二个字符串,则返回大于 0 的数字第一个字符串等于第二个字符串,则返回 0第一个字符串小于第二个字符串,则返回小于 0 的数字功能:比较对应位置上的字符大小
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[30]="abcdef";
char arr2[]="abq";
int ret=strcmp(arr1,arr2);
printf("%d\n",ret);
return 0;
}
4.2.strcmp函数模拟实现
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char* str1, const char*str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
if (*str1 > *str2)
return 1;
else
return -1;
}
int main()
{
char arr1[] = "abc";
char arr2[] = "abc";
int ret = my_strcmp(arr1, arr2);
if (ret<0)
{
printf("arr1<arr2");
}
else if (ret >0)
{
printf("arr1>arr2");
}
else
{
printf("arr1==arr2");
}
return 0;
}
注:
此处,在主函数打印时,一定不能用-1、1、0进行判断,因为标准规定返回值是一个>0、<0、=0的值(其他编译器就不一定是只返回-1、1、0三个了数字),下面就是错误的例子。
模拟实现2:
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char* str1, const char*str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
char arr1[] = "abc";
char arr2[] = "abc";
int ret = my_strcmp(arr1, arr2);
if (ret<0)
{
printf("arr1<arr2");
}
else if (ret >0)
{
printf("arr1>arr2");
}
else
{
printf("arr1==arr2");
}
return 0;
}
5.strncpy函数
char * strncpy ( char * destination , const char * source , size_t num );
拷贝 num 个字符从源字符串到目标空间如果源字符串的长度小于 num ,则拷贝完源字符串之后,在目标的后边追加\ 0 ,直到 num 个
代码1:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1="xxxxxxxxxxxxxxxx";
char arr2[]="hello word";
strncpy(arr1,arr2,5);
printf("%s\n",arr1);
return 0;
}
运行结果1:
代码2:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "xxxxxxxxxxxxxx";
char arr2[] = "he";
strncpy(arr1, arr2, 5);
printf("%s\n", arr1);
return 0;
}
运行结果2:
运行调试2:
6.strncat函数
char * strncat ( char * destination , const char * source , size_t num );
strncat函数对目标字符串进行追加,有两种情况1. 若源字符串的长度小于等于 num: 遇到源字符串的\0停止,只将源字符串进行追加完即可(与strncpy函数不同)2. 若源字符串的长度大于 num:追加源字符串的num个字符,然后在追加的最后一个字符后面补一个\0
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20]="hello";
char arr2[]="word";
strncat(arr1,arr2,5);
printf("%s\n",arr1);
return 0;
}
运行结果1:
代码2:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "hello";
char arr2[] = "word";
strncat(arr1, arr2, 2);
printf("%s\n", arr1);
return 0;
}
运行结果2:
代码3:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "hello\0xxxxxxxxx";
char arr2[] = "word";
strncat(arr1, arr2, 3);
printf("%s\n", arr1);
return 0;
}
运行结果3:
运行调试3:
代码4:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "hello\0xxxxxxxxx";
char arr2[] = "word";
strncat(arr1, arr2, 7);
printf("%s\n", arr1);
return 0;
}
运行结果4:
运行调试4:
7.strncmp函数
int strncmp ( const char * str1 , const char * str2 , size_t num );
标准规定:第一个字符串大于第二个字符串,则返回大于 0 的数字第一个字符串等于第二个字符串,则返回 0第一个字符串小于第二个字符串,则返回小于 0 的数字
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[]="abcdef";
char arr2[]="abcqqqqqq";
int ret=strncmp(arr1,arr2,3);
printf("%d\n",ret);
return 0;
}
运行结果1:
代码2:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[]="abcdef";
char arr2[]="abcqqqqqq";
int ret=strncmp(arr1,arr2,4);
printf("%d\n",ret);
return 0;
}
运行结果2:
代码3:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcwef";
char arr2[] = "abcqqqqqq";
int ret = strncmp(arr1, arr2, 4);
printf("%d\n", ret);
return 0;
}
运行结果3:
8.strstr函数
8.1.strstr函数介绍
char * strstr ( const char * str1 , const char * str2 );
功能:在str1字符串中找str2字符串。若找到str2了,返回str2第一次出现的起始地址;若找不到str2,返回一个空指针。
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[]="abcdefabcdef";
char arr2[]="bcd";
char* ret=strstr(arr1,arr2);
if(NULL==ret)
printf("没找到\n");
else
printf("%s\n",ret);
return 0;
}
运行结果1:
![](https://i-blog.csdnimg.cn/blog_migrate/9ad5140f2e3f62bf2888f25710f1bc39.png)
代码2:
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdefabcdef";
char arr2[] = "bcdq";
char* ret = strstr(arr1, arr2);
if (NULL == ret)
printf("没找到\n");
else
printf("%s\n", ret);
return 0;
}
运行结果2:
![](https://i-blog.csdnimg.cn/blog_migrate/1f903e5620fd3dda31a161aaaa12fec9.png)
8.2.strstr函数模拟实现
模拟实现:
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(const char* str, const char* substr)
{
const char* s1 = str;
const char* s2 = substr;
const char* cur = str;
assert(str && substr);
if (*substr == '\0')
{
return (char*)str;
}
while (*cur)
{
s1 = cur;
s2 = substr;
while (*s1!='\0' && *s2!='\0' && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return (char*)cur;
cur++;
}
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;
}
9.strtok函数
char * strtok ( char * str , const char * sep );
参数:第一个参数指定一个字符串,它包含了 0 个或者多个由 sep 字符串中一个或者多个分隔符分割的标记。第二个参数sep 参数是个字符串,定义了用作分隔符的字符集合返回:返回一个指向这个标记所分割的字符串的地址(首元素地址)功能:strtok 函数找到 str 中的下一个标记,并将其用\0代替,返回一个指向这个标记所分割的字符串的地址(首元素地址)。(注:strtok函数会改变被操作的字符串,所以在使用 strtok 函数切分的字符串一般都是临时拷贝的内容并且可修改)strtok 函数的第一个参数不为 NULL ,函数将找到 str 中第一个标记, strtok 函数将保存它在字符串中的位置。(strtok函数找第一个标记的时候,函数的第一个标记不是NULL)strtok 函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。(strtok函数找非第一个标记的时候,函数的第一个标记是NULL)如果字符串中不存在更多的标记,则返回 NULL 指针。注:strtok函数内部会有一个静态变量(static修饰的变量),来保存上一次标记的位置
#include <stdio.h>
#include <string.h>
int main()
{
const char* p = "@.";
char arr[] = "zpengwei@yeah.net";
char buf[50] = { 0 };
strcpy(buf, arr);
char* str = NULL;
str = strtok(buf, p);
printf("%s\n", str);
str = strtok(NULL, p);
printf("%s\n", str);
str = strtok(NULL, p);
printf("%s\n", str);
return 0;
}
运行结果1:
代码2:
#include <stdio.h>
#include <string.h>
int main()
{
const char* p = "@.#";
char arr[] = "zpengwei@yeah.net#hehe";
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;
}
运行结果2:
![](https://i-blog.csdnimg.cn/blog_migrate/33ccc8171c65755e4c0262235baa2fbf.png)
10.strerror函数
char * strerror ( int errnum );
参数:错误码返回:错误码所对错误信息的起始地址功能:strerror函数可以把错误码翻译成错误信息
#include <stdio.h>
#include <string.h>
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%s\n", strerror(i));
}
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/fc8ded08b1d524f6e7e42d2dc59bd13e.png)
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main()
{
//打开文件
FILE* pf = fopen("test.txt", "r");
if (NULL == pf)
{
//出错误的原因是什么
printf("%s\n", strerror(errno));
return 0;
}
//读文件
//...
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}
运行结果2:
![](https://i-blog.csdnimg.cn/blog_migrate/8bbdbd8a85a0ab85f4374476a58b8a52.png)
注:
![](https://i-blog.csdnimg.cn/blog_migrate/722c4ae831098d267ebaecbfdc44f07c.png)
第一个参数:文件名(在工程路径下寻找)
第二个参数:打开文件的方式(具体方式msdn上有,下面给出一个方式)
返回:返回一个指针,指向找到的文件。如果遇到一个错误的话,返回一个空指针
2.当库函数使用的时候,发生错误会把errno这个全局的错误变量设置为本次执行库函数产生的错误码。errno是c语言提供的一个全局变量,可以直接使用,放在errno.h文件中
3.使用errno时,需要包含errno.h的头文件
4.fopen,fclose这些函数后期会专门进行讲解
11.字符分类函数
函数参数:一个字符
函数返回值:如果符合返回一个非零值(真),如果不符合返回0(假)
注:使用该系列函数,需要包含ctype.h头文件
函数 |
如果他的参数符合下列条件就返回真
|
iscntr
|
任何控制字符
|
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
|
任何可打印字符,包括图形字符和空白字符
|
代码:
#include <stdio.h>
#include <string.h>
int main()
{
printf("%d\n", isspace(' '));
printf("%d\n", isspace('!'));
return 0;
}
运行结果:
12.字符转换函数
将大写字母转换成小写字母函数: int tolower ( int c );将小写字母转换成大写字母函数: int toupper ( int c );
代码:
#include <stdio.h>
#include <string.h>
int main()
{
char ch = 0;
ch = getchar();
if (islower(ch))
{
ch = toupper(ch);
}
else
{
ch = tolower(ch);
}
printf("%c\n", ch);
return 0;
}
运行结果:
13.memcpy函数
13.1.memcpy函数介绍
void * memcpy ( void * destination , const void * source , size_t num );
参数:void * destination:要拷贝的目标内存地址const void * source:要拷贝的源内存地址size_t num:拷贝字节个数,单位是字节返回:要拷贝的目标内存地址功能:内存拷贝函数,以字节为单位进行拷贝(拷贝的源和目标不可以重叠)c语言的memcpy函数的功能规定是拷贝不重叠的内存空间(vs编译器中的库函数memcpy超纲完成任务,其可以拷贝重叠的内存空间)注:函数 memcpy 从 source 的位置开始向后复制 num 个字节的数据到 destination 的内存位置。这个函数在遇到 '\0' 的时候并不会停下来。如果 source 和 destination 有任何的重叠,复制的结果都是未定义的。
#include <stdio.h>
#include <string.h>
int main()
{
int arr3[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr4[5] = { 0 };
memcpy(arr4, arr3, 5*sizeof(arr3[0]));
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d\n", arr4[i]);
}
return 0;
}
运行结果:
13.2.memcpy函数模拟实现
模拟实现:(只模拟c语言memcpy函数本身规定的功能,不去模拟内存重叠拷贝功能,与vs库中的memcpy有一定区别)
#include <stdio.h>
#include <string.h>
#include<assert.h>
void* my_memcpy(void* dest, const void*src, size_t num)
{
void* ret = dest;
assert(dest && src);
while (num--)
{
*(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*sizeof(arr3[0]));
int i = 0;
for (i = 0; i < 5; i++)
{
printf("%d ", arr4[i]);
}
return 0;
}
注:
1.该模拟代码有一定问题,比如要想将上面代码arr3数组的1 2 3 4 5拷贝到3 4 5 6 7位置处,预期是1 2 1 2 3 4 5 8 9 10,但上面代码的拷贝结果如下图所示。(出现问题的原因是:拷贝的源字符串和目标字符串有重叠的部分)
2.如果拷贝的源字符串和目标字符串有重叠的部分,我们就不能再用memcpy函数了,应该使用下面的memmove函数
14.memmove函数
14.1.memmove函数介绍
void * memmove ( void * destination , const void * source , size_t num );
参数:void * destination:要拷贝的目标内存地址const void * source:要拷贝的源内存地址size_t num:拷贝字节个数,单位是字节返回:要拷贝的目标内存地址功能:内存拷贝函数,以字节为单位进行拷贝(拷贝的源和目标可以重叠可以不重叠)c语言的memmove函数的功能是拷贝重叠或不重叠的内存空间注:和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。如果源空间和目标空间出现重叠,就得使用memmove函数处理。memmove函数的功能包含了memcpy函数
#include <stdio.h>
#include <string.h>
int main()
{
int arr3[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr4[5] = { 0 };
memmove(arr3+2, arr3, 5*sizeof(arr3[0]));
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr3[i]);
}
return 0;
}
运行结果:
14.2.memmove函数模拟实现
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
void* ret = dest;
assert(dest && src);
if (dest < src)
{
//前->后
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 };
int arr4[5] = { 0 };
memmove(arr3+2, arr3, 5*sizeof(arr3[0]));
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr3[i]);
}
return 0;
}
模拟实现的运行结果:
![](https://i-blog.csdnimg.cn/blog_migrate/960782f950251dbda2c90f2a62cee310.png)
15.memcmp函数
int memcmp ( const void * ptr1 , const void * ptr2 , size_t num );
参数:const void * ptr1:想比较的第一个内存块的起始地址const void * ptr2:想比较的第二个内存块的起始地址size_t num:从起始位置开始想比较的字节数返回:从起始地址开始比较:第一个内存块大于第二个内存块,则返回大于0 的数字第一个内存块等于第二个内存块,则返回0第一个内存块小于第二个内存块,则返回小于0的数字功能:比较从 ptr1 和 ptr2 指针开始的 num 个字节
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[]={1,2,7,4,5};
int arr2[]={1,2,3,4,5};
int ret=memcmp(arr1,arr2,9);
printf("%d\n",ret);
return 0;
}
运行结果1:
代码2:
#include <stdio.h>
#include <string.h>
int main()
{
int arr1[] = { 1,2,3,4,5 };
int arr2[] = { 1,2,3,4,5 };
int ret = memcmp(arr1, arr2, 9);
printf("%d\n", ret);
return 0;
}
运行结果2:
![](https://i-blog.csdnimg.cn/blog_migrate/fead4cd0bd8689d18d992ef2aba850a3.png)
16.memset函数
void* memset ( void * dest , int c , size_t count)
参数:void * dest:要设置的目的地起始地址int c:要设置的内容,以字节为单位size_t count:要设置的字节的个数返回:目的地地址功能:对一段内存块以字节为单位置入内容
#include <stdio.h>
#include <string.h>
int main()
{
char arr[20]={0};
memset(arr,'x',10);
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/bad31c7cee485a1d5ad5c3ae92698787.png)
代码2:
#include <stdio.h>
#include <string.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
memset(arr, 0, 10);
return 0;
}
调试结果2:
![](https://i-blog.csdnimg.cn/blog_migrate/6d74a691f7fb718a01cb1a9ffea55624.png)