使用指针比较 C 语言中的字符串

Compare strings in C using pointers

提问人:ChenBr 提问时间:9/19/2023 最后编辑:ChenBr 更新时间:9/20/2023 访问量:181

问:

我正在学习 C 课程,我很难弄清楚以下练习。

给定 2 个字符指针,该函数应按字典顺序比较指针指向的字符串(区分大小写)。如果发现第一个字符串分别小于、等于或大于第二个字符串,则应返回负数、0(零)或正整数值。

例如:(第一个)字符串“Fan”小于(第二个)字符串“Fun”,因此在这种情况下,函数应返回负整数值。

请注意:大写字母不同于小写字母('A' != 'a')。


我尝试创建每个字符串的总和,然后比较它们以查看哪个更大。 这是我写的函数:

int StringCompare(const char *str1, const char *str2)
{
    int str1_sum = 0;
    int str2_sum = 0;

    while (*str1 != '\0')
    {
        str1_sum += *str1++;
        str1++;
    }

    while (*str2 != '\0')
    {
        str2_sum += *str2++;
        str2++;
    }

    if (str1_sum > str2_sum)
    {
        return 1;
    }
    else if (str1_sum < str2_sum)
    {
        return -1;
    }
    else
    {
        return 0;
    }
}

不幸的是,它不起作用,我收到以下错误:

Running test: StringCompare("oeis03HWoLn\I7]JJ=7yCWei4H\SN7S", "BlA;Vx<2lYY6r`Mu0Z1bnXL\EMqRkau") -- Failed


当我尝试调试它时,它进展顺利,我不确定我是否遗漏了代码中的某些内容,或者我只是没有正确理解练习。

帮助将不胜感激!


更新: 我更新了我的代码:

int StringCompare(const char *str1, const char *str2)
{
    
    while(*str1 != '\0' && *str2 != '\0'){
        if(*str1 > *str2) {
            return 1;
        } else if(*str1 < *str2) {
            return -1;
        }
        str1++;
        str2++;
    }
    
    if(*str1 == '\0' && *str2 == '\0'){
        return 0;
    } else if(*str1 == '\0'){
        return -1;
    } else {
        return 1;
    }
}

不幸的是,现在我收到以下错误消息:

Running test: StringCompare("(null)", "Hello !!!???")  --  Failed: Invalid memory reference

我还尝试运行下面建议的 Surge 代码,但我也收到了相同的错误。

有谁知道可能是什么原因?


更新2: 添加了以下验证:

assert(str1 != NULL && str2 != NULL);

它现在可以工作了:

#include <assert.h>
#include <stddef.h>

int StringCompare(const char *str1, const char *str2)
{
    assert(str1 != NULL && str2 != NULL);
    while(*str1 != '\0' && *str2 != '\0'){
        
        
        if(*str1 > *str2) {
            return 1;
        } else if(*str1 < *str2) {
            return -1;
        }
        str1++;
        str2++;
    }
    
    if(*str1 == '\0' && *str2 == '\0'){
        return 0;
    } else if(*str1 == '\0'){
        return -1;
    } else {
        return 1;
    }
}
C 字符串 指针

评论

3赞 Some programmer dude 9/19/2023
您需要单独比较字符串的每个字符。我可以提出编码值总和相等的字符串,即使字符串本身不相等。例如,和 .假设 ASCII 是 ,也是 。"AD""BC"65 + 6813366 + 67133
2赞 wohlstad 9/19/2023
有关词典顺序,请参阅此处。它与字符的“总和”无关
2赞 STerliakov 9/19/2023
你对练习的解释是错误的。词典比较不检查元素的“总价值”。相反,它会逐个比较配对的元素,并在第一次不匹配时尽早返回。如果两个字符串的长度不同,并且公共前缀与最短的字符串一样长,则较长的字符串优先(因为任何字符都大于 )。字符串相等,因为它们具有相同的长度,并且相同索引中的所有字符都相等。\0
2赞 Lundin 9/19/2023
你这样做的方式是行不通的。关于如何实现自己的解决方案之前已经在 SO 上发布了 100 次,看看周围一下。strcmp
2赞 Andrew Henle 9/19/2023
但请注意,问题陈述的“区分大小写”部分“函数应按字典顺序比较指针指向的字符串(区分大小写)”令人困惑。这里的“区分大小写”是什么意思?是否所有大写字母都应被视为在小写字母之前或之后?与大写或小写字母相比,非字母属于什么位置?

