目录
引言:
(一)字符函数和字符串函数
1.简介
2.strlen()函数
2.1用法
2.2实例
2.3 实现strlen()
(1)计数法
(2)递归法
(3) 指针-指针
2.4sizeof和strlen()的区别
3.strcmp()函数
3.1用法
3.2实例
3.3实现strcmp()
4.strcpy()函数
4.1用法
4.2实例
4.3 实现strcpy()
5.strcat()函数
5.1用法
5.2实例
5.3实现strcat()
6.strchr()函数
6.1用法
6.2实例
6.3实现strchr()
7.strstr()函数
7.1用法
7.2实例
7.3 实现strstr()
8.strncmp()函数
8.1用法
8.2实例
8.3 实现strncmp()
9.strncpy()函数
9.1用法
9.2 实例
9.3实现strncpy()函数
10.strncat()函数
10.1用法
10.2 实例
10.3实现strncat()函数
11.strtok()函数
11.1用法
11.2 实例
11.3 实现strtok()函数
12.strerror()函数
12.1用法
12.2实例
(二)内存操作函数
1. 简介
2. memset()函数
2.1用法
2.2实例
2.3 实现memset()
3. memcmp()函数
3.1用法
3.2 实例
3.3 实现memcmp()
3.4strcmp,strncmp,memcmp之间的区别
4. memcpy()函数
4.1用法
4.2 实例
4.3实现memcpy()
4.4strcpy,strncpy,memcpy之间的区别
5. memmove()函数
5.1用法
5.2实例
5.3实现memmove()
结言:
引言:
我们在学习C语言的过程中,除了使用最多的头文件<stdio.h>,还会使用其他头文件,利用其中的库函数帮助我们简化代码的过程,比如像<math.h>,<string.h>等头文件,而今天贝蒂就带大家详细了解一下<string.h>。
(一)字符函数和字符串函数
1.简介
<string.h>中有很多实用的库函数,大致分为两类:一类是像strlen(),strchr()等作用于字符或字符串的字符函数和字符串函数,今天就让我们先来介绍字符函数和字符串函数吧~
2.strlen()函数
2.1用法
1.声明:size_t strlen(const char *str)
- str -- 要计算长度的字符串。
2.作用:计算字符串 str 的长度,直到空结束字符('\0'),但不包括空结束字符。
3.返回值:该函数返回字符串的长度
2.2实例
strlen()函数的用法很简单,贝蒂来简单介绍一下吧~
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abcdef";
int len = strlen(arr);//计算arr字符串的长度
printf("%d\n", len);
return 0;
}
输出结果: 6
2.3 实现strlen()
我们已经知道了strlen()函数的用法,那我们可不可以自我实现一个my_strlen()函数来模拟strlen()函数的功能,当然是可以的呀,下面贝蒂将介绍三种实现方法。
(1)计数法
思路:我们可以用一个指针变量p指向首元素和一个计数变量count并初始化为0,然后循环解引用指针所指向的元素,判断这个元素是否为‘\0’,不是每次p++,count++,是就跳出循环,返回count。
代码实现如下:
#include<stdio.h>
int my_strlen(char* p)
{
int count = 0;
while (*p)//当指向'\0',也就是0,为假跳出循环
{
p++;//指向下一个元素
count++;//计数
}
return count;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);//计算arr字符串的长度
printf("%d\n", len);
return 0;
}
(2)递归法
思路:假设我们要计算字符串“abcdef”的长度,我们可以拆分为1+“bcdef”的长度,同理“bcdef”的长度可以拆分为1+“cdef”的长度......理解了这个思路,我们就可以实现递归,首先定义一个指针变量p,如果*p!='\0',我们就把p+1作为参数调用本函数,直到*p为0.
代码实现如下:
int my_strlen(char* p)
{
if (*p != '\0')
{
return 1 + my_strlen(p + 1);//每次调用p+1指向下一个元素
}
else
{
return 0;//结束递归
}
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);//计算arr字符串的长度
printf("%d\n", len);
return 0;
(3) 指针-指针
首先大家要清楚指针-指针是指在同一空间内,两个指针之间的元素个数。
思路:首先定义两个指针p1,p2,让两个指针指向首元素,然后让一个指针p2循环++,直到指向‘\0’就停止,最后返回p2-p1。
代码实现如下:
int my_strlen(char* p1)
{
char* p2 = p1;//使两个指针都指向首元素
while (*p2)
{
p2++;
}
return p2 - p1;//返回两指针直接的元素的个数就是其长度
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);//计算arr字符串的长度
printf("%d\n", len);
return 0;
}
2.4sizeof和strlen()的区别
sizeof() 和 strlen() 的主要区别在于:
sizeof()
是一个运算符,而strlen()
是一个函数。sizeof()
计算的是变量或类型所占用的内存字节数,而strlen()
计算的是字符串中字符的个数。sizeof()
可以用于任何类型的数据,而strlen()
只能用于以空字符 '\0' 结尾的字符串。- sizeof() 计算字符串的长度,包含末尾的 '\0',strlen() 计算字符串的长度,不包含字符串末尾的 '\0'。
贝蒂说:“sizeof和 strlen() 分别是 C 语言中两个非常常用的关键字和函数,它们都与计算内存大小有关,但是它们的作用是不同的哦,大家一定要区分清楚哦~。
3.strcmp()函数
3.1用法
1.声明:int strcmp(const char* str1,const char*str2)
- str1 -- 要进行比较的第一个字符串。
- str2 -- 要进行比较的第二个字符串。
2.作用:strcmp() 会根据 ASCII 编码依次比较 str1 和 str2 的每一个字符,直到出现不到的字符,或者到达字符串末尾(遇见‘
\0’
)3.返回值:
- 如果返回值小于 0,则表示 str1 小于 str2。
- 如果返回值大于 0,则表示 str1 大于 str2。
- 如果返回值等于 0,则表示 str1 等于 str2。
3.2实例
strcmp用于比较字符串,并返回>0,==0,<0的值,让我们看看他的具体使用吧
#include<stdio.h>
#include<string.h>
int main()
{
char str1[] = "abcd";
char str2[] = "Abcd";
char str3[] = "abcd";
char str4[] = "bbcd";
int ret1 = strcmp(str1, str2);//比较str1与str2
int ret2 = strcmp(str1, str3);//比较str1与str3
int ret3 = strcmp(str1, str4);//比较str1与str4
printf("%d %d %d\n", ret1, ret2, ret3);
return 0;
}
输出:1 0 -1
贝蒂说:“strcmp()首先会比较第一个字母的ASCII值,如果==则比较第二个字符,直到遇见'\0',若不相等,则返回两个字符之差”
3.3实现strcmp()
思路:首先两个字符串不能改变,且不能传的参数不能为空指针,输入空指针让编译器报错,然后从第一个字符开始比较,直到两个字符不相等(返回两个字符之差),如果在不相等之前已经指向‘\0’,直接返回0.
代码实现如下:
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
//经const修饰让*str1与*str2无法改变
{
assert(str1 && str2);//判断str1和str2是否为空指针
//空指针直接报错,头文件<assert.h>
while (*str1== *str2)
{
if (*str1 == '\0')
{
return 0;
}
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
char str1[] = "abcd";
char str2[] = "Abcd";
int ret = my_strcmp(str1, str2);
printf("%d\n", ret);
return 0;
}
贝蒂说:“相信大家也和贝蒂一样疑惑过,为什么比较字符串不能用==,而是用库函数相比较,就让贝蒂告诉你吧,嘻嘻,那是因为字符串在内存中存储是以首元素地址方式存储的,比较两个地址,肯定会不相等呀~”
4.strcpy()函数
4.1用法
1. 声明:char *strcpy(char *dest, const char *src),dest -- 指向用于存储复制内容的目标数组,src -- 要复制的字符串。
2. 作用:把 src 所指向的字符串复制到 dest。需要注意的是如果目标数组 dest 不够大,而源字符串的长度又太长,可能会造成缓冲溢出的情况。
3. 返回值:该函数返回一个指向最终的目标字符串 dest 的指针。
4.2实例
#include <stdio.h>
#include <string.h>
int main()
{
char src[40];
char dest[40];
strcpy(src, "im not betty");
strcpy(dest, src);
printf("最终的目标字符串:%s\n", dest);
return 0;
}
输出结果: 最终的目标字符串:im not betty
4.3 实现strcpy()
思路:我们想要将src的内容拷贝进des中,首先src的内容不能被改变,且保证都不是空指针,然后循环将src的内容赋值给des,直到赋值完‘\0’,条件为假,跳出循环。
代码实现:
#include<assert.h>
char* my_strcpy(char* des, const char* src)//防止src的内容被改变
{
assert(des && src);//防止des与src是空指针
char* ret = des;//作为返回值
while (*des++ = *src++)//循环拷贝,当拷贝完'\0',判断为假,跳出循环
{
;
}
return ret;
}
int main()
{
char src[40] = "abcdef";
char des[40];
my_strcpy(des, src);//将src的内容拷贝去des
printf("%s\n", des);
return 0;
}
贝蒂说:“strcpy(),cpy,copy,就是把别人的东西copy(复制)下来呀~,嘻嘻”
5.strcat()函数
5.1用法
1. 声明:char *strcat(char *dest, const char *src)
- dest -- 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串。
- src -- 指向要追加的字符串,该字符串不会覆盖目标字符串。
2. 作用:把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。
3.返回值:该函数返回一个指向最终的目标字符串 dest 的指针。
5.2实例
#include <stdio.h>
#include <string.h>
int main()
{
char src[50];
char dest[50];
strcpy(src, "world!");
strcpy(dest, "hello ");
strcat(dest, src);
printf("最终的目标字符串:%s", dest);
return 0;
}
输出结果:最终的目标字符串:hello world!
贝蒂说:“因为strcat()函数的实现机制,所以strcat()无法对自己追加(会出现死循环),如果要实现自己对自己的追加可以使用strncat()函数,这个后面贝蒂会为大家讲解哒~”
5.3实现strcat()
思路:实现strcat的方法其实和实现strcpy的方法类似,都是替换,只是要让dest先指向末尾'\0'。
代码实现:
char* my_strcat(char* dest, const char* src)//防止src的值被改变
{
assert(dest && src);//不能为空指针
char* ret = dest;
while (*dest)//使dest指向末尾
{
dest++;
}
while (*dest++ = *src++)//循环赋值
{
;
}
return ret;
}
int main()
{
char dest[20] = "hello ";
char src[20] = "world!";
my_strcat(dest, src);
printf("%s", dest);
return 0;
}
6.strchr()函数
6.1用法
1. 声明:char *strchr(const char *str, int c)
- str -- 要查找的字符串。
- c -- 要查找的字符。
2. 作用:在参数 str 所指向的字符串中搜索第一次出现字符 c(一个无符号字符)的位置。
3. 返回值:如果在字符串 str 中找到字符 c,则函数返回指向该字符的指针,如果未找到该字符则返回 NULL。
6.2实例
#include<string.h>
int main()
{
char arr[20] = "hello betty";
char* p = strchr(arr,'y');
if (*p == NULL)
{
printf("没找到\n");
}
else
{
printf("找到了\n");
}
return 0;
}
6.3实现strchr()
思路:一样先排查空指针,然后循环寻找,如果寻找到,直接返回其地址。找不到就返回空指针NULL
代码实现:
char* my_strchr(const char* str, int c)
{
assert(str);//排查空指针
while (*str)
{
if (*str == c)
{
return str;//找到返回其地址
}
str++;
}
return NULL;//找不到返回空指针
}
int main()
{
char arr[20] = "hello betty";
char* p =my_strchr(arr,'y');
if (*p == NULL)
{
printf("没找到\n");
}
else
{
printf("找到了\n");
}
return 0;
}
贝蒂说:“strchr()函数在我们做有关字符串的问题时候非常常用,大家可以重点掌握哦~”
7.strstr()函数
7.1用法
1. 声明:char *strstr(const char *haystack, const char *needle)
haystack -- 要被检索的 C 字符串。
needle -- 在 haystack 字符串内要搜索的小字符串。
2 .作用:在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 '\0'。
3 .返回值:该函数返回在 haystack 中第一次出现 needle 字符串的位置,如果未找到则返回 空指针(NULL)
7.2实例
#include <stdio.h>
#include <string.h>
int main()
{
char haystack[20] = "hello betty";
char needle[10] = "betty";
char* ret = strstr(haystack, needle);
if (ret == NULL)
{
printf("未找到\n");
}
else
{
printf("找到啦,子字符串是:%s\n", ret);
}
return 0;
}
输出结果:找到啦,子字符串是:betty
7.3 实现strstr()
思路:首先用是用s1,s2指向两个字符串的首元素,用p记录str1中开始比较的元素的位置,方便重新开始比较。然后循环比较,如果*s1!=*s2,或者遇见‘\0’,就跳出循环,判断,如果是s2为‘\0’,说明配对成功,s1为‘\0’,则说明后续长度不够,匹配失败啦,除开以上情况,就让p++,重复上述流程,直到*p==‘\0’
情况1:在acbcef中查找acb
代码实现如下:
#include <stdio.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);//防止空指针
const char* s1 = str1;
const char* s2 = str2;
const char* p = str1;//记录初始位置
while (*p)
{
s1 = p;//从记录位置开始比较
s2 =str2;
while (*s1 != '\0' && *s2 != '\0' && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')//配对成功
{
return (char*)p;//p原本被const修饰
}
else if (*s1 == '\0' && s2 != '\0')//s1后续字符少于s2
{
return NULL;
}
p++;//记录下一个位置
}
return NULL;
}
int main()
{
char haystack[20] = "hello betty";
char needle[10] = "betty";
char* ret =my_strstr(haystack, needle);
if (ret == NULL)
{
printf("未找到\n");
}
else
{
printf("找到啦,子字符串是:%s\n", ret);
}
return 0;
}
贝蒂说:“整体来说strstr的实现方法比较复杂,需要大家细细揣摩,最好画图慢慢分析哦~”
8.strncmp()函数
8.1用法
1. 声明:int strncmp(const char *str1, const char *str2, size_t n)
- str1 -- 要进行比较的第一个字符串。
- str2 -- 要进行比较的第二个字符串。
- n -- 要比较的最大字符数。
2. 作用: 把 str1 和 str2 进行比较,最多比较前 n 个字符
3. 返回值:
- 如果返回值 < 0,则表示 str1 小于 str2。
- 如果返回值 > 0,则表示 str1 大于 str2。
- 如果返回值 = 0,则表示 str1 等于 str2。
8.2实例
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "abcdef";
char arr2[20] = "abcddd";
int ret1 = strncmp(arr1, arr2, 3);//比较前三个字符
int ret2 = strncmp(arr1, arr2, 8);//即使给出的num太大,遇见'\0'也会停止
int ret3 = strncmp(arr1, arr2, 6);//比较全部字符
printf("%d %d %d\n", ret1, ret2,ret3);
return 0;
}
输出结果:0 1 1
8.3 实现strncmp()
思路:总体思路与strcmp()的设计思路一样,只需加入限制比较字符个数的条件即可~
代码实现:
#include <stdio.h>
#include<assert.h>
int my_strncmp(const char* str1, const char* str2, size_t n)
{
assert(str1 && str2);
while (n-- && *str1 == *str2)//任意一个条件不满足就跳出循环
{
if (*str1 =='\0')
{
return 0;
}
str1++;
str2++;
}
return *str1 - *str2;
}
9.strncpy()函数
9.1用法
1. 声明:char *strncpy(char *dest, const char *src, size_t n)
- dest -- 指向用于存储复制内容的目标数组。
- src -- 要复制的字符串。
- n -- 要从源中复制的字符数。
2. 作用: 把 src 所指向的字符串复制到 dest,最多复制 n 个字符。当 src 的长度小于 n 时,dest 的剩余部分将用‘\0’填充。
9.2 实例
当src>=n时:
#include <stdio.h>
#include <string.h>
int main()
{
char src[40] = { 0 };
char dest[12] = { 0 };
strcpy(src, "This is runoob.com");
strncpy(dest, src, 10);
printf("最终的目标字符串:%s\n", dest);
return 0;
}
输出结果:最终的目标字符串:This is ru
当src<n时
include <stdio.h>
#include <string.h>
int main()
{
char src[40] = { 0 };
char dest[12] ="this is";
strcpy(src, "This");
strncpy(dest, src, 10);
printf("最终的目标字符串:%s\n", dest);
return 0;
}
输出结果:最终的目标字符串:This
9.3实现strncpy()函数
思路:总体实现思路和strcpy()差不多,但是要分src<n时,src>=n两种情况讨论
char* my_strncpy(char* dest, const char* src, int n)
{
assert(dest && src);
char* ret = dest; //将dest首地址储存在ret中,方便返回
while (*src && n)
{
*dest = *src;
dest++;
src++;
n--;
}
if (n != 0)//n>src
{
while (n)
{
*dest = '\0';
dest++;
n--;
}
}
return ret; //返回数组的首地址
}
10.strncat()函数
10.1用法
1 .声明:char *strncat(char *dest, const char *src, size_t n)
- dest -- 指向目标数组,该数组包含了一个 C 字符串,且足够容纳追加后的字符串,包括额外的空字符。
- src -- 要追加的字符串。
- n -- 要追加的最大字符数。
2. 用法:把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止。
如果n<src的长度,将source指向字符串的前n个字符追加到dest指向的字符串末尾,再追加⼀个 \0 字符。
如果n>=src,只会将字符串中到\0 的内容追加到dest指向的字符串末尾
3. 返回值:该函数返回一个指向最终的目标字符串 dest 的指针。
10.2 实例
当n<src时:
#include<string.h>
int main()
{
char str1[20];
char str2[20];
strcpy(str1, "hello ");
strcpy(str2, "helloworld");
strncat(str1, str2, 6);
printf("%s\n", str1);
return 0;
}
输出结果:hello hellow
当n>=src时:
#include<string.h>
int main()
{
char str1[20];
char str2[20];
strcpy(str1, "hello ");
strcpy(str2, "helloworld");
strncat(str1, str2, 15);
printf("%s\n", str1);
return 0;
}
输出结果:hello helloworld
因为strncat()函数会自动在末尾补充'\0‘的优势,所以可以用于“自己对自己添加”
int main()
{
char arr[10] = "abc";
strncat(arr, arr, 3);
printf("%s", arr);
return 0;
}
10.3实现strncat()函数
思路:也和strcat()实现方法大致相同,但是要注意如果n<src时,要在末尾自动补充'\0'哦
代码实现:
#include<assert.h>
char* my_strncat(char* dest, const char* src, int n)
{
char* ret = dest; //将dest首地址储存在ret中
assert(dest&&src); //保证dest、src非空
while (*dest != '\0')//找到dest结尾的‘\0’
{
dest++;
}
while (n && (*dest++ = *src++))//把src里的字符一个个放入dest后
{
n--; //循环跳出条件
}
if(n==0)
{
*dest = '\0'; //如果n<src
}
return ret; //返回dest字符串起始地址
}
11.strtok()函数
11.1用法
1. 声明:char *strtok(char *str, const char *delim)
- str -- 要被分解成一组小字符串的字符串。第一次调用 strtok() 时,这个参数应该是你想要分割的字符串。随后的调用应该将此参数设置为
NULL
,以便继续从上次的位置分割。- delim -- 包含分隔符的 C 字符串。
2. 作用:strtok() 用于将字符串分割成一系列的子串
3. 返回值:该函数返回被分解的第一个子字符串,如果没有可检索的字符串,则返回一个空指针。
贝蒂说:“如果一下子没有明白,不要但心,继续跟着贝蒂看看例子就明白啦~”
11.2 实例
#include <string.h>
#include <stdio.h>
int main()
{
char str[80] = "This is - betty -@class";
const char s[] = "-@";
char* p = strtok(str, s);//第一次传参
while (*p != NULL)
{
printf("%s\n", p);
p = strtok(NULL, s);//非第一次传参
}
return 0;
}
输出结果:
This is
betty
class
11.3 实现strtok()函数
在这里这里,贝蒂详解strcat哦~
12.strerror()函数
12.1用法
1. 声明:char *strerror(int errnum)
- errnum -- 错误号,通常是 errno。
2. 作用:从内部数组中搜索错误号 errnum,并返回一个指向错误消息字符串的指针。strerror 生成的错误字符串取决于开发平台和编译器。
2. 返回值:该函数返回一个指向错误字符串的指针,该错误字符串描述了错误 errnum。
12.2实例
#include<string.h>
#include<errno.h>//错误码的头文件
int main()
{
//每一个错误码对应一个错误信息
printf("%s\n", strerror(0));
printf("%s\n", strerror(1));
printf("%s\n", strerror(2));
printf("%s\n", strerror(3));
return 0;
}
输出:
No error (没有错误)
Operation not permitted (操作不允许)
No such file or directory (没有这样的文件)
No such process (没有这样的进程)
strerror常常用于动态内存开辟和文件的操作
FILE* pfwrite = fopen("contact.txt", "wb");
if (pfwrite == NULL)
{
printf("%s\n", strerror(errno));//如果打开失败,输出错误信息
return 1;
}
pc->data = (peoinfo*)calloc(3 , sizeof(peoinfo));
if (pc->data == NULL)
{
printf("inticontact:%s\n", strerror(errno));//如果开辟失败,输出错误信息
return 1;
}
贝蒂说:“可惜贝蒂现在已学的知识,还无法实现strerror()啦”
(二)内存操作函数
1. 简介
除了字符函数和字符串函数,<string.h>中还有一类内存操作函数,如memset(),memcmp()等函数,他们在功能和某些字符串函数很像,但作用范围更广,除了作用于字符串外,还可以作用于int ,double等类型,但因为是以字节为单位改变,所以限制也很大。下面就让我们来看看吧~
2. memset()函数
2.1用法
1. 声明:void *memset(void *str, int c, size_t n)
- str -- 指向要填充的内存块。
- c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
- n -- 要被设置为该值的字符数。
2. 复制字符 c(一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。
3. 返回值:该值返回一个指向存储区 str 的指针。
2.2实例
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "hello world";
memset(str, 'x', 6);//以字节为单位
printf(str);
return 0;
}
输出结果:xxxxxxworld
int main()
{
int arr[4] = { 1,2,3,4 };
memset(arr, 1, sizeof(arr));
int i = 0;
for (i = 0; i < 4; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
输出结果:16843009 16843009 16843009 16843009
贝蒂说:“虽然memset可以作用于int,float等类型,但是memset设置是以字节为单位,容易造成不符合我们预期的情况哦~”
2.3 实现memset()
思路:memset()函数和strcpy()函数有点像,都是替换,但是内在实现也有区别,因为memset()函数还可以用于不同数据类型,所以要先强制类型为(char*),再以字节为单位替换。
代码实现:
#include <string.h>
#include<assert.h>
void* my_memset(void*str, int c, size_t n)
{
assert(str);//防止str为空指针
char* tmp= (char*)str;//以字节为单位改变
while (n--)
{
*tmp = c;
tmp++;
}
return str;
}
int main()
{
char str[] = "hello world";
my_memset(str, 'x', 6);//以字节为单位
printf(str);
return 0;
}
贝蒂说:“memset()函数常用于初始化哦~”
3. memcmp()函数
3.1用法
1. 声明:int memcmp(const void *str1, const void *str2, size_t n)
- str1 -- 指向内存块的指针。
- str2 -- 指向内存块的指针。
- n -- 要被比较的字节数。
2. 作用:把存储区 str1 和存储区 str2 的前 n 个字节进行比较。
3. 返回值:
- 如果返回值 < 0,则表示 str1 小于 str2。
- 如果返回值 > 0,则表示 str1 大于 str2。
- 如果返回值 = 0,则表示 str1 等于 str2。
3.2 实例
#include <stdio.h>
#include <string.h>
int main()
{
char str1[] = "Hello, World!";
char str2[] = "Hello, World!";
char str3[] = "Hello, Betty!";
// 比较相同的字符串
if (memcmp(str1, str2, strlen(str1)) == 0)
{
printf("str1 和 str2 相同。\n");
}
// 比较不同的字符串
if (memcmp(str1, str3, strlen(str1)) != 0)
{
printf("str1 和 str3 不同。\n");
}
return 0;
}
输出:
str1 和 str2 相同。
str1 和 str3 不同。
3.3 实现memcmp()
思路:总体思路与strncmp差不多,只是也需要先强制类型转换
#include<stdio.h>
#include<assert.h>
int my_memcmp(const void* str1, const void* str2, size_t n)
{
assert(str1 && str2);//
char* p1 = (char*)str1;
char* p2 = (char*)str2;
while (n--&&(*p1==*p2))
{
if (*p1 == '\0')
{
return 0;
}
p1++;
p2++;
}
return *p1 - *p2;
}
贝蒂说:“memcmp()函数也是以字节比较,所以限制也很大哦~”
3.4strcmp,strncmp,memcmp之间的区别
- memcmp是比较两个存储空间的前n个字节,即使字符串已经结束,仍然要比较剩余的空间,直到比较完n个字节。
- strcmp比较的是两个字符串,任一字符串结束,则比较结束。
- strncmp在strcmp的基础上增加比较个数,其结束条件包括任一字符串结束和比较完n个字节。
- strcmp比较的字符串,而memcmp比较的是内存块,strcmp需要时刻检查是否遇到了字符串结束的 /0 字符,而memcmp则完全不用担心这个问题,所以memcmp的效率要高于strcmp
4. memcpy()函数
4.1用法
1. 声明:void *memcpy(void *str1, const void *str2, size_t n)
- str1 -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
- str2 -- 指向要复制的数据源,类型强制转换为 void* 指针。
- n -- 要被复制的字节数。
2. 作用:从存储区 str2 复制 n 个字节到存储区 str1。
3. 返回值:该函数返回一个指向目标存储区 str1 的指针。
4.2 实例
int main()
{
int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
memcpy(arr2, arr1, 20);//前五个元素
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d ", arr2[i]);
}
return 0;
}
输出结果:1 2 3 4 5 0 0 0 0 0
4.3实现memcpy()
思路:自然也是和strcpy()差不多啦,嘻嘻
void* my_memcpy(void* dest, const void* src, size_t n)
{
assert(dest && src);//防止空指针
void* ret = dest;
while (n--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
return ret;
}
贝蒂说:“因为memcpy()函数实现机制,所以不能自己对自己进行拷贝哦~”
4.4strcpy,strncpy,memcpy之间的区别
- memcpy是从源存储空间拷贝到目标存储空间;而strcpy,strncpy是从源字符串拷贝到目标字符串。
- memcpy拷贝时是按照参数n作为结束标志的,即拷贝n个字节就结束;strncpy是以参数n或者‘\0’为结束标志;strcpy是判断‘\0’为结束标志。
5. memmove()函数
5.1用法
我们上面说过memcpy()无法对自己进行拷贝,那有没有能对自己拷贝的函数呢,当然有啦,就是我们的memmove()函数。
1. 声明:void *memmove(void *str1, const void *str2, size_t n)
- str1 -- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。
- str2 -- 指向要复制的数据源,类型强制转换为 void* 指针。
- n -- 要被复制的字节数。
2. 作用:从 str2 复制 n 个字符到 str1,但是在重叠内存块这方面,memmove() 是比 memcpy() 更安全的方法。如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后源区域的内容会被更改。如果目标区域与源区域没有重叠,则和 memcpy() 函数功能相同。
3. 返回值:该函数返回一个指向目标存储区 str1 的指针。
5.2实例
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "Hello, World!";
printf("Original string: %s\n", str);
// 将字符串前6个字符移动到字符串的末尾
memmove(str, str + 7, 6);
printf("Modified string: %s\n", str);
return 0;
}
输出结果:
Original string: Hello, World!
Modified string: World! World!
5.3实现memmove()
分析如下:
情况1:
//假设需要拷贝以下场景
int arr1[9] = { 1,2,3,4,5,6,7,8,9 };
my_memmove(arr1, arr1 + 2, 12);
1. 假设我们从3的位置开始拷贝,3-1,4-2,5-3,拷贝成功。
2. 假设我们从5的位置开始拷贝,5-3,4-2,5-1,拷贝失败。
情况2:
//假设我们要拷贝的情况如下
int arr1[9] = { 1,2,3,4,5,6,7,8,9 };
my_memmove(arr1+4, arr1 + 2, 12);
1. 假设我们从3的位置开始拷贝,3-5,4-6,3-7,拷贝失败。
2. 如果我们从5的位置开始拷贝,:5-7,4-6,3-5,拷贝成功。
情况3:
int arr1[9] = { 1,2,3,4,5,6,7,8,9 };
my_memmove(arr1+1, arr1 + 5, 12);
my_memmove(arr1 + 5, arr1 + 1, 12);
1. 假设从6开始拷贝,6-2,7-3,8-4,拷贝成功。
2. 假设从8开始拷贝,8-4,7-3,6-2,拷贝成功。
1. 假设从2开始拷贝,2-6,3-7,4-9,拷贝成功。
2. 假设从4开始拷贝,4-8,3-7,2-6,拷贝成功。
总结:如果dest字符串在src的字符左边,则从首元素拷贝。如果dest字符串在src右边,则从末尾元素开始拷贝。
代码实现:
void* my_memmove(void* dest, const void* src, size_t n)
{
assert(dest && src);//防止空指针
void* ret = dest;
if (dest <= src)//dest在src左侧
{
while (n--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest + 1;
src = (char*)src + 1;
}
}
else//dest在src的右侧
{
dest = (char*)dest + n - 1;//指向末尾
src = (char*)src + n - 1;//指向末尾
while (n--)
{
*(char*)dest = *(char*)src;
dest = (char*)dest - 1;
src = (char*)src - 1;
}
}
return ret;
}
结言:
第一次写这么长的博客,累死贝蒂啦,虽然没有介绍完string.h中所有的库函数,但是也把常用的基本介绍啦,希望这些能对大家有所帮助哦~