0


c语言判断字符串str1中含有字符串str2(是否为子串问题)

一、可以用三种方式解决子串问题:函数strstr、指针、子串出现的首个位置。

先举几个例子来说明一下什么样的字符串可以称作子串(区分大小写,假设字符串数组长度为20):

令str1[20]="dou LUO da lu";

1.str2[20]="da l";是子串;

2.str2[20]="dal";不是子串;

3.str2[20]="LUO";是子串;

4.str2[20]="Luo";不是子串;

5.str2[20]="dou da";不是子串。

二、使用函数strstr判断str1中是否包含str2

1.strstr函数在库函数"string.h"中,它的使用方法是strstr(str1,str2),函数得到的是地址,并不是数据内容,所以要用指针变量来接收;

2.如果判断str2是子串,就会返回str1中首次出现str2加上其后的内容,否则返回null;

举个例子:str1[20]="dou LUO da lu"; str2[20]="da l";那么strstr(str1,str2)返回的内容是"da lu";

3.运行代码和结果(codeblocks和手机程序C Compiler可运行)

#include<stdio.h>
#include<string.h>
void main()
{
    char str1[20],str2[20];
    char *str;//设置指针变量来存储子串在母串中的地址
    printf("请输入被查找字符串str1:");
    scanf("%s",str1);
    printf("要查找的字符串str2:");
    scanf("%s",str2);
    str=strstr(str1,str2);
    if(str)//判断str是否为空,不能写成str!=null
    {
        printf("str2是子串:%s\n",str);
    }
    else
    {
        printf("str2不是子串:%s\n",str);
    }
}

注意代码中进行比较的两个字符串是运行程序后手动输入的,用的scanf函数获取,所以字符串得是连续的,若有空格则会自动将前两个字符串分别赋值给str1和str2,至于第二个空格及以后有多少内容都不管,看结果就知道了:

所以可以把原代码中的scanf函数改成:

    printf("请分别输入字符串str1和str2,用空格隔开:");
    scanf("%s%s",str1,str2);

运行结果:

4.如果不用输入的方式,直接在程序中给定两个字符串的话,可以有多个空格,代码如下:

#include<stdio.h>
#include<string.h>
int main()
{
    char str1[20]="dou LUO da lu";
    char str2[20]=" LUO d";//注意必须写成数组型,一定要带下标[N]!!
    char *str;
    str=strstr(str1,str2);
    printf("根据结果自行判断:%s\n",str);
}

关于strstr函数的详细定义可以参看https://www.runoob.com/cprogramming/c-function-strstr.html

三、利用指针来判断是否为子串

1.基本思路:利用指针p依次遍历str1,每遍历一位字符便将之与str2的首地址值q进行比较,如果相同则两个指针同时自增,然后依次向后比较,若不同则指针p往下移动一位,再与str2的首地址值q进行比较,循环往复,直到str2遍历完(即确定str2为子串),或者str1遍历完。

①外层循环:for(p=str1;p;p++)意思是从首地址开始,只要p不等于'0',则执行内嵌语句块,然后自增;

②内层循环:for(q=str2;*p==*q&&*q;p++,q++); 意思是从首地址开始,判断两个字符串的值是否相等且str2是否遍历完,因为for语句后面有分号,表示它没有内嵌语句,所以若判断为真则执行第三表达式,判断为假则退出内层循环,执行外循中内嵌的其他语句,然后再执行外层循环,接着再从头开始执行内层循环。

关于for循环的详细用法可参看http://c.biancheng.net/cpp/html/45.html

2.指针初始化与赋值需要注意,在c语言里没有总体处理一个字符串的机制。例如:

①char *p="asdfgh"; 初始化,指针p指向字符串首地址

②char *p; p="asdfgh"; 赋值,指针p指向字符串首地址

③char a[10],*p; p=a; 赋值,数组的变量名a表示该数组的首地址

④int a=1; int b[10]; int *p=&a; int *q=b; int *w=&b[0];这些指针初始化都是正确的

总的来说,指针p指向地址,而*p指向数据,详细了解指针可参看https://www.cnblogs.com/mfrbuaa/p/3756342.html

3.代码及运行情况:

#include<stdio.h>

int main()
{
    char str1[20]="sadadadf";
    char str2[20]="adf";
    char *p=str1,*q=str2;//指针初始化,赋以首地址
    int flag=0;//设置一个变量来判断是否为子串

    for(p=str1;*p;p++)//将str1的首地址赋给p;第二个表达式判断字符是否为‘0’;
    {
        for(q=str2;*p==*q&&*q;p++,q++);//注意这里有分号!!这个for语句没有内嵌代码

        if(!*q)//如果str2遍历完,此时*q的值一定是默认值‘0’,那么!*q为真
        {
            flag=1;
            break;//得到想要的答案之后就跳出循环
        }
    }
    if(flag==1) printf("是");
    else puts("否");//判断后执行紧邻第一句,可以不加大括号{},puts()和printf()都可以输出

}

