目录
函数介绍:
字符串函数:
strlen
一道迷惑笔试题:
strcpy
strcat
strcmp
strncpy
strncat
strncmp
strstr
strtok
strerror
字符分类函数:
iscntrl
isspace
isdigit
isxdigit
islower
isupper
isalpha
isalnum
ispunct
isgraph
isprint
tolower
toupper
内存函数:
memcpy
memmove
memcmp
memset
库函数的模拟实现
模拟实现strlen
模拟实现strcpy
模拟实现strcat
模拟实现strstr
模拟实现strcmp
模拟实现memcpy
模拟实现memmove
对C语言中的几个常用的库函数进行解释说明
并彻底了解如何使用
了解原理,并进行模拟实现
函数介绍:
字符串函数:
strlen
计算字符串长度函数
函数原型:size_t strlen(const char* str)
返回值:size_t 就是 unsigned int 无符号整型
返回的是'\0‘之前字符的个数
参数:const char* str
是一个char*的指针 且用const修饰
const修饰的是*str
表示指针指向的内容是不可被修改的
函数作用:计算的是字符串长度
计算'\0'之前字符的个数
函数的用途:看以下代码:
#include <stdio.h> #include <string.h>int main() {//创建一个数组 用来封装字符串char str[] = "abcdefghjk";//调用strlen函数,用一个size_t 无符号整型来接收//将str数组名表示首元素地址,也就是字符串的首地址传过去size_t len = strlen(str);//打印,从传过去的位置开始,遇到'\0'之前,字符的个数printf("%u\n", len);return 0; }
一道迷惑笔试题:
#include <stdio.h> #include <string.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");}//在判断的时候,strlen(str2)的值为3 //strlen(str1)的值为6 //而 3 和 6 都是size_t类型 //3-6 的实际结果为:-3 // -3 : // 原码:10000000 00000000 00000000 00000011 // 反码:11111111 11111111 11111111 11111100 // 补码:11111111 11111111 11111111 11111101 // //但因为是无符号整型,将-3的补码实际解读的时候 //是按照无符号数来解读的,因为正数的 原码,反码,补码相同 //所以将-3的补码当做原码解读,是一个很大的数 //该数必定大于0 所以必定指向if里面的语句return 0; }
解析:
答案:str2>str1
在判断的时候,strlen(str2)的值为3
strlen(str1)的值为6
而 3 和 6 都是size_t类型
3-6 的实际结果为:-3
-3 :
原码:10000000 00000000 00000000 00000011
反码:11111111 11111111 11111111 11111100
补码:11111111 11111111 11111111 11111101
但因为是无符号整型,将-3的补码实际解读的时候
是按照无符号数来解读的,因为正数的 原码,反码,补码相同
所以将-3的补码当做原码解读,是一个很大的数
该数必定大于0 所以必定指向if里面的语句
strcpy
字符串拷贝函数
函数原型:char * strcpy ( char * destination, const char * source );
参数:char * destination, const char * source
将source 指向的字符串复制到destination指向的数组中
包括终止字符'\0’也要赋值过去
返回值:char*
返回的是sourec指向的那一片空间的地址
函数作用:将源头src指向字符串的内容赋值到目的地dest指向字符串中
在赋值的时候会将字符'\0’也赋值过去
为避免溢出,destination指向的数组的大小应足够长
以包含与source相同的字符串(包括终止空字符),
并且不应与source在内存中重叠。
函数的使用:看以下代码:
#include <stdio.h> #include <string.h>int main() {//将str2的内容拷贝到str1中//拷贝的时候会将'\0'也拷贝过去//str1的空间要足够大要装的下str2的内容!char str1[20] = "zzzzzzzzzzzzzz";char str2[] = "abcde";strcpy(str1, str2);printf("%s\n", str1);//将s2的内容拷贝到s1中//拷贝的时候会将'\0'也拷贝过去//s1的空间要足够大要装的大s2的内容char s1[] = "xxxxxxxxxx";char s2[] = "fghijk";strcpy(s1, s2);printf("%s\n", s1);//将p2指向的常量字符串的内容拷贝到p2中//拷贝的时候会将'\0'也拷贝过去//p1的空间要足够大要装的大p2的内容char p1[20] = "yyyyyyyyyyyyyyyyyy";char* p2 = "lmnopq";strcpy(p1, p2);printf("%s\n", p1);return 0; }
strcat
字符串追加函数
函数原型:char * strcat ( char * destination, const char * source );
返回值:char*
返回的是追加完成之后
destination的首地址
参数:char * destination, const char * source
destination是目的地字符串的首地址
source 是源头字符串的首地址
函数作用:
将source指向的字符串内容
追加到destination指向的字符串后面
追加时:destination中的'\0'被source的第一个字符覆盖
destination指向的空间要足够大
要容纳下追加之后的新字符串
函数用途:看以下代码
#include <stdio.h> #include <string.h>int main() {//将str2的内容追加到str1的后面//在追加的时候str1最后的‘\0’字符被str2的第一个字符覆盖//然后进行追加,追加时会将str2的'\0'也追加进去//str1的空间要足够大,要能容纳下追加后的新字符串char str1[50] = "abcdefg";char str2[] = "hijklmn";strcat(str1, str2);printf("%s\n", str1);//将p2指向的常量字符串内容追加到p1的后面//追加时p1的'\0'字符被p2的首字符覆盖//追加时会将p2的'\0'也追加进去//p1的空间要足够大,能容纳下追加后的新字符串char p1[20] = "abc";char* p2 = "defgk";strcat(p1, p2);printf("%s\n", p1);return 0; }
strcmp
字符串比较函数
函数原型:int strcmp ( const char * str1, const char * str2 );
返回值:int
返回的是一个有符号整型数
可返回负数,0,正数
参数:const char * str1, const char * str2
str1指向一个字符串,
str1里面存放的是字符串的首地址
用const修饰说明字符串的内容不可被修改
str2也指向一个字符串,
str2里面存放的是字符串的首地址
用const修饰说明字符串的内容不可被修改
函数的作用:
str1字符串与str2字符串从首字符的位置开始
一个字符一个字符对应向后一一比较,
在比较字符的时候比较的是其ASCII码值,
若对应比较两个字符相等则一直向后比较,
直到碰到字符不等的情况就停止比较,
然后返回这两个不等字符的比较结果,
当str1的字符大于str2的字符 则返回大于0的数字,
若两个字符串比较完了,各字符都相同,
且长度相等的情况下,则这两个字符串相等
str1等于str2时返回0,
str1的字符小于str2的字符时 返回小于0的数
函数用途:如下代码:
#include <stdio.h> #include <string.h>int main() {//字符串比较//str1 与 str2 进行比较//从首字符开始向后一一比较//在比较的时候比较的是字符的ASCII码值//若对应的字符相等,则继续向后比较//若不等,则停止比较,返回他们的比较结果//若两个字符串比较完都相等,且长度一样长,说明str2和str2相等//返回值://第一个字符串大于第二个字符串,则返回大于0的数字//第一个字符串等于第二个字符串,则返回0//第一个字符串小于第二个字符串,则返回小于0的数字char str1[] = "abcde";char str2[] = "abcfk";int n = strcmp(str1, str2);if (n == 0){printf("str1 == str2");}else if (n > 0){printf("str1 > str2");}else{printf("str1 < str2");}return 0; }
strncpy
字符串拷贝函数(指定字节数拷贝)
函数原型:char * strncpy ( char * destination, const char * source, size_t num );
返回值:char *
返回的是一个char* 的指针
返回的是拷贝完成后的destination指向的空间
参数:char * destination, const char * source, size_t num
目的地字符串:
destination 是指向一个字符串空间的指针
源头字符串:
soure是一个指向一个字符串空间的指针
const修饰说明soure指向的字符串不可被修改
num是一个sizt_t 无符号整型的数字
函数的作用:
将soure指向的字符串中num个字节的内容
复制到destination指向的字符串空间
如果source指向的字符串的长度小于num,
则拷贝完源字符串之后,在目标的后边追加0,
直到追加够num个结束
destination 指向的空间要足够大
至少能容纳下拷贝后新的字符串
函数用途:如下代码:
#include <stdio.h> #include <string.h>int main() {//拷贝num个字符从源字符串到目标空间。//如果源字符串的长度小于num,则拷贝完源字符串之后,//在目标的后边追加0,直到num个char str1[] = "yyyyyyyyyyyyyyyyyyy";char str2[] = "hello";strncpy(str1, str2, 5);printf("%s\n", str1);//当s2的长度<num时char s1[] = "xxxxxxxxxxxxxxxxxxxxxx";char s2[] = "abcd";strncpy(s1, s2, 6);printf("%s\n", s1);char p1[20] = "zzzzzzzzzzzzzzzzzzz";char* p2 = "efgh";strncpy(p1, p2, 5);printf("%s\n", p1);return 0; }
strncat
字符串追加函数(指定字节数追加)
函数原型:char * strncat ( char * destination, const char * source, size_t num );
返回值:char *
返回的是一个char*的指针
返回追加完成之后destination指向的空间
参数:char * destination, const char * source, size_t num
目的地字符串:
destination 是指向一个字符串空间的指针
源头字符串:
soure是一个指向一个字符串空间的指指针
const修饰 说明soure指向的字符串不可被修改
num是一个sizt_t 无符号整型的数字
函数的作用:
将soure指向的字符串中num个字节的内容
追加到destination指向的字符串空间
destination指向字符串的最后的'\0'字符
会被soure指向的字符串的首字符所覆盖
如果source指向的字符串的长度大于num,
则追加完num个字符之后,在后边自动加上'\0'
如果source指向的字符串的长度小于num,
则只追加完source指向的字符串内容(包含'\0’)
就结束结束追加
destination 指向的空间要足够大
至少能容纳下追加后新的字符串
函数用途:如下代码:
#include <stdio.h> #include <string.h>int main() {//str2 大于 num 的情况//会自动在末尾加上'\0'//在追加的时候,str1的'\0'会被str2的首字符所覆盖char str1[50] = "uvwxy";char str2[] = "abcdefg";strncat(str1, str2, 5);printf("%s\n", str1);//str2 小于 num 的情况//只追加完str2包含'\0’字符就结束追加//在追加的时候,s1的'\0'会被s2的首字符所覆盖char s1[50] = "wasche";char s2[] = "hello world";strncat(s1, s2, 13);printf("%s\n", s1);return 0; }
strncmp
字符串比较函数(指定字节数比较)
函数原型:int strncmp ( const char * str1, const char * str2, size_t num );
返回值:int
返回的是一个有符号整型数
可返回负数,0,正数
参数:const char * str1, const char * str2, size_t num
str1指向一个字符串,
str1里面存放的是字符串的首地址
用const修饰说明字符串的内容不可被修改
str2也指向一个字符串,
str2里面存放的是字符串的首地址
用const修饰说明字符串的内容不可被修改
num是一个无符号整数,表示字节数
函数的作用:
对str1和str2字符串,指定num个字节进行比较
str1字符串与str2字符串从首字符的位置开始
比较到num个字节结束
一个字符一个字符对应向后一一比较,
在比较字符的时候比较的是其ASCII码值,
若对应比较两个字符相等则一直向后比较,
直到碰到字符不等的情况就停止比较,
然后返回这两个不等字符的比较结果,
当str1的字符大于str2的字符 则返回大于0的数字,
若两个字符串比较num个字节之后,
各字符都相同,则这两个字符串相等
str1等于str2时返回0,
str1的字符小于str2的字符时 返回小于0的数
若字符串的长度小于num,则比较完字符'\0'就结束比较
函数用途:如下代码:
#include <stdio.h> #include <string.h>int main() {char str1[] = "abcdefghijklm";char str2[] = "abcdefgxyz";//比较前六个字符是否相等int n = strncmp(str1, str2, 6);if (n == 0){printf("str1 == str2\n");}else if (n > 0){printf("str1 > str2\n");}else{printf("str1 < str2\n");}//比较前8个字符是否相等n = strncmp(str1, str2, 8);if (n == 0){printf("str1 == str2\n");}else if (n > 0){printf("str1 > str2\n");}else{printf("str1 < str2\n");}//比较前11个字符是否相等n = strncmp(str1, str2, 11);if (n == 0){printf("str1 == str2\n");}else if (n > 0){printf("str1 > str2\n");}else{printf("str1 < str2\n");}return 0; }
strstr
字符串找子串函数
函数原型:char * strstr ( const char *str1, const char * str2);
返回值:char *
返回一个字符指针
返回找到子串的首字符的地址找不到返回NULL
参数:const char *str1, const char * str2
str1指向一个字符串,
str1里面存放的是字符串的首地址
用const修饰说明字符串的内容不可被修改
str2也指向一个字符串,
str2里面存放的是字符串的首地址
用const修饰说明字符串的内容不可被修改
函数的作用:
寻找在str1指向的常量字符串里
是否包含str2指向的字符串
若包含则返回str2第一次出现的地址
若不包含则返回NULL
函数用途:如下代码:
#include <stdio.h> #include <string.h>int main() {//查找str2是否是str1的子串//若是则返回str2第一次出现的位置//若不是则返回NULLchar str1[] = "abcdefgjklcdefgmn";char str2[] = "cdef";char* p = strstr(str1, str2);if (p == NULL){printf("str2 不是 str1 的子串\n");}else{printf("str2 是 str1 的子串\n");//用%s打印的时候会从str2在str1中第一次出现的位置开始,直到遇到'\0'结束printf("%s\n", p);}return 0; }
strtok
字符串分割函数
函数原型:char * strtok ( char * str, const char * sep );
返回值:char *
返回一个字符指针
返回用分割符号分割后字符串的首地址
参数:char * str, const char * sep
str是一个指向要被分割的字符串的空间
sep指向的是分割符号的字符串空间
用const修饰说明sep指向的内容不可被修改
函数的作用:
sep里面传过来的是分隔符的字符串
在第一次调用的时候
str里面传过来的是要被分割字符串的首地址
在查找分隔符的时候会将分隔符的位置改为'\0'
在第二次调用的时候
str里面传入一个空指针,
此时查找分隔符的位置会在第一次分隔符的下一个字符开始查找
会找到下一个分隔符,再将分隔符的位置改为'\0‘
以此类推有几个分隔符就查找几次
sep参数是个字符串,定义了用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
strtok函数找到str中的下一个标记,并将其用 \0 结尾,
返回一个指向这个标记的指针。
(注:
strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串
一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,
strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,
查找下一个标记。
如果字符串中不存在更多的标记,则返回 NULL 指针函数用途:如下代码:
#include <stdio.h> #include <string.h>int main() {char str[] = "hello@world&string#strtok";//被分割的字符串char ep[] = "@&#";//分隔符字符串//第一次调用 会将找到的分割符的位置改为'\0'char* p = strtok(str, ep);printf("%s\n", p);//第二次调用传入空指针 会将找到的分割符的位置改为'\0'p = strtok(NULL, ep);printf("%s\n", p);//第三次调用也传入空指针 会将找到的分割符的位置改为'\0'p = strtok(NULL, ep);printf("%s\n", p);//第四次调用也传入NULL 会将找到的分割符的位置改为'\0'p = strtok(NULL, ep);printf("%s\n", p);上述我们打印分割的字符串总共调用了四次代码写的有点繁琐,我们可以用一个for循环直接调用打印//char* ret = NULL;//for (ret = strtok(str, ep);ret!=NULL; ret = strtok(NULL, ep))//{// printf("%s\n", ret);//}return 0; }
strerror
获取错误信息函数
函数原型:char * strerror ( int errnum );
返回值:char *
返回一个字符指针
返回的是错误信息是字符串
参数:int errnum
参数是一个整数
传入的是一个错误码
函数的作用:
返回一个字符串,而这个字符串
就是一串错误信息
而参数是一个整数,是一个错误码
每一个错误码都有一个对应的错误信息
函数用途:如下代码:
#include <stdio.h> #include <string.h> #include <errno.h>int main() {//随便传入一个错误码,打印出其错误信息printf("%s\n", strerror(12));//具体应用//FILE是一个文件指针,fopen是打开文件//在当前目录下打开text.txt文件进行读操作//若打开失败返回NULLFILE* pf = fopen("text.txt", "r");if (pf == NULL){printf("打开失败错误信息为:%s",strerror(errno));}else{printf("打开成功\n");}return 0; }
字符分类函数:
头文件包含:#include <ctype.h>
iscntrl
字符控制函数
函数原型:int iscntrl ( int c );
函数的作用:
传入一个字符,
判断是否是控制字符
若是则返回非0数(也就是ture)
若不是则返回0(也就是false)
函数用途:
#include <stdio.h> #include <string.h>int main() {char c = 0;scanf("%c", &c);int ret = iscntrl(c);if (ret == 0){printf("%c不是控制字符\n", c);}else{printf("%c 是控制字符\n", c);}return 0; }
isspace
空白字符:‘空格’,‘\f’换页,'\n'换行,
'\r'回车,制表符‘\t’,垂直制表符'\v'
函数原型:int isspace ( int c );
函数作用:
传入一个字符,
判断是否是空白字符
若是则返回非0数(也就是ture)
若不是则返回0(也就是false)
函数用途:
#include <stdio.h> #include <ctype.h>int main() {//空白字符:‘空格’,‘\f’换页,'\n'换行,'\r'回车,制表符‘\t’,垂直制表符'\v'char c = '\n';int ret = iscntrl(c);if (ret == 0){printf("%c不是空白字符\n", c);}else{printf("%c 是空白字符\n", c);}return 0; }
isdigit
十进制数字0~9
函数原型:int isdigit ( int c );
函数作用:
传入一个字符,
判断是否是0~9的字符
若是则返回非0数(也就是ture)
若不是则返回0(也就是false)
函数用途:
#include <stdio.h> #include <ctype.h>int main() {char c = 0;scanf("%c", &c);int ret = isdigit(c);if (ret == 0){printf("%c不是0~9字符\n", c);}else{printf("%c 是0~9字符\n", c);}return 0; }
isxdigit
十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A~F 函数原型:int isdigit ( int c );
函数作用:
传入一个字符,
判断是否是十六进制数
小写字母a~f,大写字母A~F的字符
若是则返回非0数(也就是ture)
若不是则返回0(也就是false)
函数用途:
#include <stdio.h> #include <ctype.h>int main() {char c = 0;scanf("%c", &c);int ret = isxdigit(c);if (ret == 0){printf("%c NO is 十六进制\n", c);}else{printf("%c YES 十六进制\n", c);}return 0; }
islower
小写字母:a~z
函数原型:int islower ( int c );
函数作用:
传入一个字符,
判断是否是小写字母:a~z
若是则返回非0数(也就是ture)
若不是则返回0(也就是false)
函数用途:
#include <stdio.h> #include <ctype.h>int main() {char c = 0;scanf("%c", &c);int ret = islower(c);if (ret == 0){printf("%c NO is 小写字母\n", c);}else{printf("%c YES 小写字母\n", c);}return 0; }
isupper
大写字母A~Z
函数原型:int isupper ( int c );
函数作用:
传入一个字符,
判断是否是大写字母:A~Z
若是则返回非0数(也就是ture)
若不是则返回0(也就是false)
函数用途:
#include <stdio.h> #include <ctype.h>int main() {char c = 0;scanf("%c", &c);int ret = isupper(c);if (ret == 0){printf("%c NO is 大写字母\n", c);}else{printf("%c YES 大写字母\n", c);}return 0; }
isalpha
字母a~z或者A~Z
函数原型:int isalpha ( int c );
函数作用:
传入一个字符,
判断是否是大写或者小写字母
若是则返回非0数(也就是ture)
若不是则返回0(也就是false)
函数用途:
#include <stdio.h> #include <ctype.h> int main() {char c = 0;scanf("%c", &c);int ret = isalpha(c);if (ret == 0){printf("%c NO is 字母\n", c);}else{printf("%c YES 字母\n", c);}return 0; }
isalnum
字母或者数字,A~Z ,a~z,0~9
函数原型:int isalnum ( int c );
函数作用:
传入一个字符,
判断是否是
大写或者小写字母或者是数字字符
若是则返回非0数(也就是ture)
若不是则返回0(也就是false)
函数用途:
#include <stdio.h> #include <ctype.h> int main() {char c = 0;scanf("%c", &c);int ret = isalnum(c);if (ret == 0){printf("%c NO is 字母或数字\n", c);}else{printf("%c YES 字母或数字\n", c);}return 0; }
ispunct
标点符号,任何不属于数字或者字母的图形字符(可打印)
函数原型:int ispunct ( int c );
函数作用:
传入一个字符,
判断是否是
不属于数字或者字母的图形字符
若是则返回非0数(也就是ture)
若不是则返回0(也就是false)
函数用途:
#include <stdio.h> #include <ctype.h> int main() {char c = 0;scanf("%c", &c);int ret = ispunct(c);if (ret == 0){printf("%c NO is 它属于数字或字母\n", c);}else{printf("%c YES 它不属于字母或数字\n", c);}return 0; }
isgraph
任何图形字符
函数原型:int isgraph ( int c );
函数作用:
传入一个字符,
判断是否是图形字符
若是则返回非0数(也就是ture)
若不是则返回0(也就是false)
函数用途:
#include <stdio.h> #include <ctype.h> int main() {char c = 0;scanf("%c", &c);int ret = isgraph(c);if (ret == 0){printf("%c NO is 它不是图形字符\n", c);}else{printf("%c YES 它是图形字符\n", c);}return 0; }
isprint
任何可打印字符,包括图形字符和空白字符
函数原型:int isprint ( int c );
函数作用:
传入一个字符,
判断是否是可打印的字符
包含图形字符和空白字符
若是则返回非0数(也就是ture)
若不是则返回0(也就是false)
函数用途:
#include <stdio.h> #include <ctype.h> int main() {char c = 0;scanf("%c", &c);int ret = isprint(c);if (ret == 0){printf("%c NO is 它不是可打印的字符\n", c);}else{printf("%c YES 它是可打印的字符\n", c);}return 0; }
tolower
字母大写转小写
函数原型:int tolower ( int c );
函数作用:
传入一个字符,
判断是否是大写字母A~Z
若是将其转为对应小写字母
函数用途:
#include <stdio.h> #include <ctype.h> #include <string.h>int main() {//将字符串的大写字母全部转为小写字母char str[] = "abcDEfGjK";int i = 0;for (i = 0; i < strlen(str); i++){if (isupper(str[i])!=0)//判断是否是大写字母{str[i] = tolower(str[i]);//大写转小写}}printf("%s\n", str);return 0; }
toupper
字母小写转大写
函数原型:int toupper ( int c );
函数作用:
传入一个字符,
判断是否是小写字母a~z
若是将其转为对应大写字母
函数用途:
#include <stdio.h> #include <ctype.h> #include <string.h>int main() {//将字符串的小写字母全部转为大写字母char str[] = "abcDEfGjK";int i = 0;for (i = 0; i < strlen(str); i++){if (islower(str[i])!=0)//判断是否是小写字母{str[i] = toupper(str[i]);//小写转大写}}printf("%s\n", str);return 0; }
内存函数:
memcpy
内存拷贝函数
函数原型:void * memcpy ( void * destination, const void * source, size_t num );
返回值:void *
返回值是一个任意类型的指针
返回拷贝好的内存空间的起始地址
参数:void * destination, const void * source, size_t num
目的地:
destination是一个任意类型的指针
源头:
source是一个任意类型的指针
用const修饰,
说明source指向的内存空间的内容不可修改
字节数:
num是一个无符号整型
函数的作用:
将source 指向的空间
里面的num个字节的数据
复制到destination指向的空间中
返回值,返回的是:
拷贝好之后 destination指向的空间的地址
destination指向的内存空间要足够大
至少能容纳下拷贝之后的数据
这个函数遇到'\0'时根本就不会停下来
直到拷贝够num字节数就停止
memcpy函数不能胜任重叠拷贝
自己拷贝自己
函数用途:如下代码:
#include <stdio.h> #include <string.h>// 定义结构体 struct {char name[40];int age; } person, person_copy; //创建结构体全局变量 person,和 per_copyint main() {char myname[] = "Pierre de Fermat";//创建一个字符串//将myname整个字符串的内容,拷贝到结构体变量person 的成员变量 name 空间中memcpy(person.name, myname, strlen(myname) + 1);//再给变量person的成员变量 age 赋值为46person.age = 46;//将变量person 的空间的内容,全部拷贝 到变量 person_copy的空间中memcpy(&person_copy, &person, sizeof(person));//将变量 person_copy 空间中的内容打印出来 printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);return 0; }
memmove
内存拷贝函数(指定字节数)
函数原型:void * memmove ( void * destination, const void * source, size_t num );
返回值:void *
返回值是一个任意类型的指针
返回拷贝好的内存空间的起始地址
参数:void * destination, const void * source, size_t num
目的地:
destination是一个任意类型的指针
源头:
source是一个任意类型的指针
用const修饰,
说明source指向的内存空间的内容不可修改
字节数:
num是一个无符号整型
函数的作用:
将source 指向的空间
里面的num个字节的数据
复制到destination指向的空间中
返回值,返回的是:
拷贝好之后 destination指向的空间的地址
destination指向的内存空间要足够大
至少能容纳下拷贝之后的数据
这个函数遇到'\0'时根本就不会停下来
直到拷贝够num字节数就停止
memmove函数可以胜任重叠拷贝
自己可以拷贝自己
函数用途:如下代码:
#include <stdio.h> #include <string.h> int main() {//创建字符串数组并初始化char str[] = "memmove can be very useful......";//str+20 取到的是字符u的地址//str+15 取到的是字符v的地址//从v字符还是往后拷贝11个字节的数据到 str+20的位置//自己拷贝自己 重叠拷贝memmove(str + 20, str + 15, 11);//打印重叠拷贝后的strputs(str);return 0; }
memcmp
内存比较函数
函数原型:int memcmp ( const void * ptr1,const void * ptr2,size_t num );
返回值:int
返回一个有符号整数
返回小于0的数
返回等于0的数
返回大于0的数
参数:const void * ptr1,const void * ptr2,size_t num
目的地:
ptr1指向任意类型的一块内存空间
用const修饰
说明ptr1指向的空间的内容不可被修改
源头:
ptr2指向任意类型的一块内存空间
用const修饰
说明ptr2指向的空间的内容不可被修改
num是一个无符号整型
表示字节个数
函数作用:
从ptr1和ptr2分别指向空间首地址开始
一个字节一个字节,一一对应进行比较
比较num个字节,
当ptr1大于ptr2返回大于0的数
当ptr1等于ptr2返回数字0
当ptr1小于ptr2返回小于0的数
函数用途:如下代码:
#include <stdio.h> #include <string.h> int main() {//创建两个字符串char buffer1[] = "DWgaOtP12df0";char buffer2[] = "DWGAOTP12DF0";//将buffer1 跟 buffer2 的 前sizeof(buffer1) 个字节 进行比较//一个字节 一个字节 往后一一比较 要是相同往后继续比较//只要遇到不等的字节 就停止比较,返回这两个字节比较的结果//buffer1 大于 buffer2 返回大于0的数字//buffer1 等于 buffer2 返回数字0//buffer1 小于 buffer2 返回小于0的数int n = 0;n = memcmp(buffer1, buffer2, sizeof(buffer1));if (n > 0) printf("'%s' is greater than '%s'.\n", buffer1, buffer2);else if (n < 0) printf("'%s' is less than '%s'.\n", buffer1, buffer2);elseprintf("'%s' is the same as '%s'.\n", buffer1, buffer2);return 0; }
memset
内存填充函数
函数原型:void * memset ( void * ptr, int value, size_t num );
返回值:void *
返回任意类型的指针
返回被修改后的内存空间的地址
参数:void * ptr, int value, size_t num
ptr是一个任意类型的指针
指向一片任意类型的空间
value是一个有符号整型
表示要修改的值
num是一个无符号整型
表示要修改的字节数
函数作用:
将ptr指向的内存块
前num个字节的内容设置为value
从ptr的位置开始向后num个字节
的内容修改成value
函数用途:如下代码
#include <stdio.h> #include <string.h>int main() {int arr[] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);//数组名表示数组首元素地址//将arr指向的内存块的前20个字节,每个字节的内容都设置为0memset(arr, 0, 20);int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");char str[] = "xxxxxxxxx";//将str指向的内存块的前5个字节,每个字节的内容都设置为'a’memset(str, 'a', 5);printf("%s\n", str);return 0; }
库函数的模拟实现
模拟实现strlen
函数原型:size_t strlen(const char* str);
原理:strlen函数是计算字符串的长度
也就是计算'\0'之前的字符的个数
模拟实现:
实现1:
#include <stdio.h>size_t my_strlen(const char* str) {size_t count = 0;while (*str != '\0'){count++;str++;}return count; } int main() {char str[] = "abcdefgh";size_t len = my_strlen(str);printf("%d\n", len);return 0; }
实现2:
#include <stdio.h> //递归方式实现 size_t my_strlen(const char* str) {if (*str != '\0'){return 1 + my_strlen(str+1);}return 0; }int main() {char str[] = "abcdefgh";size_t len = my_strlen(str);printf("%d\n", len);return 0; }
实现3:
#include <stdio.h> size_t my_strlen(const char* str) {char* p = str;while (*str++);return str - p - 1; } int main() {char str[] = "abcdefgh";size_t len = my_strlen(str);printf("%d\n", len);return 0; }
模拟实现strcpy
函数原型:char * strcpy ( char * destination, const char * source );
原理:strcpy就是将source指向空间的内容
复制到destination指向的空间里
在复制的同时会将source的'\0'也复制过去
复制完成后将str1返回
模拟实现:
#include <stdio.h> #include <assert.h>//模拟实现strcpy char* my_strcpy(char* str1, const char* str2) {assert(str1 && str2);char* p = str1;while (*str1++ = *str2++);return p; }int main() {char str1[50] = "xxxxxxxxxxxxxxxxxxxx";char str2[] = "abcdefg";//将str2的内容赋值到str1中//str1的空间要足够大my_strcpy(str1, str2);printf("%s\n", str1);return 0; }
模拟实现strcat
函数原型:char * strcat ( char * destination, const char * source );
原理:将source指向的字符串的内容
追加到destination指向的字符串的后面
追加的时候destination字符串的'\0'字符
会被source字符串的首字符覆盖
且会将source字符串的'\0'也追加上来
且返回追加完成后的destination
模拟实现;
#include <stdio.h> #include <assert.h>//模拟实现 strcat char* my_strcat(char* dest, const char* src) {assert(dest && src);char* p = dest;while (*dest){dest++;}while ((*dest++ = *src++));return p; }int main() {char str1[50] = "abcdef";char str2[] = "ghijklmn";//将str2字符串的内容追加到str1后面//在追加的时候会将str1字符串的'\0'覆盖掉my_strcat(str1, str2);printf("%s\n", str1);return 0; }
模拟实现strstr
函数原型:const char * strstr ( const char * str1, const char * str2 );
原理:寻找str1这个字符串中是否包含str2字符串
若是包含则返回str2第一次出现的位置
否则返回NULL
也就是判断str2是否是str1的子串
模拟实现:
#include <stdio.h> #include <assert.h>//模拟实现strstr函数 char* my_strstr(const char* str1, const char* str2) {assert(str1 && str2);char* p = (char*)str1;char* s1 = NULL;char* s2 = NULL;if (*str2 == '\0'){return (char*)str1;}while (*p){s1 = p;s2 = (char*)str2;while (*s1 && *s2 && !(*s1 - *s2)){s1++;s2++;}if (!*s2){return p;}p++;}return NULL; }int main() {char str1[] = "kkkabcdefghijklmnabcdefgxyz";char str2[] = "abcdef";//查找str2是否是str1的子串//若是返回str2第一次出现的位置//不是则返回NULLchar* p = my_strstr(str1, str2);if (p == NULL){printf("不是子串\n");}else{printf("是子串\n");printf("从返回的地址处开始打印:%s\n", p);}return 0; }
模拟实现strcmp
函数原型:int strcmp ( const char * str1, const char * str2 );
原理: 让str1字符串与str2字符串
从首字符开始一个字符一个字符向后比较
若两个字符相等则继续向后比较
直到出现两个字符不等的情况下停止比较
并且返回这两个不同字符比较的结果
若str1大于str2返回大于0的数
若str1等于str2返回等于0的数
若str1小于str2返回小于0的数
模拟实现:
#include <stdio.h> #include <assert.h>//模拟实现strcmp函数 int my_strcmp(const char* str1, const char* str2) {assert(str1 && str2);while (*str1 && *str2){if (*str1 == *str2){str1++;str2++;}else{return (*str1 - *str2);}}return (*str1 - *str2); }int main() {char str1[] = "abcdefg";char str2[] = "abcdhjk";int ret = my_strcmp(str1, str2);if (ret == 0){printf("str1 = str2\n");}else if (ret > 0){printf("str1 > str2\n");}else{printf("str1 < str2\n");}return 0; }
模拟实现memcpy
函数原型:void * memcpy ( void * destination, const void * source, size_t num );
原理:将source指向的内存块中
num个字节的内容复制到
destination指向的内存块中
返回复制完成后的destination
一般情况下不能胜任重叠拷贝
也就是自己拷贝自己
模拟实现:
#include <stdio.h> #include <assert.h>//模拟实现memcpy void* my_memcpy(void* dest, void* src, size_t num) {assert(dest && src);void* p = dest;while (num--){*(char*)dest = *(char*)src;++(char*)dest;++(char*)src;}return p; }int main() {//拷贝整型int arr[] = { 1,2,3,4,5 };int brr[] = { 6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);my_memcpy(arr,brr,8);int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");//拷贝字符串char str1[] = "xxxxxxxxxx";char str2[] = "abcde";my_memcpy(str1, str2, 5);printf("%s\n", str1);return 0; }
模拟实现memmove
函数原型:void * memmove ( void * destination, const void * source, size_t num );
原理:将source指向的内存块中
num个字节的内容复制到
destination指向的内存块中
返回复制完成后的destination
完全胜任重叠拷贝
可以自己拷贝自己
模拟实现:
#include <stdio.h> #include <assert.h>//模拟实现,memmove //可实现重叠拷贝 //当dest<srt时从前向后 //当dest>src时从后向前 //当dest=src时从前向后 从后向前void* my_memmove(void* dest, void* src, size_t num) {void* p = dest;assert(dest && src);if (dest > src){dest = (char*)dest + num-1;src = (char*)src + num-1;while (num--){*(char*)dest = *(char*)src;dest=(char*)dest-1;src=(char*)src-1;}}else{while (num--){*(char*)dest = *(char*)src;++(char*)dest;++(char*)src;}}return p; }int main() {//拷贝整型int arr[] = { 6,7,8,9,10 };int brr[] = { 1,2,3,4,5 };int sz = sizeof(arr) / sizeof(arr[0]);my_memmove(arr, brr, 12);int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");//拷贝字符串char str1[] = "yyyyyyyyyy";char str2[] = "abcdef";my_memmove(str1, str2, 4);printf("%s\n", str1);//重叠拷贝int prr[] = { 1,2,3,4,5,6,7,8,9,10 };int s = sizeof(prr) / sizeof(prr[0]);my_memmove(prr + 5, prr, 12);int j = 0;for (j = 0; j < s; j++){printf("%d ", prr[j]);}return 0; }