首页 > 其他分享 >字符串操作函数总结

字符串操作函数总结

时间:2023-03-15 22:32:02浏览次数:35  
标签:总结 arr return 函数 char arr1 字符串 include

经过一段时间的学习,现在在这里写下这篇博客,以复习字符串操作函数

首先我用软件画了一张图,

字符串操作函数总结_字符串

这里面大概的介绍了字符串操作函数的用法,现在我们来详细的学习

首先就是strtok函数

首先我们在日常生活中会遇到形如[email protected]这样的邮箱地址

而在这一个字符串中@和.就是分割符,

而这个strtok函数的功能就是将被分割符分割的字符串打印出来

#include<stdio.h>
#include<string.h>
//学会使用strtok
int main()
{
char arr[] = "[email protected]";
char buf[30] = { 0 };
strcpy(buf, arr);//这里要再拷贝一个相同字符串的目的就是,这个strtok函数真的会改变给它传过去的字符串
const char* p = ".,@";
char* ret=strtok(buf, p);//当我们首次使用strtok的时候要将有分隔符的字符串传递给它,它会开始向后遍历,直到找到这个分隔符后将分隔符改为\0然后返回这个已被分离出的字符串的首地址
printf("%s\n", ret);
ret = strtok(NULL, p);//当我们第二次使用这个函数的时候,在前面的参数处传递一个空指针,那么这个函数就会从刚刚还是分隔符的下一个地址开始再次向后遍历,寻找分隔符
printf("%s\n", ret);
ret = strtok(NULL, p);//第三次使用和第二次使用一样,那么当strtok这个函数发现不存在更多分隔符的时候就会返回一个空指针
printf("%s\n", ret);
return 0;//我们使用上面的这种方式写很麻烦,那么有没有更方便的方式使用这个函数呢?
}//上面的代码是使用strtok的最普遍方法
//下面的代码是运用了for循环的strtok

#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "[email protected]";
char buf[30] = { 0 };
strcpy(buf, arr);
const char* p = ".,@";
char* ret = NULL;
for (ret = strtok(buf, p); ret != NULL; ret=strtok(NULL, p))
{
printf("%s\n",ret);
}//这个循环可以这么理解首先我们将待分割的字符串和分割符传递给strtok,并将返回值赋值给ret,然后判断ret是不是空指针,不是的话就打印第一个分割出来的字符串
//打印完之后我们第二次调用strtok同时将返回值赋值给ret,再次判断,直到最后将所有的字符串打印出来
return 0;
}

运行结果

字符串操作函数总结_#include_02

和原字符串比较很明显被分割符,隔开的字符串被分别打印出来了

下面我们学习strerror函数,这个函数的是显示错误信息这个错误信息是什么呢?

这个错误信息就是当c语言的库函数在调用失败的时候,会将一个错误码存放到一个叫:errno的变量中

当我们想要知道调用函数的时候发生了什么错误信息,就可以将errno中的错误码翻译成错误信息。

#include<stdio.h>
#include<string.h>
int main()
{
char*p=strerror(0);
printf("%s\n", p);
p = strerror(1);
printf("%s\n", p);
p = strerror(2);
printf("%s\n", p);
p = strerror(3);
printf("%s\n", p);
return 0;
}//这些0,1,2,3就是错误码

下面的是运行结果图

字符串操作函数总结_#include_03

这就是运行的信息。

但在实际情况中到底会怎么运行呢?

我们先来看这个工程的文件

字符串操作函数总结_数组_04

可以发现我在这里创建了

一个名为test的txt文件然后我们运行以下代码

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
//c语言的打开文件使用fopen
FILE* pf = fopen("test.txt", "r");//这里fopen函数里的第一个
//""里面写的就是要打开的文件名,第二个""里放的是打开方式是以读的方式打开
//文件打开方式如果是r,若文件存在则打开成功,文件不存在则打开失败
//会返回一个FILE* 类型的指针
if (pf == NULL)
{
printf("打开文件失败,原因是%s", strerror(errno));
return 1;
}
//读写文件
//未写
//关闭文件
fclose(pf);
pf = NULL;

return 0;
}//还有就是errno里的信息是会被覆盖的若你第一次打开文件失败,然后第二次打开文件成功,然后你这时候如果打印错误信息的话就会发现没有错误
//因为第一次的错误信息已经被覆盖了

运行结果

字符串操作函数总结_字符串_05

很明显这里就没有显示任何错误信息但若是我删除了那个文件