啰嗦几句:最开始用while语句写的代码,发现运行结果不对,调试之后还是for循环好用点,但这个程序还是有个小问题,如果str1="sadadf"; str2="adf"; 运行结果显示“否”,不正确,若str2="df",运行结果为“是”,是对的,那是因为内层循环比较到str1[3]和str2[2]时,前者是‘a’,后者是‘f’,这时候内存循环结束,外层循环执行第三表达式p++,这时候*p='d',再执行内层循环也得不到想要的结果了,我就想着是不是可以再增加一个内层循环,可是呢,对于现在这两个字符串来说,结果是对了,可是如果str1="sadadadf";结果又会出错,还是跟之前一样的问题,嗯~一般情况下还是好使的,不过下面这种不用函数和指针的方法更好,没有这些问题!

四、不用函数和指针,返回子串在母串中出现的首位置

1.用getchar()来获取一个个字符,依次存入数组当中;

getchar()的具体用法可参见https://www.runoob.com/cprogramming/c-function-getchar.html

2.用while循环将获得的字符依次存入数组中:while((c=getchar())!='\n') a[num++]=c;

①如果获得的字符不是回车符,就存入数组a中,包括空格。注意while循环后没有大括号{}或分号;时,则紧邻的第一句为其循环体;

②num=0;则(num++)=0,num=1,所以是从a[0]开始存,存到最后一个字符a[num-1],循环结束。

3.进行判断,如果是子串,返回并输出子串在母串中出现的首位置,否则什么都不返回。(同while一样,若for和if后面没有分号和大括号,则紧跟的第一句为其循环体)

首先,外层循环先依次判断母串元素a[i]与要查找串的首位值b[0]是否相等,如果相等则进行下一步循环与比较,内循表达式如下:

if(a[i]==b[0])
{
    for(j=1;j<lb;j++)
        if(a[i+j]!=b[j])
            break;
    if(j==lb)
    {
    printf("%d\n",i+1);
    }
}

因为前面已经判断了a[i]与b[0]相等,所以将数组下标分别下移一位,再比较,每比较一次就判断是否相等,如果相等,下标下移并比较;如果不相等则退出内层循环,判断j与lb是否相等(此时肯定不相等的,只是遵从顺序执行规则,要判断一次),再回到if(a[i]==b[0])语句,此时a的下标已经变成了i+j,即i=i+j,将这一位与b的首位再比较,若相等则循环比较,若不相等则退回到外层循环。

如果比较之后确定为子串,那么子串一定遍历完,此时jj与lb一定相等。

4.代码及运行情况:

#include<stdio.h>
#include<string.h>
int main()
{
    int i,j,la,lb,num=0;
    char c,a[120],b[100];
    printf("请输入母串:");
    while((c=getchar())!='\n')//while循环后没有大括号{}或分号;时,则紧邻的第一句为其循环体
        a[num++]=c;//用数组a存储被查找字符串

    num=0;//num一定要重新赋值为0,否则数组b的值就不是从首地址开始
    printf("输入要查找的字符串:");
    while((c=getchar())!='\n')
        b[num++]=c;//用数组b存储要查找的字符串

    la=strlen(a);
    lb=strlen(b);
    for(i=0;(la-i)>=lb;i++)//如果遍历到i还没行,将剩下的串长与要查找的串长相比,若还大,接着循环,若小,就不用再比较了
    {
        if(a[i]==b[0])
        {
            for(j=1;j<lb;j++)
                if(a[i+j]!=b[j])//for后面没有分号和大括号,所以紧跟的第一句为其循环体
                    break;//if后面没有分号和大括号,所以紧跟的第一句为其循环体
            if(j==lb)
            {
                printf("子串出现的首位置是母串第%d位\n",i+1);
                break;
            }
        }
    }

}

文中三种思路来源于文章https://blog.csdn.net/fakine/article/details/7517417/

写在最后:每次代码看懂了,复制能够运行,然后自己码一遍,结果运行没问题,但就是结果出了问题,前前后后仔细对比,就是不知道哪里错了,感觉都是对的啊,每次到最后找到问题所在时,基本上都是咪咪小问题被忽略了,就造成了大问题,比如多个或少个分号啊空格,或者数据类型搞的不对、少个简单但很关键的语句等,好的习惯需要更多训练。

标签: 字符串 指针

本文转载自: https://blog.csdn.net/m0_53182716/article/details/111404291
版权归原作者 一只傲娇孤鹜 所有, 如有侵权,请联系我们删除。

“c语言判断字符串str1中含有字符串str2(是否为子串问题)”的评论:

还没有评论