【问题标题】:C strcmp behaving strangelyC strcmp 行为异常
【发布时间】:2015-11-22 16:41:47
【问题描述】:

好吧,我不确定这是我还是其他人,但我真的很困惑。

我试图找到一个字符串在另一个字符串中的第一次出现(就像 C++ 中的 InString()),但来自 C 并使用 strcmp()。

我有两个 char 数组,string[] 和 toFind[],我在两个 for() 循环中遍历它们,将每个 char 与 strcmp() 进行比较。

代码如下:

int inString(char string[], char toFind[]){

int i_toFind, i_string, check = 0, start = -1;

for(i_toFind = 0; i_toFind < getLength(toFind)-1; i_toFind++){

    for(i_string = 0; i_string < getLength(string)-1; i_string++){

        if(strcmp(&string[i_string], &toFind[i_toFind])==0){

            printf("%i & %i == %i\n", string[i_string], toFind[i_toFind], strcmp(&string[i_string], &toFind[i_toFind]));

            if(start == -1){
                start = i_string;
            }

            check++;
            i_toFind++;

            if(check == getLength(toFind)-1){
                return start;
            }

        }
        else{

            printf("%i & %i == %i\n", string[i_string], toFind[i_toFind], strcmp(&string[i_string], &toFind[i_toFind]));

            check = 0;
            start = -1;

        }

    }

}

return -1;

}

现在这适用于这个值:

string[] = "hello my friend"
toFind[] = "friend"

result:

104 & 102 == 2
101 & 102 == -1
108 & 102 == 6
108 & 102 == 6
111 & 102 == 9
32 & 102 == -70
109 & 102 == 7
121 & 102 == 19
32 & 102 == -70
102 & 102 == 0
114 & 114 == 0
105 & 105 == 0
101 & 101 == 0
110 & 110 == 0
100 & 100 == 0

但这是行不通的:

string[] = "friday friend comes"
toFind[] = "friend"

result:

102 & 102 == -1
114 & 102 == 12
105 & 102 == 3
100 & 102 == -2
97 & 102 == -5
121 & 102 == 19
32 & 102 == -70
102 & 102 == 22
114 & 102 == 12
105 & 102 == 3
101 & 102 == -1
110 & 102 == 8
100 & 102 == -2
32 & 102 == -70
99 & 102 == -3
111 & 102 == 9
109 & 102 == 7
101 & 102 == -1
115 & 102 == 13
102 & 114 == -12
114 & 114 == -1
105 & 114 == -9
...

有趣的是:

102 & 102 == -1
114 & 114 == -1

如果相等,这不应该是 0 吗?或者我在这里错过了什么? 如果我正在搜索的单词不是 string[] 中的最后一个单词,我编写的函数似乎只会失败。

希望有人能真正找到我的错误.. 谢谢!

更新:

我运行 InString() 的代码只有一行:

printf("Beginn: %i\n", inString(string, substring));

更新 2:

这是一个简单的问题示例:

int inString(char string[], char toFind[]){

    const char *pointer_toStart = strstr(string, toFind);

    return pointer_toStart ? pointer_toStart - string : -1;

}

int main(int argc, const char * argv[]) {

    char string[300], substring[300];

    printf("String: ");

    fgets(&test, 20, stdin); // To capture the one '\n' inside the buffer (just ignore this line)
    fgets(string, 300, stdin);

    printf("toFind: ");

    fgets(substring, 300, stdin);

    printf("Beginn: %i\n", inString(string, substring));

}

【问题讨论】:

  • 您不能使用strcmp 来比较单个字符。
  • 既然您使用的是 c 字符串函数,为什么不将 getLength 替换为 strlen
  • strstr() 可能是要使用的。
  • 您确定不想要strstr() 吗?如果您尝试实现strstr(),则不清楚strcmp() 是否有用;您也许可以使用strncmp(),但即使这样也比在字符而不是字符串上执行工作更有可能出现问题。
  • getLength() 使用的是strlen,所以基本一样。我没有使用 strstr() 因为那给了我一个指针对吗?我如何从中获取搜索字符串的起始位置?

标签: c char compare strcmp


【解决方案1】:

您不能使用strcmp 来比较C 字符串的各个部分,您可以使用memcmp 进行比较。但是使用strstr 可以更简单地解决您的问题。

这是根据您的隐式规范的 inString 的简单实现。

#include <string.h>

int inString(const char *string, const char *toFind) {
    const char *p = strstr(string, toFind);
    return p ? p - string : -1;
}

如果找到该函数返回子字符串的起始索引,如果没有找到则返回-1

使用此实现,以下测试正确打印25

#include <stdio.h>

int main(void) {
    char string[] = "Friede freude Eierkuchen freuen sich freundlich";
    char toFind[] = "freuen";

    printf("inString(\"%s\", \"%s\") -> %d\n", string, toFind, inString(string, toFind));
    return 0;
}

在您的测试代码中,您使用fgets 从标准输入中读取字符串。两个字符串都可能包含一个最终的'\n',因此您将找不到与"freuen\n" 的匹配项,除非它位于string 的末尾,也有一个最终的'\n'。通过删除'\n' 更正此问题。这是一个简单的剥离方法,如果它不存在也可以:

string[strcspn(string, "\n")] = '\0';
toFind[strcspn(toFind, "\n")] = '\0';

【讨论】:

  • 哇,谢谢你的回答!你能解释一下最后一行(返回值的位置)是做什么的吗? (从未见过这种语法。。)
  • 三元运算符类似于 if/then/else 表达式。最后一行可以这样写:if (p != NULL) return p - string; else return -1;。编译器可能会为两个版本生成完全相同的代码。
  • 非常感谢!可悲的是,它似乎也不适用于所有字符串: string[] = "friede freude eierkuchen freuen sich freundlich" | toFind[] = "freuen" |结果 = -1
  • 三元运算符是最丑的 C 运算符 :))
  • 那可能是真的,但为什么 strstr() 也像我的自我实现一样失败了?
【解决方案2】:

好的,首先非常感谢 chqrlie 为我提供了这么多帮助并为我指明了正确的方向。

我尝试了你提到的,从 string[] 和 toFind[] 中删除了 '\n',但我仍然以同样的问题结束。

为我解决的问题是使用我在开头发布的方法,而不是使用 memcmp() 来代替 strcmp()。做到了。所以这是我的 inString() 现在的样子:

int inString(char string[], char toFind[]){

     int i_toFind, i_string, check = 0, start = -1;

     for(i_toFind = 0; i_toFind < getLength(toFind)-1; i_toFind++){

       for(i_string = 0; i_string < getLength(string); i_string++){

         if(memcmp(&string[i_string], &toFind[i_toFind], 1)==0){

           if(start == -1){

             start = i_string;

           }

           check++;
           i_toFind++;

           if(check == getLength(toFind)-1){
             return start;
           }

         }
         else{

         i_toFind = i_toFind - check;

         check = 0;
         start = -1;

         }

       }

     }

     return -1;

}

在上面提到的例子中也给了我 25 个。

【讨论】:

  • 你的函数还是太复杂了。与其使用 memcmp 一次比较 1 个字节(一个简单的 == 运算符就足够了),不如使用它比较 string 中连续位置的 strlen(toFind) 字节,从 0strlen(string)-strlen(toFind) 包括在内.首先计算字符串长度并使用单个 for 循环进行测试,返回第一个匹配的偏移量,如果所有比较都失败,则返回 -1
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多