经过一段时间的学习,现在在这里写下这篇博客,以复习字符串操作函数
首先我用软件画了一张图,
这里面大概的介绍了字符串操作函数的用法,现在我们来详细的学习
首先就是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;
}
运行结果
和原字符串比较很明显被分割符,隔开的字符串被分别打印出来了
下面我们学习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就是错误码
下面的是运行结果图
这就是运行的信息。
但在实际情况中到底会怎么运行呢?
我们先来看这个工程的文件
可以发现我在这里创建了
一个名为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里的信息是会被覆盖的若你第一次打开文件失败,然后第二次打开文件成功,然后你这时候如果打印错误信息的话就会发现没有错误
//因为第一次的错误信息已经被覆盖了
运行结果
很明显这里就没有显示任何错误信息但若是我删除了那个文件
错误信息就被我打印出来了
哪么有没有一个函数既可以将错误码转化为错误信息,又有打印这个错误信息的功能呢,当然是有的那就是
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;
}
运行截图
下面我们来学习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;
}
运行截图
下面我们来模拟实现这个函数
//照例我们要实现这个函数首先就要知道它的原理
//首先我们传递过去的是两个字符数组的首元素地址然后将源头函数从开始一个一个的复制到目的函数的空间里直到源头函数读取到\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;
}
从运行截图可以看到,虽然出现了数组越界的报错,但是这个函数依旧将打印任务完成了,而这也是为什么这个函数是属于长度不受限制的函数。
对于此就有了一个比较安全的长度受限制的函数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中了注意这里的空格也占了一个字节
下面我们来模拟实现这个函数
#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;
}
运行截图
下面我们来模拟实现这个函数
#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<stdio.h>
#include<string.h>
int main()
{
char arr1[30] = "hello ";
char arr2[] = "world";
printf("%s",strncat(arr1,arr2,5));
return 0;
}
下面我们来模拟实现这个函数
#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;
}
下面是模拟实现这个函数
#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;
}
然后我们使用三种方法来模拟实现这个函数
第一种
//但是我们必须先弄懂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<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;
}
运行截图如图上
希望这篇博客对您能有所帮助,如果您发现了任何错误,请一定严厉指出我一定迅速改正。