字符串操作函数总结_数组_06

错误信息就被我打印出来了

哪么有没有一个函数既可以将错误码转化为错误信息,又有打印这个错误信息的功能呢,当然是有的那就是

perror

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
//c语言的打开文件使用fopen
FILE* pf = fopen("test.txt", "r");//这里fopen函数里的第一个
//""里面写的就是要打开的文件名,第二个""里放的是打开方式是以读的方式打开
//文件打开方式如果是r,若文件存在则打开成功,文件不存在则打开失败
//会返回一个FILE* 类型的指针
if (pf == NULL)
{
Perror("文件打开失败,原因是:");
return 1;
}
//读写文件
//未写
//关闭文件
fclose(pf);
pf = NULL;
return 0;
}

运行截图

字符串操作函数总结_字符串_07

下面我们来学习strcpy函数

strcpy函数是字符串拷贝函数,它的功能就是拷贝字符串

#include<stdio.h>
#include<string.h>
int main()
{
char arr[20] = {0};
char arr1[] = "world";
strcpy(arr, arr1);
printf("%s", arr);
return 0;
}

运行截图

字符串操作函数总结_字符串_08

下面我们来模拟实现这个函数

//照例我们要实现这个函数首先就要知道它的原理
//首先我们传递过去的是两个字符数组的首元素地址然后将源头函数从开始一个一个的复制到目的函数的空间里直到源头函数读取到\0
#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* p1, const char* p2)//这里我们不需要修改源头函数所以为了保护源头函数可以加const
{
assert(p1, p2);//对两个指针进行断言防止出现野指针
char* ret = p1;
while (*p1++ = *p2++)
{
;
}
return ret;
}
int main()
{
char arr[20] = { 0 };
char arr1[] = "hello world";
my_strcpy(arr, arr1);
printf("拷贝的函数%s", arr);
return 0;
}

运行截图同上。

但是,在拷贝函数的时候有可能会遇到要拷贝的字符串太大了,目标数组装不下,虽然编译器会报错,但是这个函数依旧会将拷贝的任务完成如下面的代码

#include<stdio.h>
#include<string.h>
int main()
{
char arr[4] = {0};
char arr1[] = "world";
strcpy(arr, arr1);
printf("拷贝的字符串:%s", arr);
return 0;
}

字符串操作函数总结_数组_09

从运行截图可以看到,虽然出现了数组越界的报错,但是这个函数依旧将打印任务完成了,而这也是为什么这个函数是属于长度不受限制的函数。

对于此就有了一个比较安全的长度受限制的函数strncpy下面我们就用代码来展示它的功能。

#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "hello world";
char arr2[10] = { 0 };
strncpy(arr2, arr1, 9);//和strcpy函数一样前面的数组代表目标数组,就一个代表源头数组,而最后的数字则代表要拷贝数据的字节数。
printf("拷贝的字符串:%s",arr2);
return 0;
}//这里我们就是将arr1里面的9个字节的数据拷贝到arr2中了注意这里的空格也占了一个字节

字符串操作函数总结_字符串_10

下面我们来模拟实现这个函数

#include<stdio.h>
char* my_strncpy(char* des, const char* sor, size_t num)
{
char* ret = des;
while (num--)
{
*des++ = *sor++;
}
return ret;
}
int main()
{
char arr1[] = "hello world";
char arr2[10] = { 0 };
my_strncpy(arr2, arr1, 9);//和strcpy函数一样前面的数组代表目标数组,就一个代表源头数组,而最后的数字则代表要拷贝数据的字节数。
printf("拷贝的字符串:%s",arr2);
return 0;
}

运行截图和上图一致。

那么如果有一个数组里的内容是hello ,然后要给他追加一个world有没有这样的函数呢?答案是肯定的那就是strcat字符串追加函数。

#include<stdio.h>
#include<string.h>
int main()
{
char arr[20] = "hell\0xxxxxx";
char arr1[] = "world";
//strcat函数追加的规则就是从目标函数的\0处开始向后追加源头函数包括源头函数的\0
strcat(arr, arr1);
printf("%s", arr);
return 0;
}

运行截图

字符串操作函数总结_字符串_11


下面我们来模拟实现这个函数

