【问题标题】:C++ Comparison of String Literals字符串文字的 C++ 比较
【发布时间】:2015-02-11 12:58:35
【问题描述】:

我是一个 c++ 新手(只是 oldschool c)。我儿子为此寻求帮助,我无法解释。如果他问我“我如何比较字符串”,我会告诉他使用 strcmp(),但这并不是让我感到困惑的地方。这是他的要求:

int main() 
{ 
  cout << ("A"< "Z");
}

将打印 1

int main() 
{ 
  cout << ("Z"< "A");
}

也会打印 1,但是

int main() 
{ 
  cout << ("Z"< "A");
  cout << ("A"< "Z");
}

然后将打印 10。两个 cout 语句单独打印 1,但连续执行我得到不同的答案?

【问题讨论】:

  • 不是你的问题,但你可以通过将任一文字转换为 std::string: std::cout &lt;&lt; (std::string("A") &lt; "Z");
  • 仅供参考 cstrings 可以转换为 c++ 字符串,然后与典型的运算符进行比较。 std::string s1 = "A";
  • 或者从 C++14 开始只是 ("A"s &lt; "Z"s).
  • 寻找面试问题的人,请注意!

标签: c++ string-literals


【解决方案1】:

您正在比较内存地址。显然,您的编译器将字符串文字按照遇到它们的顺序放置在内存中,因此第一个比第二个“小”。

由于在第一个 sn-p 中它首先看到“A”,然后看到“Z”,因此“A”较小。由于它在第二个中首先看到“Z”,因此“Z”较小。在最后一个 sn-p 中,当第二个命令滚动时,它已经放置了文字“A”和“Z”。

【讨论】:

  • 您可能应该提到compare 方法来实际比较它们。
  • 我认为值得注意的是,这与“oldschool c”中发生的情况完全相同。
  • 我很惊讶地发现 C++ 不支持 spaceship operator &lt;=&gt; 进行比较。
  • @Wintermute 我编辑指出它们本身不是字符串,而是char 数组,因为来自其他语言的人经常忘记这一点。
  • @Roland 不,至少在 C++11 中未指定。 § 5.9/2 “如果相同类型的两个指针 p 和 q 指向不同的对象,这些对象不是同一对象的成员或同一数组的元素或不同的函数,或者如果其中只有一个为空,则结果pq、p=q 未指定”
【解决方案2】:

字符串字面量具有静态存储持续时间。在所有这些比较中,都会比较编译器为字符串文字分配的内存地址。似乎编译器遇到的第一个字符串文字存储在内存中,与下一个遇到的字符串文字相比,地址较低。

因此在这个程序中

int main() 
{ 
  cout << ("Z"< "A");
  cout << ("A"< "Z");
}

字符串文字“Z”分配的地址比字符串文字“A”低,因为它是由编译器首先找到的。

考虑这种比较

  cout << ("A"< "A");

可以根据编译器的选项给出不同的结果,因为编译器可以为字符串文字分配两个内存范围,或者只使用相同的字符串文字的一个副本。

来自 C++ 标准(2.14.5 字符串文字)

12 所有字符串字面量是否不同(即存储在 不重叠的对象)是实现定义的。的效果 尝试修改字符串文字是未定义的。

同样适用于 C。

【讨论】:

  • 值得注意的是,这些不是 C++ std::string 类型的字符串,而是 char* C 风格的字符串。
【解决方案3】:

在声明中:

cout << ("A"< "Z");

您已创建 2 个string literals"A""Z"。这些是const char * 类型,它是指向以空字符结尾的字符数组的指针。这里的比较是比较指针而不是它们指向的值。正是这里的内存地址比较给了你编译器警告。比较的结果将取决于编译器分配内存的位置,从编译器到编译器,这在某种程度上是任意的。在这种情况下,您的编译器似乎为找到的第一个文字分配了第一个内存地址。

就像在 C 中正确比较这些字符串文字一样,您需要使用 strcmp 来进行值比较。

但是,当您以更惯用的 c++ 方式做某事时:

cout << (std::string("A") < std::string("Z"));

然后您可以正确比较值,因为该比较运算符是为 std::string 定义的。

【讨论】:

    【解决方案4】:

    如果要比较实际的 C++ 字符串,则需要声明 C++ 字符串:

    int main() 
    {
      const std::string a("A");
      const std::string z("Z");
    
      cout << (z < a) << endl; // false
      cout << (a < z) << endl; // true
    }
    

    【讨论】:

      【解决方案5】:

      在 C++ 中,结果未指定。我将在 C++11 中使用 N3337

      首先,我们要看看字符串字面量的类型是什么。

      §2.14.5

      9 普通字符串文字和 UTF-8 字符串文字也是 称为窄字符串文字。窄字符串文字有 键入“数组 n const char”,其中 n 是字符串的大小 如下定义,并且具有静态存储持续时间 (3.7)。

      数组通俗地说是衰减到指针。

      §4.2

      1 类型为“N T 的数组”或“未知数组”的左值或右值 T" 的边界可以转换为类型为 "pointer to T" 的纯右值。 结果是指向数组第一个元素的指针。

      由于您的字符串文字都包含一个字符,因此它们属于同一类型(char[2],包括空字符。)

      因此以下段落适用:

      §5.9

      2 [...]

      指向相同类型的对象或函数的指针(在指针之后 转换)可以进行比较,结果定义如下:

      [...]

      ——如果两个相同类型的指针pq指向不同 不是同一对象或元素的成员的对象 相同的数组或不同的函数,或者如果其中只有一个为空, p&lt;qp&gt;qp&lt;=qp&gt;=q 的结果未指定。

      未指定意味着行为取决于实现。我们可以看到 GCC 对此给出了警告:

      warning: comparison with string literal results in unspecified behaviour [-Waddress]
           std::cout << ("Z" < "A");
      

      行为可能会因编译器或编译器设置而改变,但在实践中会发生什么,请参阅 Wintermute 的 answer

      【讨论】:

        【解决方案6】:

        您正在比较内存地址。以下示例说明了如何比较 2 个字符串:

        #include "stdafx.h"
        #include <iostream>
        #include <cstring> //prototype for strcmp()
        
        int _tmain(int argc, _TCHAR* argv[])
        {
         using namespace std;
        
         cout << strcmp("A", "Z"); // will print -1
         cout << strcmp("Z", "A"); // will print 1
        
         return 0;
        }
        

        【讨论】:

          【解决方案7】:

          C++ 中的字符串常量(“A”和“Z”)由 C 概念表示 - 最后一个字符为 '\0' 的字符数组。此类常量必须与 strcmp() 类型的函数进行比较。

          如果您想使用 C++ std::string 比较,您必须明确说明:

          cout << (std::string( "A") < "Z");
          

          【讨论】:

            【解决方案8】:

            String 表示指向内存区域的指针。因此,您首先只将内存地址与此类代码进行比较

            "Z"< "A"
            

            比较字符串是通过函数完成的。它们取决于您拥有的“什么样的字符串”。您有 char 数组字符串,但它们也是对象。这些对象具有其他比较功能。例如 MFC 中的 CString 有 Compare 也有 CompareNoCase 函数。

            对于您的字符串,您最好使用 strcmp。如果您调试并介入,您会看到该函数的作用:它比较两个字符串的每个字符,如果出现第一个差异则返回一个整数,如果相同则返回零。

            int result = strcmp("Z", "A");
            

            在这里你可以找到更多sample code

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2021-11-19
              • 2016-02-08
              • 2013-11-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多