【问题标题】:Why isn't this case insensitive version of strstr() function working?为什么这个不区分大小写的 strstr() 函数版本不起作用?
【发布时间】:2019-06-06 12:35:38
【问题描述】:

为了解决教科书问题,我正在尝试创建一个不区分大小写的函数版本,名为strstr(),它是用 C 语言编写的。到目前为止,我遇到了两个问题。第一个问题是,当我制作不区分大小写的strstr() 版本时,它可以工作,但它并没有在第一个匹配的字符串处停止,并且即使它们不匹配也会继续返回字符串。

strstr() 应该看到匹配字符的第一个实例,最多指定 n 个计数,然后停止。就像我写:"Xehanort" 在字符串A"Xemnas" 在字符串B 并指定4,作为number,它将返回Xe

不区分大小写版本背后的想法是,我可以在一个字符串中写入:"Xehanort",在下一个字符串中写入"xemnas",并让它返回Xe

但是,我在尝试过的新代码中遇到了一个新问题:该函数似乎根本不想运行。我已经对此进行了测试,结果发现该功能似乎崩溃了,我不知道如何让它停止。

我尝试过编辑代码,我尝试过使用不同的 for 循环,但我认为代码不需要太复杂,我还尝试过与您将要阅读的完全不同的代码,但这导致了前面提到的问题。

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>

#define MAX 100

char *stristr4(const char *p1, const char *p2, size_t num);

int main() {
    char c[MAX], d[MAX];
    printf("Please enter the string you want to compare.");
    gets(c);
    printf("Please enter the next string you want to compare.");
    gets(d);
    printf("The first string to be obtained from \n%s, and \n%s is \n%s",
           c, d, stristr4(c, d, MAX));
}

char *stristr4(const char *p1, const char *p2, size_t num) {
    const char *str1 = p1;
    const char *str2 = p2;
    char *str3;
    int counter = 0;

    for (int i = 0; i < num; i++) {
        for (int j = 0; j < num; j++) {
            if (tolower(str1[i]) == tolower(str2[j])) {
                str3[i] = str1[i];
                counter++;
            } else {
                if (counter > 0) {
                    break;
                } else
                    continue;
            }
        }
    }
    return str3;
}

您看到的代码将询问您要输入的字符串。理想情况下,它应该返回输入。

然后它应该执行stristr 函数并返回不区分大小写的匹配字符串的第一个实例。

但是,我创建的函数似乎并没有运行。

【问题讨论】:

  • "Strstr() 应该看到匹配字符的第一个实例,最多指定 n 个计数,然后停止。" strstr 不是这样工作的。跨度>
  • 你没有让char *str3;指向任何东西,然后你做了str3[i] = str1[i];。你的编译器不会在这里警告你吗?
  • @Matthew_J_Barnes "Xemnas""Xehanort" 中没有匹配项。你觉得strstr的目的是什么?
  • strstr 不寻找公共前缀;它进行子字符串搜索。 "Xemnas" 不是 "Xenahort" 的子字符串,所以不,没有匹配。
  • 你可能不应该复制字符串(当然也不应该修改它们)——但如果你这样做了,你必须管理空间。考虑一下您正在大海捞针(大事中的小事)。您应该返回一个指向大海捞针位置的指针。

标签: c string


【解决方案1】:

您的代码具有未定义的行为(在这种情况下会导致分段错误),因为您尝试通过未初始化的指针 str3 存储结果字符串。

标准函数strstr返回一个指向匹配子序列的指针,你也应该这样做。如果第一个和第二个参数是正确的 C 字符串,则第三个参数是无用的。

这是修改后的版本:

char *stristr4(const char *p1, const char *p2) {
    for (;; p1++) {
        for (size_t i = 0;; i++) {
            if (p2[i] == '\0')
                return (char *)p1;
            if (tolower((unsigned char)p1[i]) != tolower((unsigned char)p2[i]))
                break;
        }
        if (*p1 == '\0')
            return NULL;
    }
}

注意事项:

  • 函数tolower()&lt;ctype.h&gt; 中的其他函数一样,采用int,该int 必须具有unsigned char 的值或特殊的负值EOFchar 参数必须转换为 unsigned char 以避免负 char 值的未定义行为。 char 默认情况下可以签名或未签名,具体取决于平台和编译器设置。
  • 你不应该从不gets()。此功能已过时,无法安全使用不受控制的输入。使用fgets() 并去掉尾随的换行符:

    if (fgets(c, sizeof c, stdin)) {
        c[strcspn(c, "\n")] = '\0';
        ...
    }
    

【讨论】:

    【解决方案2】:

    可以将第三个字符串传递给函数并用匹配的字符填充该字符串。
    使用fgets 而不是gets

    #include <ctype.h>
    #include <stdio.h>
    #include <string.h>
    
    #define MAX 100
    
    int stristr4(const char* p1, const char *p2, char *same);
    
    int main( void)
    {
        int comp = 0;
        char c[MAX] = "", d[MAX] = "", match[MAX] = "";//initialize to all zero
    
        printf ( "Please enter the string you want to compare. ");
        fflush ( stdout);//printf has no newline so make sure it prints
        fgets ( c, MAX, stdin);
        c[strcspn ( c, "\n")] = 0;//remove newline
        printf ( "Please enter the next string you want to compare. ");
        fflush ( stdout);//printf has no newline so make sure it prints
        fgets ( d, MAX, stdin);
        d[strcspn ( d, "\n")] = 0;//remove newline
        comp = stristr4 ( c, d, match);
        printf ( "Comparison of \n%s, and \n%s  is \n%d\n", c, d, comp);
        if ( *match) {
            printf ( "The matching string to be obtained from \n%s, and \n%s is \n%s\n"
            , c, d, match);
        }
        return 0;
    }
    
    int stristr4 ( const char *p1,const char *p2, char *same)
    {
        //pointers not pointing to zero and tolower values are equal
        while ( *p1 && *p2 && tolower ( (unsigned char)*p1) == tolower ( (unsigned char)*p2))
        {
            *same = tolower ( (unsigned char)*p1);//count same characters
            same++;//increment to next character
            *same = 0;//zero terminate
            p1++;
            p2++;
        }
        return *p1 - *p2;//return difference
    }
    

    【讨论】:

    • 您应该将char 值传递给(unsigned char) 时将它们转换为(unsigned char),因为tolower() 对于负值具有未定义的行为,EOF 除外。 char 可以默认签名:在这种情况下,stristr4() 对非 ASCII 字符的字符串有未定义的行为。
    猜你喜欢
    • 2013-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-27
    • 2011-11-14
    • 2017-09-04
    相关资源
    最近更新 更多