比较两个 C 风格字符串的 C++ For 循环的效率和可读性

Efficiency & Readabilty of a C++ For Loop that Compares two C-style Strings

所以我创建了自己的函数来比较两个 C 字符串:

bool list::compareString(const char array1[], const char array2[])
{
    unsigned char count;
    for (count = 0; array1[count] != '[=10=]' && array2[count] != '[=10=]' && (array1[count] == array2[count] || array1[count + 32] == array2[count] || array1[count] == array2[count+32]); count++);
    if (array1[count] == '[=10=]' && array2[count] == '[=10=]')
        return true;
    else
        return false;
}

我的 for 循环的参数很长,因为它将计数带到至少一个字符串的末尾,并比较每个数组中的每个 char,以便它们的大小写不会'无关紧要(将 32 添加到大写字母 char 会将 char 变成对应的小写字母)。

现在,我猜这是比较两个 C 字符串的最有效方法,但是 for 循环由于其长度而难以阅读。有人告诉我的是尽可能使用 for 循环而不是 while 循环,因为 for 循环在其起始参数中具有开始、结束和递增条件,但为此,这似乎不适用。

我想问的是,我应该如何格式化这个循环,有没有更有效的方法来做到这一点?

array1[count + 32] == array2[count] 如果数组的长度小于 32,则可能导致 OutOfRangeException。 您可以使用 strcmp 比较两个字符串

您可以直接对指针进行操作,而不是用 count 索引到您不知道其大小的数组中:

bool list::compareString(const char* array1, const char* array2)
{
    while (*array1 != '[=10=]' || *array2 != '[=10=]')
        if (*array1++ != *array2++) return false; // not the same character

    return true;
}

对于不区分大小写的比较,将 if 条件替换为:

        if (tolower(*array1++) != tolower(*array2++)) return false;

这会将字符安全地转换为小写。

while 循环检查字符串是否终止。它会在其中一个字符串尚未终止时继续。如果只有 1 个字符串终止,则下一行 - if 语句将意识到字符不匹配(因为只有 1 个字符是 '[=14=]',而 returns false.

如果字符串在任何一点不同,则 if 语句 returns false。

if 语句还 post 递增指针,以便它在 while 循环的下一次迭代中测试下一个字符。

如果两个字符串相等,并且同时终止,那么在某个时候,while 条件会变为假。在这种情况下,将执行 return true 语句。


如果您想自己编写tolower函数,您需要检查字符是否为大写字母,而不是其他类型的字符(例如,数字符号)。

这将是:

inline char tolower(char ch)
{
    return (ch >= 'A' && ch <= 'Z' ? (ch + 'a' - 'A') : ch);
}

您的代码有一些问题。

我在这里要做的是将您的一些逻辑移动到 for 循环的主体中。将所有内容都塞进 for 循环表达式会大大降低可读性,而不会给我带来我能想到的任何性能提升。代码最终变得混乱。将循环的条件保留为测试增量并将实际任务放在主体中。

我还要指出,您根本没有向该字符添加 32。您将它添加到数组的索引中,使您面临 运行 越界的风险。您需要测试索引处的值,而不是索引本身。

使用 unsigned char 索引数组没有任何好处,只会减少可以比较的字符串的最大长度。使用一个整数。

您可以重组代码,使其看起来像这样:

bool list::compareString(const char array1[], const char array2[])
{
    // Iterate over the strings until we find the string termination character
    for (int count = 0; array1[count] != '[=10=]' && array2[count] != '[=10=]'; count++) {

      // Note 0x20 is hexadecimal 32. We're comparing two letters for
      // equality in a case insensitive way.
      if ( (array1[count] | 0x20) != (array2[count] | 0x20) ) {
          // Return false if the letters aren't equal
          return false;
      }
    }
    // We made it to the end of the loop. Strings are equal.
    return true;
}

至于效率,在我看来你正在尝试减少:

  1. 您用来存储数据的变量的大小 内存
  2. 您的解决方案中单独的代码行数

这些都不值得你花时间。效率是关于执行一项任务需要多少步骤(不是代码行,请注意),以及这些步骤如何随着输入变大而扩展。比如比较两部小说的内容是否相等,比比较两个单字串要慢多少?

希望对您有所帮助:)

我猜你想在这里进行不区分大小写的比较。如果您只需要最快的版本,请使用库函数:strcasecmpstricmpstrcmpi(名称取决于您的平台)。

如果您需要了解如何操作(我的意思是,您的问题是出于学习目的吗?),请从 可读 版本开始,如下所示:

for (index = 0; ; ++index)
{
    if (array1[index] == '[=10=]' && array2[index] == '[=10=]')
        return true; // end of string reached

    if (tolower(array1[index]) != tolower(array2[index]))
        return false; // different characters discovered
}

然后测量它的性能。如果足够好,完成。如果不是,调查原因(通过查看编译器生成的机器代码)。优化的第一步 可能 是用一段手工编写的代码替换 tolower 库函数(忽略非英文字符 - 这是你想做的吗? ):

int tolower(int c)
{
    if (c >= 'A' && c <= 'Z')
        return c + 'a' - 'A';
}

请注意,我仍然保持代码的可读性。可读代码可以很快,因为编译器会对其进行优化。