0

我正在尝试逐个比较字符。我正在从课堂作业中模拟 strcmp 函数。这是我想出的。不幸的是,我总是得到 0,因为所有字符都匹配,直到它到达最后一个。我假设它只检查第一个字符并停止。我将 i++ 添加到下一个字符中,但我认为它不起作用。

strComp("abc", "abcd");

int strComp(char a[], char b[]) {
    int i = 0;

    if (strLen(a) == strLen(b)) {
        while (a[i] != NULL && b[i] != NULL) {
            if (a[i] == b[i]) {
                return 0;
            } else if(a[i] > b[i]) {
                return 1;
            } else {
                return -1;
            }
        }
        i++;
    } else if (strLen(a) > strLen(b)) {
        return 1;
    } else {
        return -1;
    }
}
4

5 回答 5

4

注意

  • NULL不同于'\0'
  • char[]真的腐烂成char*
  • 在 C/C++ 中,任何可以被声明的东西都const应该被声明const
  • strlen在这样的基本功能中使用是低效的

这是一个非常快速的解决方案:

inline int compare(char const* const a, char const* const b)
{
    /* Return -1 less than, 0 equal, 1 greater than */
    if (!a[0] && b[0])
        return -1;
    else if (a[0] && !b[0])
        return 1;
    register int i = 0;
    for (; a[i] && b[i]; i++) {
        if (a[i] < b[i])
            return -1;
        if (a[i] > b[i])
            return 1;
    }
    #if 1 /* this addition makes this code work like std::strcmp */
    if (!a[i] && b[i])
        return -1;
    else if (a[i] && !b[i])
        return 1;
    #endif
    return 0;
}

这个是我在 20 多年前编写的,作为 386 汇编程序的原型。对于不区分大小写的字符串,比较#include <locale>并修改 for 循环:

            .
            .
        for (; a[i] && b[i]; i++) {
            if (std::toupper(a[i]) < std::toupper(b[i]))
                return -1;
            if (std::toupper(a[i]) > std::toupper(b[i]))
                return 1;
        }
于 2013-10-17T06:54:15.197 回答
3

++i; 

在while循环内

上面只有两行...

于 2013-10-17T06:53:11.983 回答
1

只要看到两个不同的字符,您就可以检测到不匹配 - 但直到您到达字符串末尾并且字符仍然相同时才能检测到匹配。

至少在我看来,这方面的大多数尝试都将基本想法倒退,试图立即比较字符(一个或两个字符串为空的一些特殊情况)。相反,通常最好从跳过相等的非零字节开始。然后,您要么位于(至少一个)字符串的末尾,要么您发现两个字符串中的字节不匹配。无论哪种方式,此时您都可以理清发生了什么,并返回正确的值。

int cmp_str(char const *a, char const *b) {
    while (*a && *a == *b) {
        ++a;
        ++b;
    }
    if (*b < *a)
       return 1;
    if (*b > *a)
        return -1;
    return 0;    
}

这使循环非常简单,条件很少,因此可以快速执行。所有更复杂的比较来确定实际排序发生在循环之外,它们只发生一次,并且对速度几乎没有影响。

我可能应该添加一个警告:这并没有尝试正确处理国际字符。为此,您只需添加定义字符相对顺序的整理表,因为(至少在许多代码页中)字符的值与字符的排序顺序不对应。

值得一提的是,这里有一个快速测试,比较了 Andreascomparestrcmp标准库中的结果和速度:

int cmp_str(char const *a, char const *b) {
    while (*a && *a == *b) {
        ++a;
        ++b;
    }
    if (*b < *a)
        return 1;
    if (*b > *a)
        return -1;
    return 0;
}

inline int compare(char const* const a, char const* const b)
{
    /* Return -1 less than, 0 equal, 1 greater than */
    if (!a[0] && b[0])
        return -1;
    else if (a[0] && !b[0])
        return 1;
    register int i = 0;
    for (; a[i] && b[i]; i++) {
        if (a[i] < b[i])
            return -1;
        if (a[i] > b[i])
            return 1;
    }
#if 1 /* this addition makes this code work like std::strcmp */
    if (!a[i] && b[i])
        return -1;
    else if (a[i] && !b[i])
        return 1;
#endif
    return 0;
}

#ifdef TEST
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

