字符串+内存函数(C语言)

news/2024/12/29 7:21:19/

目录

函数介绍:

字符串函数:

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;
}


http://www.ppmy.cn/news/12361.html

相关文章

Servlet的实战用法(表白墙前后端)

作者&#xff1a;~小明学编程 文章专栏&#xff1a;JavaEE 格言&#xff1a;热爱编程的&#xff0c;终将被编程所厚爱。 目录 服务器版本的表白墙 创建项目 约定前后端交互接口 获取全部留言 发表新的留言 服务端代码 创建Message类 创建DBUtil类 创建MessageServlet…

年度征文|一个业余电脑玩家的30年(1992-2022)

《论语为政》&#xff1a;“五十而知天命”。岁月真的是一把刀&#xff0c;一晃已过不惑之年&#xff0c;还有几天就要进入知非之年。不论知非还是知天命&#xff0c;反正是花甲将至而从心所欲了。年少时因某种不合机缘&#xff0c;错与IT界擦肩而过&#xff0c;每每想起就扼腕…

Java学习(88)Java集合——案例:商品信息管理(HashMap增删改查)

Java集合——案例&#xff1a;商品信息管理&#xff08;HashMap增删改查&#xff09;需求分析分析商品信息类&#xff08;属性、方法&#xff09;商品类的属性、构造方法和重写toString()方法商品信息添加&#xff0c;输出商品信息商品信息添加优化&#xff08;判断商品编号id是…

iperf工具源码下载、编译、编译报错解决、以及测试网络带宽

1、iperf源码下载 (1)源码下载地址&#xff1a;https://iperf.fr/iperf-download.php; (2)有的版本源码下载下来并不能直接编译成功&#xff0c;可能会报缺少头文件或者编译选项的错误&#xff0c;要么去解决这些错误&#xff0c;要么换个版本再试一下&#xff1b; (3)在我的环…

【并查集】【Union-Find】

Union-Find算法基本概念并查集模板1. [参考leetcode](https://leetcode.cn/problems/number-of-provinces/solution/python-duo-tu-xiang-jie-bing-cha-ji-by-m-vjdr/)2.平衡优化和重量优化基本概念 并查集是一种数据结构并查集这三个字&#xff0c;一个字代表一个意思。 并&a…

20多年老码农的IT学习之路

20年IT工作经历&#xff0c;目前在一家500强做企业架构&#xff0c;年薪税前150万多&#xff0e;最近公司业绩不好&#xff0c;有感觉工作不保&#xff0c;所以又捡起了编程&#xff0c;开始学习Golang&#xff0c;Angular等。我不是985&#xff0c;211也不是海归&#xff0c;我…

C语言:分支语句和循环语句

往期文章 C语言&#xff1a;初识C语言 目录往期文章前言1. 什么是语句2. 分支语句&#xff08;选择结构&#xff09;2.1 if语句2.2 switch语句3. 循环语句3.1 while循环3.2 for循环3.3 do while 循环3.4 goto语句后记前言 趁热打铁啊。写完该系列第一篇博客我就来劲了&#x…

2022年终总结---权衡好工作和生活

2022总结 【校园】2022年6月研究生顺利毕业&#xff0c;让下文的一切才变的有机会。感谢师弟送学长毕业&#xff0c;感谢在最后时刻各位舍友帮忙送材料&#xff0c;怀念最后一个月一起打球的时光。 【工作】2022年6月入职阿里&#xff0c;成为打工人。在这个大的平台&#xf…