答:

2赞 Surge 9/19/2023 #1

关于对词典排序的理解,您收到的评论是正确的。为了完整起见,以下是我经过一些测试的解决方案:

#include<stdio.h>
#include<stdlib.h>

int StringCompare(const char *str1, const char *str2)
{

    while (*str1 == *str2)
    {
        if (*str1 == 0) return 0;
        str1++;
        str2++;
    }
    return   (*(unsigned char *)str2 < *(unsigned char *)str1) 
           - (*(unsigned char *)str1 < *(unsigned char *)str2);
}

int main(void) {
    printf("\"AD\":\"BC\" -> %d\n", StringCompare("AD", "BC"));
    printf("\"Ab\":\"aa\" -> %d\n", StringCompare("Ab", "aa"));
    printf("\"xxx\":\"aa\" -> %d\n", StringCompare("xxx", "aa"));
    printf("\"\":\"aa\" -> %d\n", StringCompare("", "aa"));
    printf("\"a\":\"a\xd0\" -> %d\n", StringCompare("a", "a\xd0"));
    printf("\"\xee\":\"\xef\" -> %d\n", StringCompare("\xee", "\xef"));
    printf("\"\xd0\":\"\" -> %d\n", StringCompare("\xd0", ""));

    return EXIT_SUCCESS;
}

希望它有所帮助。(空字符串是排序中最低的字符串。

更新:一条评论指出,您可能还需要检查无效的输入,例如 .遗憾的是,没有自然的方法可以对无效输入与有效输入进行排序。这就是为什么正确的方法是在将输入传递给该比较器之前检查输入的有效性。另一种方法是返回一个处理非结果的复杂类型(比如 )。NULLstruct{int order_int; int error_flag;}

Update2:感谢 @chux - 恢复 Monica,这是另一个边缘案例修复。由于可以有符号或无符号,因此根据实现的不同,与 0 的比较会受到影响。如果使用扩展的 ASCII 字符,则会将字符串放在较短的字符串之前(以 0 结尾)。还需要使空字符串相对于所有有效字符串正确排序。char""

评论

1赞 Surge 9/19/2023
@ChenBr对我来说,它工作正常。我不确定你实际运行了什么代码。如果你澄清,我可以帮忙。
1赞 Surge 9/19/2023
只要确保你使用的是输入。我明白了,我想知道你是否在做正确的函数调用...... :DOfc,该算法可以很容易地添加到其他类型中。char *"(null)"
1赞 Surge 9/19/2023
它们可能将字符串作为输入传递。尝试使用和递增 rathen 访问元素,而不是访问和递增指针。[i]i
1赞 Surge 9/19/2023
您发布的更新代码在独立编译时按预期工作。这意味着您的环境没有按预期提供输入,或者您误解了说明。
1赞 wohlstad 9/19/2023
从测试错误消息()中猜测,您需要检查是否有任何指针在函数的开头。StringCompare("(null)", ...NULL
3赞 chux - Reinstate Monica 9/20/2023 #2

仅适用于迂腐的人:

@Surge可以很好地处理许多字符串。然而,由于 may 是有符号的,因此以负数开头的字符串小于 。charchar""

相反,它执行该操作,它会比较字符串,就好像它们是值一样,即使它们是有符号的。strcmp()unsigned charchar

对于本子句中的所有函数,每个字符都应解释为具有类型(因此每个可能的对象表示都是有效的并且具有不同的值) C23dr § 7.26.1 4unsigned char

int StringCompareAlt(const char *str1, const char *str2) {
  const unsigned char *ustr1 = (const unsigned char *) str1;
  const unsigned char *ustr2 = (const unsigned char *) str2;
  while (*ustr1 == *ustr2 && *ustr1 != 0) {
    ustr1++;
    ustr2++;
  }

  return (*ustr1 > *ustr2) - (*ustr1 < *ustr2);
}

OP 表示未发布的调用代码存在问题。StringCompare("(null)", "Hello !!!???")

评论

0赞 Surge 9/20/2023
谢谢!你说得很对,我以前被字符的符号绊倒过。我会更新我的答案。