int main(){
    char *s1 [] = { "", "a", "one", "two", "three", "one", "final" };
    char *s2 [] = { "x", "b", "uno", "deux", "three", "oneone", "" };

    for (int i = 0; i < 7; i++) {
        printf("%d\t", cmp_str(s1[i], s2[i]));
        printf("%d\t", compare(s1[i], s2[i]));
        printf("%d\n", strcmp(s1[i], s2[i]));
    }

    // Test a long string:
    static const int size = 5 * 1024 * 1024;

    static char s3[size];
    for (int i = 0; i < size - 1; i++)
        s3[i] = (rand() % 254) + 1;
    s3[size - 1] = '\0';

    static char s4[size];
    strcpy(s4, s3);
    s3[size - 5] = (s3[size - 5] + 4) % 255;
    clock_t start = clock();
    int val1 = cmp_str(s3, s4);
    clock_t t1 = clock() - start;

    start = clock();
    int val2 = compare(s3, s4);
    clock_t t2 = clock() - start;

    start = clock();
    int val3 = strcmp(s3, s4);
    clock_t t3 = clock() - start;

    double v1 = (double) t1 / CLOCKS_PER_SEC;
    double v2 = (double) t2 / CLOCKS_PER_SEC;
    double v3 = (double) t3 / CLOCKS_PER_SEC;

    printf("Jerry: %d, %f\nAndreas: %d, %f\nstdlib: %d, %f\n", val1, v1, val2, v2, val3, v3);
}

#endif

结果:

-1      -1      -1
-1      -1      -1
-1      -1      -1
1       1       1
0       0       0
-1      -1      -1
1       1       1
Jerry: 1, 0.007000
Andreas: 1, 0.010000
stdlib: 1, 0.007000

由于 Andreas 已经更正了他的代码,所有三个测试都产生了相同的结果,但是这个版本和标准库比 Andreas 的版本快了大约 30%。不过,这确实与编译器有所不同。使用VC++,我的代码几乎和标准库中的代码匹配(但如果我使用一个巨大的字符串,比如200兆字节,标准库中的版本明显更好。使用g++,标准库中的代码似乎有点比 VC++ 标准库中的代码慢,它为 Andreas 的代码或我的代码生成的结果比 VC++ 为它们生成的结果要差很多。在 200 兆字节的字符串上,我使用 VC++ 得到以下结果:

Jerry: 1, 0.288000
Andreas: 1, 0.463000
stdlib: 1, 0.256000

...但是使用 g++ (MinGW),我得到如下结果:

Jerry: 1, 0.419000
Andreas: 1, 0.523000
stdlib: 1, 0.268000

尽管排名保持不变,但标准库和我的代码之间的速度差异使用 g++ 比使用 VC++ 大得多。

于 2013-10-17T07:43:24.800 回答
0

关于您的代码,我不得不说两件事:

  1. i++需要进入循环,但你应该使用++i,取决于编译器i++可能会更慢++i
  2. while (a[i])代替就足够了while (a[i] != NULL && b[i] != NULL),因为ab长度相等。
于 2013-10-17T07:18:15.727 回答
0

只是因为你回来得太早了。在函数中执行 return 后,控件将返回到调用它的位置。

在这种情况下,您将在 while 循环中返回,这是一个逻辑错误。让我们来看看这里的情况。首先它将比较 a[0] 和 b[0],它会根据您的代码在所有三种情况下返回.. 即a[0]b[0] return 1 and else return 0... 你必须改变整个函数。我会根据需要编辑你的函数请稍候

int strComp(char a[], char b[]) {
    int i = 0;

    if (strLen(a) == strLen(b)) {
        while (a[i] != NULL && b[i] != NULL) {
            if (a[i] == b[i]) {
                return 0;
            } else if(a[i] > b[i]) {
                return 1;
            } else {
                return -1;
            }
        }
        i++;
    } else if (strLen(a) > strLen(b)) {
        return 1;
    } else {
        return -1;
    }
}

编辑代码(PS:请检查我没试过):

  int strComp(char a[], char b[])
    {
        int i = 0;


            while (a[i]!='\0'&&b[i]!='\0')  
            {

             if(a[i] > b[i])
                {
                    return 1;
                }
                else if (a[i] < b[i])
                {
                    return -1;
                }
                i++;   //place i++ here
            }

       if(a[i]==b[i])
          return 0;  //if string are equal
      if(a[i]=='\0')
          return -1;
      else 
         return 1;
    }
于 2013-10-17T07:38:04.527 回答