C - 检查一个字符串是否是另一个字符串的子串

3
我需要编写一个程序,该程序以两个字符串作为参数,并检查第二个字符串是否是第一个字符串的子字符串。我需要在不使用任何特殊库函数的情况下完成它。我创建了这个实现,但我认为只要两个字符串中有一个字母相同,它就总是返回true。你能帮我看看吗?我不确定我做错了什么:
#include <stdio.h>
#include <string.h>

int my_strstr( char const *s, char const *sub ) {
    char const *ret = sub;

    int r = 0;
    while ( ret = strchr( ret, *sub ) ) {
        if ( strcmp( ++ret, sub+1 ) == 0 ){
            r = 1;
        }
        else{
            r = 0;
        }        
    }
    return r;
}

int main(int argc, char **argv){

    if (argc != 3) {
        printf ("Usage: check <string one> <string two>\n");
    }
    int result = my_strstr(argv[1], argv[2]);

    if(result == 1){
        printf("%s is a substring of %s\n", argv[2], argv[1]);
    } else{
        printf("%s is not a substring of %s\n", argv[2], argv[1]);
    }
    return 0;
}

4
如果你“需要在不使用任何特殊库函数”的情况下完成任务,那么你不应该使用strchr和strcmp。实际上,strcmp正是导致你问题的地方。 - stmax
@stmax:那些只是普通的库函数。它们没有什么特别的 :) - Daniel Daranas
@Daniel:如果 strchr()strcmp() 是普通的函数,那么 strstr() 也是。 - Jonathan Leffler
@Jonathan Leffler:当然。我指出的实际上是,事实上没有“特殊”的库函数——只有库函数,就这样。 - Daniel Daranas
6个回答

3
你编写 strstr 的方法基本上是有缺陷的。让我们看看你所写的内容:
char const *ret = sub;

int r = 0;
while ( ret = strchr( ret, *sub ) ) {
    if ( strcmp( ++ret, sub+1 ) == 0 ){
        r = 1;
    }
    else{
        r = 0;
    }        
}
return r;

首先,由于您将ret初始化为指向sub,因此您正在将sub与其本身进行比较,并且从未查看s。但是让我们假设您的意思是将ret初始化为s... ret = strchr( ret, *sub ) 找到sub中下一个字符在ret中的位置,然后将ret向前移动,以便它从该字符开始。
然后,您执行strcmp(++ret, sub+1),该函数确定从ret的下一个字符开始的字符串是否等于从sub的下一个字符开始的字符串,然后将ret移动到下一个字符(无论测试结果是真还是假)。
显然,这种逻辑并不是您想要的。实际上,它将确定子字符串是否等于字符串s或者是否位于字符串s的结尾并且不包含重复的字母。
以下是您需要的算法的一般概述:
  1. s中找到sub的第一个字符的位置。如果未找到,则返回false。
  2. 更新s,使其从该位置开始
  3. 假设sub的长度为n,则测试s的前n个字符是否与sub匹配(小心不要超出s的末尾)。如果是,则返回true。否则,将s向前移动一个字符并循环。
请注意,您永远不应在sub中搜索除第一个字符以外的任何字符。想法是使用sub的第一个字符来查找ssub的潜在起始位置,然后检查子字符串sub是否实际存在于那里。如果不存在,则要丢弃到该点的s的所有内容,然后重新开始尝试找到下一个潜在的起始位置。

1

嗯,你不应该在my_strstr中修改ret。而且strcmp并不是比较子字符串,它比较的是整个字符串。你可能想要使用strncmp


0
char const *ret = sub;

int r = 0;
while ( ret = strchr( ret, *sub ) ) {

ret 存储了子数组的地址,在 while 语句中使用 strchr(ret,*sub) 比较 sub 中的值与存储在 ret 中的地址是否相同,这样做是否可行(比较是否正确)?请有经验的人回答一下...


0

看起来你正在char * sub中搜索char * sub:

int my_strstr( char const *s, char const *sub ) {
char const *ret = sub;

你应该将ret设置为s吗?

另外,strcmp比较的是字符串而不是子字符串,因此strcmp(“abcde”,“abc”)返回false。你可能想要使用strncmp,它还需要一个指定长度的整数。


0

ret = strchr( ret, *sub )

当首次遇到ret == sub时,strchr(ret, *sub)会在ret中搜索ret的第一个字符的第一次出现。这将返回ret

因此,ret保持不变。

接下来,

strcmp( ++ret, sub+1 ) == 0 

ret 仍然等于 sub,因此上述语句为

并且您将获得 1 作为返回值。


0

将此任务分解为不同的部分可能会有所帮助。该任务有两个关键部分:1)查找潜在子字符串匹配的起始点和2)测试该起始点是否确实是匹配的子字符串。因此,将其实现为两个函数。

首先,创建一个确定两个字符串是否完全相同的函数。这应该相对容易编码,只需将第一个字母与第二个字母进行比较等等。如果您发现两个字符串不匹配,则返回false。如果您到达其中一个字符串的末尾,则返回true。如果允许使用strncmp,则这将简单地是(strncmp(a, b, strlen(b)) == 0)(假设b始终是较短的字符串)。

其次,创建一个函数来循环一个字符串,查找特定的字母。每当它找到这个字母时,它调用一个函数并传递该字母在字符串中的指针。换句话说,如果你调用了my_function("This is a sample string", 's'),那么该函数应该遍历字符串,找到所有四个' s '字母的实例,并使用该字符串中该字母的指针调用一个函数。在这种情况下,您将调用前面段落中描述的函数。
使用这种方法,只要任何子函数调用返回"true",就立即返回"true",或者如果您完成对输入字符串的扫描,则返回"false"。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接