给小朋友看的字符串
现在假设你是我助教班上的小朋友,预设你知道最基本的字符串相关知识,在这里强调一些非常重要的字符串相关知识,并试图简单引入一下指针,让你明白strstr应该怎么用。
两种输入方式
char a[10];
gets(a);
scanf("%s",a);
gets:
读一整行,不可能读一行的一半,把行末回车从缓冲区里取出,变成\0
放到最后。
如输入一行(既然都说输入了,行末肯定有回车)
hey you!
缓冲区里进来了九个字符:
`h` `e` `y` `空格` `y` `o` `u` `!` `\n`
a这个字符串变成了:
{`h`,`e`,`y`,`空格`,`y`,`o`,`u`,`!`,`\0`}
然后缓冲区里什么也没有了。
scanf:
不一定读一整行,遇到空白符(如空格)就停了。
如输入一行(既然都说输入了,行末肯定有回车)
hey you!
缓冲区里进来了九个字符:
`h` `e` `y` `空格` `y` `o` `u` `!` `\n`
a这个字符串变成了:
{`h`,`e`,`y`,'\0'}
然后缓冲区里剩:
`空格` `y` `o` `u` `!` `\n`
这时候如果后面还有scanf("%s",b);
或者gets(b)
等试图读一个字符串的语句,便不会等用户输入,直接从缓冲区里剩的字符里拿。
scanf %s会忽略前导空白符,遇到空白符就停
但gets不会,有啥要啥,一整行除了回车全是它的
应用
为什么hint让我们用gets(a)
读入?
因为如果用scanf("%s",a)
的话,long long
只能读进去long
,
剩下的空格long回车
还留在缓冲区里,干扰下一次输入。
顺带一提,输入2和5以后要怎么来着?
是不是要getchar?
如果不getchar,gets(a)就把缓冲区里的回车吃掉了。
多组输入
如果用scanf
while(scanf("%s",a)!=EOF)
{
//balabala
}
如果用gets
while(gets(a)!=NULL)
{
//balabala
}
重大误区
char a[20];
a="hello";
错!
char a[20];
char b[10]="hhh";
a=b;
错!
字符串不可以直接赋值哦。
char a[20]="hello";
if(a=="hello")
{
puts("ok");
}
错!字符串不可以用== > <来比较。
那怎么办
引入string库
#include<string.h>
用里面的库函数。
下面放一些不需要懂指针也可以明白的函数!
strlen
strcpy
strcmp
strcat
memset
#include<stdio.h>
#include<string.h>
/*-----------搞懂string.h-------------*/
int main()
{
/*---strlen是字符串的长度---*/
char a[100]="hhh";
int c=strlen(a);
printf("%d\n",c);//输出3
/*---strcpy(a,b)是把b的值给了a---*/
strcpy(a,"hello");
puts(a);//输出hello
char b[100]="world";
strcpy(a,b);
puts(a);//输出world
/*---strcmp(a,b)是比较字符串---*/
/*---strcmp(a,b)<0 字典里a在b前面---*/
/*---strcmp(a,b)>0 字典里a在b后面---*/
/*---strcmp(a,b)==0 a和b一模一样---*/
if(strcmp("hello","world")<0)
puts("ok");
if(strcmp(b,"world")==0)
puts("ok");
if(strcmp("car ","car")>0)
puts("ok");
//输出了三个ok
/*---strcat(a,b)是把b的值接到了a后面---*/
strcpy(a,"toyama") ;
strcpy(b,"kasumi");
strcat(a,"_");//a是"toyama_"
strcat(a,b);
puts(a);//输出toyama_kasumi
/*---memset(a,0,sizeof(a))是把数组元素很快地都设成0---*/
/*---memset(a,-1,sizeof(a))是把数组元素很快地都设成-1---*/
int d[3]={1,2,3};
memset(d,0,sizeof(d));
for(int i=0;i<3;i++)
printf("%d ",d[i]);//输出0 0 0
putchar('\n');
}
虽然strstr函数需要懂指针才能彻底了解,不过它有点好用,所以我粗略介绍一下,听不懂就不要听了!快乐备考最重要。
还记得函数那一节讲的返回值吗?
int max(int a,int b)
{
if(a>b) return a;
return b;
}
int max
里面的int,就代表着这个函数return的是一个int类型的变量。
double ave(int sum,int n)
{
return 1.0*sum/n;
}
double ave
里面的double,就代表着这个函数return的是一个double类型的变量。
如果我们在网上查一下strstr函数的原型,网上会这么告诉我们:
char* strstr(const char* haystack, const char* needle)
{
//balabala
}
char *
虽然很像char,但是char *
和char
是两种数据类型,char *
是指向一个char类型数据的指针类型变量。正如int *
是指向一个int类型数据的指针类型变量。double *
是指向一个double类型数据的指针类型变量。
如果我们用了一句
char a[10]="toyama";
strstr(a,"yam");
这一句strstr的值现在是个指针,char*类型,指向“yam”在"toyama"中第一次出现的位置,也就是这儿。
对,没错,指针就是个箭头,指向某个数据,在这里就是指向我们的a[2]。
顺带一提,我们定义数组的时候,数组名可以看做指向第一个字符的指针。当我们char a[10];
的时候,a的类型,可以说是char [10],也可以说是char *。如果把a当成指针的话,它指向哪儿呢?指向它的头头,也就是a[0]。
你可能会问,指针有什么用,我不会输入指针,也不会输出指针,也没有题让我求指针。
但是指针的差有用啊,能解决大问题。
一个字符串中,两个指针(箭头)的距离是几,两个指针(箭头)的差就是几->一个常数。
那么来看题,C6的字符串匹配。
这题可以这么做。
#include<stdio.h>
#include<string.h>
int main() {
char a[120],b[120];
gets(a);
gets(b);
if(strstr(a,b)!=NULL) {//如果strstr找不到就返回NULL,跟EOF差不多
printf("YES %d",strstr(a,b)-a);
}
else printf("NO");
return 0;
}
如果我们输入akizuki
和izu
,那么strstr(a,b)
和a
两个指针分别指向这里:
这两个指针中间差2(指针a往右挪两位,就到指针strstr(a,b)那里了)。
也就是“izu”在“akizuki”中最早出现的位置是第二位。(从第零位开始算)
再开拓思维一下,如果题目让你输出字符串A里,字符串B第一次出现及以后的所有字符,也就是让我们输出“izuki”的话,怎么办呢。
直接
printf("%s",strstr(a,b));
就行。
还记得上面说的吗,数组本质就是指针,这句话只是在输出一个字符串罢了。
就跟下面的这句话原理一样。
printf("%s",a);
a是一个从a[0]开始到a[6]结束的数组,那strstr(a,b)也是一个从a[2]开始到a[6]结束的,长度为5的数组呀,他们都是指针,指向哪儿,就从哪儿开始,到’\0’结束。
再开拓思维一下,如果题目让你输出字符串A里,字符串B第一次出现以后的所有字符,不包括字符串B,也就是让我们输出“ki”的话,怎么办呢。
直接
printf("%s",strstr(a,b)+strlen(b));
就行。
还记得上面说的吗,指针上面可以加减常数,相当于把指针向右(左)挪动几位。
再开拓思维一下,如果题目让你输出字符串A里,字符串B第一次出现及以前的所有字符,也就是让我们输出“akizu”的话,怎么办呢。
直接
a[strstr(a,b)-a+strlen(b)]='\0';
printf("%s",a);
看起来有点复杂,不过只是把a[5]从’k’变成了‘\0’哦,因为字符串输出到\0为止,也是刚刚说过的问题。
这是包学姐和贠学长当年E6的题。
你当然可以用暴力法,一位一位对着来解决这道问题,你也可以用strstr的各种妙用,更方便并且不容易出错。
这是strstr法的标程。
#include <stdio.h>
int main()
{
char a[20],b[20];
char *p;
int len;
gets(a);
gets(b);
len = strlen(b);
p = a;//让指针p和指针a一开始指的一样
while((p = strstr(p, b))!=NULL){//如果还能找到子串
printf("%d-%d\n",p-a, p-a+len-1);
p += len;//指针p往右挪子串那么长
}
return 0;
}
PS.这些开拓思维如果觉得听起来比较困难就不要管了!暴力循环永远滴神!
PPS.你说指针是箭头吧,那肯定不准确,这么说只是为了让小朋友在期中考试之前速成理解strstr怎么用罢了,等真正学指针了,别信我说的话。
PPPS.字符串很重要,跟排序和查找一样。