【问题标题】:strcmp() and strcat() sequencestrcmp() 和 strcat() 序列
【发布时间】:2013-07-27 21:39:46
【问题描述】:

在使用 C 指针文献来磨练我的 C 技能的过程中,我遇到了这段代码。在这个问题中,我应该证明输出的合理性。我熟悉strcat()strcmp() 的工作。我知道strcmp() 在两个字符串传递时返回 0,它们是相同的。

# include <stdio.h>
# include <string.h>
int main()
{
    static char str1[]="Good";
    static char str2[20];
    static char str3[20] ="Day";

    int l;      

    l = strcmp(strcat(str3, strcpy(str2, str1)), strcat(str3, "good"));

    printf("%d\n", l);
    return 0;
}

提供的答案是 0,这意味着两个计算的字符串必须相同。我试图通过多个步骤解决该语句。

首先,尝试strcat(str3, strcpy(str2, str1))。 'str2' 更改为 "Good",然后 strcat()str3 更改为 `DayGood'。 到目前为止,我的 gcc 编译器与我一致。

来到strcat(str3, "good"),由于str3 已经更改为DayGoodstrcatstr3 更改为DayGoodgood

再次,gcc 与我发生冲突。

int main()
{
    static char str1[]="Good";
    static char str2[20];
    static char str3[20] ="Day";

    int l;
    printf("%s\n", strcat(str3, strcpy(str2, str1)));
    printf("%s\n", strcat(str3, "good"));       

    //l = strcmp(strcat(str3, strcpy(str2, str1)), strcat(str3, "good"));

    //printf("%d\n", l);
    return 0;
}

它产生

DayGood

DayGoodgood

我再次尝试了这种变化。

int main()
{
    static char str1[]="Good";
    static char str2[20];
    static char str3[20] ="Day";

    int l;

    printf("%s\n", strcat(str3, "good"));
    printf("%s\n", strcat(str3, strcpy(str2, str1)));

    //l = strcmp(strcat(str3, strcpy(str2, str1)), strcat(str3, "good"));

    //printf("%d\n", l);
    return 0;
}

它产生。

Daygood
DaygoodGood

在我的两个测试用例中,我得到了两个不同的字符串进行比较。那么为什么 strcmp() 会产生 0 呢?

【问题讨论】:

  • 到处都是各种未定义和未指定的行为,甚至不要试图推理他们......
  • 我不确定有什么未定义的。 str3 的最终内容可能取决于未指定的评估顺序,但未知顺序的函数调用并不像 x=x++ 那样糟糕,而且我认为任何可能的顺序都不会溢出缓冲区。重要的事实是str3 最终等于它自己。
  • @WumpusQ.Wumbley str3 的内容在序列点之间被多次修改。
  • @H2CO3 我相信内部strcat 的完成提供了一个序列点,它的副作用在外部调用之前提交。
  • 至少我们可以非常确定,编写此代码的人打算将其作为一个技巧问题......“发现无序的函数调用”或“注意到字符串等于自身”。它肯定不会教如何正确使用字符串函数

标签: c string pointers


【解决方案1】:

有一种快速的方法可以在不跟踪所有调用的情况下获得答案:strcat 的两个参数都从strcpys 返回,第一个参数为str3,并且由于strcpy 返回它的第一个参数,即表示最终调用是strcmp(str3, str3),无论对其进行了哪些奇怪的操作,它当然都是 0。

针对更新后的问题,试试这个,看看你是否得到启发:

#include <stdio.h>
#include <string.h>
int main(void)
{
    static char str1[]="Good";
    static char str2[20];
    static char str3[20] ="Day";
    char *first, *second;

    printf("str3 = %p => %s\n", (void *)str3, str3);

    first = strcat(str3, strcpy(str2, str1));
    printf("first strcat returned %p => %s\n", (void *)first, first);
    printf("and now str3 = %p => %s\n", (void *)str3, str3);

    second = strcat(str3, "good");
    printf("second strcat returned %p => %s\n", (void *)second, second);
    printf("and now first = %p => %s\n", (void *)first, first);
    printf("and now str3 = %p => %s\n", (void *)str3, str3);

    printf("Is it any surprise that strcmp(first,second) = %d?\n",
        strcmp(first,second));
    return 0;
}

【讨论】:

  • 那么,最后我们只比较 str3, str3 吗?最后,我的意思是,在对 str3 进行所有修改之后,str3 指向内存中的相同位置。我只是想问最后的调用是 strcmp(str3, str3),而不是 strcmp("DayGood", "DayGoodgood"); ?
  • str3 不是指针,因此它不会指向任何地方。这是一个数组。和 C 中的任何对象一样,数组的地址在其生命周期内是一个常量。
【解决方案2】:

无论编译器选择哪种顺序来计算strcmp 的参数,strcat 总是返回它的第一个参数。

因此本质上是这样的:

... // execute strcat(str3, strcpy(str2, str1)) and strcat(str3, "good")
l = strcmp(str3, str3);

【讨论】:

    【解决方案3】:

    返回 0 因为两个参数:

    strcat(str3, strcpy(str2, str1))
    

    strcat(str3, "good")
    

    实际上返回相同的东西:分配给str3的内存地址。因此,strcmp 返回 0,因为它正在将变量 str3 与自身进行比较。

    【讨论】:

      【解决方案4】:

      strcat 始终返回传递给它的第一个参数这一事实使您的表达式始终为真。这是解释:

      strcmp(strcat(str3, strcpy(str2, str1)), strcat(str3, "good"));
      //            ^^^^                              ^^^^
      
      // become
      
      strcmp( str3, str3 );
      

      所以strcmp 通过将变量与自身进行比较来返回0

      你应该知道这种表达方式不是很好,因为它使代码更难理解,并且可能导致未定义的行为比你想象的更快......

      【讨论】:

        【解决方案5】:

        strcmp 获取两个指向字符串的指针作为其参数:

         l = strcmp(strcat(str3, strcpy(str2, str1)), strcat(str3, "good"));
        

        第一步:

        l = strcmp(str3, strcat(str3, "good"));
        

        这里 str3 指向字符串 DayGoodgoodGood。

        第二步:

         l = strcmp(str3,str3 );
        

        现在 str3 指向字符串 DayGoodgoodGoodgood。

        无论 str3 指向什么,这将返回 0。由于地址相同 strcmp 甚至不应该进行优化比较;只返回 0。

        【讨论】:

          【解决方案6】:

          strcat返回它的第一个参数,这就是为什么!

          【讨论】:

          • 不,strcat 返回它的第一个参数,而不是指向它的指针。 strcat 的第一个参数是一个指针,strcat 返回它。
          • 是的,对不起。我是这个意思。
          猜你喜欢
          • 2014-02-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-21
          • 2017-07-06
          • 2016-02-10
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多