#include<stdio.h>
#include<assert.h>
char* my_strcat(char* des,const char* sor)
{
assert(des, sor);
char* s1 = des;//记录des的起始地址便于最终返回
while (*des != '\0')
{
des++;
}//通过这个循环找到了目标函数的\0
while (*des++ = *sor++)
{
;
}//通过这个循环将源头函数追加到des函数里直到sor为\0那么这个时候整个表达式的值就为0(假)循环停止
return s1;
}
int main()
{
char arr[20] = "hello ";
char arr1[] = "world";
//strcat函数追加的规则就是从目标函数的\0处开始向后追加源头函数包括源头函数的\0
printf("%s", my_strcat(arr, arr1));//我们也能通过这样去打印目标函数因为这个strcat函数的返回值返回的就是目标函数的首地址这样我们也能将函数的返回值运用到了
return 0;
}

字符串操作函数总结_#include_12

同样的这个函数也有一个长度受限制的版本

#include<stdio.h>
#include<string.h>
int main()
{
char arr1[30] = "hello ";
char arr2[] = "world";
printf("%s",strncat(arr1,arr2,5));
return 0;
}

字符串操作函数总结_#include_13

下面我们来模拟实现这个函数

#include<stdio.h>
#include<assert.h>
char* my_strncat(char* des, const char* sor, size_t num)
{
assert(des && sor);
char* ret = des;
while (*des != '\0')
{
des++;
}
while (num--)
{
*des++ = *sor++;
}
return ret;
}
int main()
{
char arr1[30] = "hello ";
char arr2[] = "world";
printf("%s", my_strncat(arr1, arr2, 5));
return 0;
}

运行截图如图上。

下面我们就来学习字符串比较函数strcmp

和上面的两个函数一样它也有不受长度限制的版本

#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abc";
char arr2[] = "abfde";
strcmp(arr1, arr2);//strcmp函数比较的原理就是它一对一对的读取两个数组的元素若读取的这两个数组元素相等啧继续读取下一对如果读取到两边都是\0则返回0,
//若中途有任意一对出现不相等的元素若arr1大就返回大于0的数反之则相反
printf("%d", strcmp(arr1, arr2));
return 0;
}

字符串操作函数总结_字符串_14

下面是模拟实现这个函数

#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* p1, const char* p2)
{
assert(p1, p2);
while (*p1++== *p2++&&*p1!='\0'&&*p2!='\0')
{
;
}
return *p1 - *p2;
}
int main()
{
char arr1[] = "abc";
char arr2[] = "abc";
printf("%d", my_strcmp(arr1, arr2));
return 0;
}//这是其中一种写法但这种写法只是满足了规定前大于后就返回一个大于0的数字反之相反,
//但在vs编译环境下前大于后返回的是1反之返回的是-1
#include<stdio.h>
#include<assert.h>
int my_strcmp(const char* p1, const char* p2)
{
assert(p1, p2);
while (*p1++== *p2++)
{
if (*p1 == '\0')
{
return 0;
}
}
if (*p1 > *p2)
{
return 1;
}
else
return -1;
}
int main()
{
char arr1[] = "abc";
char arr2[] = "abc";
printf("%d", my_strcmp(arr1, arr2));
return 0;
}//这一个就是前大于后返回后大于前返回而相等返回0的版本

至于strncmp我就不再介绍了功能和上面的两个带n的是一样的至于实现也是。

下面我们就来学习strlen函数也就是求字符串长度函数

#include<string.h>
#include<stdio.h>
int main()
{
char arr[] = "abcdefgh";
printf("%d", strlen(arr));
return 0;
}

字符串操作函数总结_数组_15

然后我们使用三种方法来模拟实现这个函数

第一种

//但是我们必须先弄懂strlen函数的运行原理
//strlen函数我们传递给这个函数数组首元素的地址这个函数就从第一个元素开始向后遍历只要不是\0他就会让计数器+1最后返回计数器的值
//下面是模拟实现的第一个版本计数器版本
#include<stdio.h>
#include<string.h>
#include<assert.h>
int my_strlen(const char* p)//我们在这个函数里面不需要改变数组的值所以加了一个const保护
{
assert(p);
int count = 0;
while (*p++!= '\0')
{
count++;
}
return count;
}
int main()
{
char arr[] = "abcdefgh";
printf("%d", my_strlen(arr));
return 0;
}

运行截图和上面是一样的。

方法二递归(这个方法出现是有了一个条件就是在不创建临时变量的情况下模拟实现strlen函数)

