大家好,我们又见面了,让大家久等了,我们今天就来学习字符函数和字符串函数。
在开启今天的学习之前呢,我来解决一下一些小伙伴平时找不到库函数使用的烦恼,因为我们cplusplus.com最新版本不能够查询函数,我们需要去找我们需要使用的函数,所以就很麻烦,我们可以将它切换成老版本就可以进行查询了。
我们只要点击这个红色框就能够切换成老版本了。
然后我们点击红色框输入我们想要知道的函数就可以实现查询了。
1.strlen函数
我们以前接触过这个函数,这个函数是用来求字符串或字符长度的对吧,求的是‘/0’之前的字符个数。
我们在这里需要注意的是:
字符串已经 ‘\0’ 作为结束标志,strlen函数返回的是在字符串中 ‘\0’ 前面出现的字符个数(不包
含 ‘\0’ )
参数指向的字符串必须要以 ‘\0’ 结束。
注意函数的返回值为size_t,是无符号的( 易错 )
学会strlen函数的模拟实现
那么我们怎么来使用它呢,我们看到代码:
#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");
}
return 0;
}
我们因为str1里面‘\0’前面有六个字符,所以strlen的结果就是6,而str2的结果就只有3,但是我们这里函数的返回类型size_t,也就是无符号数,我们得到的结果是-3,但是我们这里的结果之后也得转化为一个无符号数,就会是一个很大的正数,所以结果就会输出str2>str1。
那么怎么对这个函数模拟实现呢?
#include<stdio.h>
#include<assert.h>
#include<windows.h>
int my_strlen(const char *str)
{
int count = 0;
assert(str != NULL);//断言,指针为空,打印出错误信息
while (*str++)//遇到'\0'停止,不算'\0'
{
count++;
}
return count;
}
int main()
{
int len=0;
char *p = "abcdef";
len=my_strlen(p);
printf("len=%d\n", len);
system("pause");
return 0;
}
这里我们要注意我们的传过去的*p,因为我们只求它的字符个数,所以我们不用改变它,就给它用const进行保护,我们为了防止空指针,所以要给它进行断言,我们在使用断言的时候,我们要加上头文件#include<assert.h>,因为我们这里是要求它的字符个数,所以我们需要碰到一个字符就给它计数,所以我们要定义一个计数器,并且对它初始化,我们接下来就利用循环结构就行,当我们碰到一个字符就计数,碰到‘\0’的时候得到’\0’,它的Ascall值为0,所以我们碰到‘\0’的时候就为假,就跳出循环了,最后在将结果返回主函数进行打印。
2.strcpy
源字符串必须以 ‘\0’ 结束。
会将源字符串中的 ‘\0’ 拷贝到目标空间。
目标空间必须足够大,以确保能存放源字符串。
目标空间必须可变。
学会模拟实现。
接下来我们就给它模拟实现以下:
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = { 0 };
char arr2[] = "abc";
/*my_strcpy(arr1, arr2);
printf("%s\n", arr1);*/
printf("%s\n", my_strcpy(arr1, arr2));
return 0;
}
我们这里定义两个字符数组,将这两个数组的地址传到我们自定义的函数my_strcat中,通过两个指针接收,这里我们依然要给它进行断言,因为我们要把第二个数组的元素拷贝到第一个元素当中,所以我们第二个元素是不变的,所以就用const对它进行保护,首先我们用一个循环找到数组的一个末尾,然后再循环将指针str中的内容拷贝到指针dest中,当dest为’/0’时,整个式子的结果为假就跳出循环。再将指针ret储存的数据返回进行打印。
3.strcat
连接函数:
源字符串必须以 ‘\0’ 结束。
目标空间必须有足够的大,能容纳下源字符串的内容。
目标空间必须可修改。
字符串自己给自己追加,如何
char* my_strcat(char* dest, const char* src)
{
char* ret = dest;
assert(dest && src);
//1. 找到目标空间的末尾
while (*dest != '\0')
{
dest++;
}
//2. 数据追加
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "abc";
strcat(arr1, arr1);//strncat
printf("%s\n", arr1);
return 0;
}
在这个函数我们要知道连接函数strcat和拷贝函数strcpy一样,我们要连接的数组是从上一个数组的‘/0’开始,而且第二个数组的‘\0’也会连接到上一个数组作为结束的标志。所以当我们字符串自己给自己追加也会打印出结果。我们在这里也要进行断言,为了防止变成空指针。
4.strcmp
比较字符串函数:
第一个字符串大于第二个字符串,则返回大于0的数字
第一个字符串等于第二个字符串,则返回0
第一个字符串小于第二个字符串,则返回小于0的数字
那么我们怎么去比较两个字符串的大小呢?我们其实是比较两个字符串函数之间对应位置字符的ASCLL值的小,如果前一个相同的话就比较下一个,一直比较下去直到比较出大小为止。
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
return *str1 - *str2;
}
int main()
{
char arr1[] = "abq";
char arr2[] = "abc";
if (my_strcmp(arr1, arr2) > 0)
{
printf(">\n");
}
else
{
printf("<=\n");
}
return 0;
}
我们这里将两个数组的地址传到函数中,我们进入循环中,如果第一个字符的值都相等,如果此时的str1=‘/0’的话,那么str2也为’\0’,所以两个字符串大小相等,如果str1!=0,那么我们就进行下一个字符的比较,最后返回str1-str2到主函数中进行判断和打印结果。
5.strncpy, strncat,strncmp
我们看到这里的三个函数和上面我们刚学的一些函数有些相似,那么我们就以strcpy和strncpy函数为例来讲解。
我们发现下面这个函数多了一个参数,而且是一个无符号数的参数,那么这个参数具体的作用是什么呢?其实这个参数是进行限制作用的,我们这个拷贝函数,如果给num一个值,那么num就是我们拷贝过去的字符个数。
int main()
{
char arr1[20] = { 0 };
char arr2[] = "abcdefghi";
strncpy(arr1, arr2, 3);
printf("%s\n", arr1);
return 0;
}
因为我们这里传的参数是3,所以我们只拷贝三个字符上去,所以得到的结果是abc。
int main()
{
char arr1[20] = "abc\0xxxxxxxxxxxxxx";
char arr2[] = "defghi";
strncat(arr1, arr2, 10);
printf("%s\n", arr1);
return 0;
}
我们这里用的连接函数是10个字符,所以我们全部都可以连接上去。但是我们要注意拷贝的时候如果我们要拷贝10个字符上去,而我们这个数组少于10个字符的时候后面多的位置就会补充’\0’,而我们的连接函数则不会补充’\0’,这就是这两个函数的区别。另外两个也是类似的,这里就不一一进行讲解了。
6.strstr
上面这个是c++,而下面这个才是我们C语言的库函数。这个函数的作用呢就是在一个字符串里找到我们出现的字符串。也就是说要从我们str1里面找到str2的字符串。
#include<stdio.h>
#include<assert.h>
const char* my_strstr(const char* str1, const char* str2)
{
const char* cp;//记录开始匹配的位置
const char* s1;//遍历str1指向的字符串
const char* s2;//遍历str2指向的字符串
assert(str1 && str2);
if (*str2 == '\0')
return str1;
cp = str1;
while (*cp)
{
s1 = cp;
s2 = str2;
while (*s1 && *s2 && *s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
return cp;
cp++;
}
return NULL;
}
int main()
{
char arr1[] = "abbbcdef";
char arr2[] = "bbc";
const char* ret = my_strstr(arr1, arr2);
if (ret == NULL)
{
printf("找不到\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
在做这个题的时候我们需要用到多个指针,因为我们要两个指针指向刚开始的位置,用另外的指针去移动,在用指针给储存起来,在这里我们的s1和s2指针是用来遍历的,我们先用if语句进行判断,如果我们的str2为’\0’时,就返回str1,因为我们在集合中就已经知道空集合是任意集合的子集,当我们的str2指针为’\0’时,我们才会将str1的指针用cp来接收,然后我们将cp指针和str2指针分别赋给s1和s2指针,前提是cp不能为不能为’\0’,然后我们进入下一个循环,当s1和s2为’\0’和s1与s2相等时,我们就给他们进行下一个字符的比较,如果不相等我们就跳出循环,跳出循环后要对指针s2进行判断,如果我们的s2指针为’\0’的话,我们就返回cp,cp++我们就下一个字符作为第一个字符开始遍历,如果一直到指针cp为’\0’的时候都没有找到,那就返回NULL空指针。
7.strtok
sep参数是个字符串,定义了用作分隔符的字符集合
第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记
strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记,则返回 NULL 指针。
这个函数的作用是用分隔符将我们的一些字符串给分隔开,而我们将分隔符储存到一个指针sep中,当我们需要用到的时候就给它传参就行了。
int main()
{
char arr[] = "zpengwei@yeah.net";
char buf[200] = {0};//"zpengwei@yeah.net"
strcpy(buf, arr);
char* p = "@.";
char* s = strtok(buf, p);
printf("%s\n", s);
s = strtok(NULL, p);
printf("%s\n", s);
s = strtok(NULL, p);
printf("%s\n", s);
return 0;
}
我们将分隔符@和.存入一个指针p中,当我们对字符串进行操作的时候我们就取分隔符前面的字符串,并且将分隔符的位置保存下来,然后我们想要对下面的字符串进行打印的话,就要重复对字符串进行该函数操作,不过这里传参不同,我们传参的第一个位置变成了空指针NULL,而我们的就会从上一次标记的地方开始,找到下一个分隔符,将字符串输出。
8. strerror
这个函数的作用是返回错误码,所对应的错误信息。
#include<errno.h>
int main()
{
int i = 0;
for (i = 0; i < 10; i++)
{
printf("%d: %s\n", i, strerror(i));
}
return 0;
}
在使用这个函数我们会用到全新的头文件,这个我们要记得,然后由于我们这个函数的作用是返回错误码所对应的信息,我们就可以利用循环来查看0到9的错误码所代表的信息。
好了,学到这里大家一定都很累了吧,我们今天的学习就到这里了,我们下次再见,谢谢大家。