#include<string.h>
#include<stdio.h>
#include<assert.h>
int my_strlen(const char* p)
{
assert(p);
while (*p != '\0')
{
return 1 + my_strlen(p + 1);
}
}
int main()
{
char arr[] = "abcdefgh";
printf("%d", my_strlen(arr));
return 0;
}

方法三(原理就是在同一个数组中时,一个元素的地址减去另一个得到的就是中间元素的数量)

#include<string.h>
#include<stdio.h>
#include<assert.h>
int my_strlen(const char* p)
{
assert(p);//assert是断言,防止传入的是一个空指针。
char* s1 = p;
while (*p != '\0')
{
p++;
}
char* s2 = p;
return s2 - s1;
}
int main()
{
char arr[] = "abcdefgh";
printf("%d", my_strlen(arr));
return 0;
}

下面我们就来学习使用strstr函数这个函数的功能就是:寻找目标字符串中是否存在比较字符串,也就是查找目标字符串中是否含有比较字符串

下面我们来使用这个函数

#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abbbcd";
char arr1[] = "bbcd";
printf("%s", strstr(arr, arr1));
return 0;
}//这个函数的功能就是查找一个字符串里有没有另一个字符串
//然后返回的就是查找字符串里面相同字符串的那个首字符的地址

从运行截图也能看出来它返回来的正是相同字符串里面那个首字符的地址

字符串操作函数总结_#include_16

下面我们来模拟实现这个函数

这是图解

字符串操作函数总结_字符串_17

#include<stdio.h>
#include<assert.h>
char* my_strstr(char* p1, const char* p2)
{
assert(p1 && p2);
char* s1 = NULL;
char* s2 = NULL;
char* cp = p1;
while (*cp)
{
s1 = cp;
s2 = p2;
while (*s1 == *s2&&*s1&&*s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return cp;
}
cp++;
}
return NULL;
}
int main()
{
char arr[] = "abbbcd";
char arr2[] = "bbcd";
if (NULL == my_strstr(arr, arr2))
{
printf("没有找到\n");
}
else
{
printf("%s", my_strstr(arr,arr2));
}
return 0;
}

运行截图如图上

希望这篇博客对您能有所帮助,如果您发现了任何错误,请一定严厉指出我一定迅速改正。


标签:总结,arr,return,函数,char,arr1,字符串,include
From: https://blog.51cto.com/u_15838996/6123597

相关文章

  • 每日总结 3.15
    今天实现了简单的线路查询,同一线路和不同线路的查询。下面是方法。  下面是演示:  点击查询后:  如果是在统一线路: ......
  • 每日总结2023/3/15
    今天实现了简单的线路查询,同一线路和不同线路的查询。下面是方法。  下面是演示:  点击查询后:  如果是在统一线路: ......
  • Java虚拟机详解——JVM常见问题总结
    面试必问关键词:JVM垃圾回收、类加载机制。 先把本文的目录画一个思维导图:一、Java引用的四种状态:强引用:用的最广。我们平时写代码时,new一个Object存放在堆内存......
  • 3/15每日总结
    在今天我学安卓的时候,发现能建一个表但是不能建两个表,于是我通过询问同学,我发现在数据库如果第一次有错误的时候,在以下的操作中,数据库还是会错误的,进行删除,重新启动就行。......
  • 递归函数
    递归函数目录递归函数1.什么是递归函数2、递归函数有啥优缺点3、通过实例来介绍函数递归:1.什么是递归函数​ 在函数内部,可以调用其他函数,如果一个函数在内部调用自......
  • JNA字符串类型操作
    1.返回字符串类型c/c++代码全局变量charretp[1024];constchar*getStr1(inta,intb){memset(retp,0,1024);charoutstr[256];memset(outstr,......
  • 2023武汉多校集训总结
    一共考了5场试,讲了3次课。中间时间学习了回滚莫队和带修改莫队,CDQ分治。CDQ分治是一种思想,作用是在复杂的点对关系(一般是多个参数的关系),优化一种关系。集训难度很大,主要......
  • 剑指 Offer 58 - II. 左旋转字符串
    题目剑指Offer58-II.左旋转字符串字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"......
  • 3.15总结
      赶快学习,再不学就跟不上进度了,能做的的事情极其有限,缺乏相关知识,学习劲头没有多少,恶性循环呗......
  • 每日总结-23.3.15
    今日新建一个类数组后,对其内容赋值出现了以下问题。Pd[]pdd=newPd[20];Cannotassignfield"mingcheng"because"pdd2[0]"isnull翻阅资料后得知当我从数组中......