C++ Comparison of String Literals

C++String Literals

C++ Problem Overview


I'm a c++ newbie (just oldschool c). My son asked for help with this and I'm unable to explain it. If he had asked me "how do I compare strings" I would have told him to use strcmp(), but that isn't what is confusing me. Here is what he asked:

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

will print 1

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

will also print 1, but

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

will then print 10. Individually both cout statements print 1, but executed in a row I get a different answer?

C++ Solutions


Solution 1 - C++

You are comparing memory addresses. Apparently your compiler places the string literals in memory in the order it encounters them, so the first is "lesser" than the second.

Since in the first snippet it sees "A" first and "Z" second, "A" is lesser. Since it sees "Z" first in the second, "Z" is lesser. In the last snippet, it already has literals "A" and "Z" placed when the second command rolls around.

Solution 2 - C++

String literals have static storage duration. In all these comparisons there are compared addresses of memory allocated by the compiler for string literals. It seems that the first string literal that is encountered by the compiler is stored in memory with a lower address compared with the next encountered string literal.

Thus in this program

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

string literal "Z" was alllocated with a lower address than string literal "A" because it was found first by the compiler.

Take into account that comparison

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

can give different results depending on the options of the compiler because the compiler may either allocate two extents of memory for the string literals or use only one copy of the string literals that are the same.

From the C++ Standard (2.14.5 String literals)

> 12 Whether all string literals are distinct (that is, are stored in > nonoverlapping objects) is implementation defined. The effect of > attempting to modify a string literal is undefined.

The same is valid for C.

Solution 3 - C++

In the statement:

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

You have created 2 string literals: "A" and "Z". These are of type const char * which is a pointer to a null terminated array of characters. The comparison here is comparing the pointers and not the values that they point to. It's this comparing of memory addresses here which is what gives you the compiler warning. The result of the comparison is going to be determined by where the compiler allocated the memory to which is going to be somewhat arbitrary from compiler to compiler. In this case it looks like the first literal found is getting assigned the first memory address by your compiler.

Just like in C to compare these string literals properly you need to use strcmp which will do a value comparison.

However when you do something the more idiomatic c++ way by doing:

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

Then you get the proper comparison of the values as that comparison operator is defined for std::string.

Solution 4 - C++

If you want to compare actual C++ strings, you need to declare C++ strings:

int main() 
{
  const std::string a("A");
  const std::string z("Z");

  cout << (z < a) << endl; // false
  cout << (a < z) << endl; // true
}

Solution 5 - C++

In C++, the results are unspecified. I will be using N3337 for C++11.

First, we have to look at what the type of a string literal is.

§2.14.5

> 9 Ordinary string literals and UTF-8 string literals are also > referred to as narrow string literals. A narrow string literal has > type "array of n const char", where n is the size of the string > as defined below, and has static storage duration (3.7).

Arrays are colloquially said to decay to pointers.

§4.2

> 1 An lvalue or rvalue of type "array of N T" or "array of unknown > bound of T" can be converted to a prvalue of type "pointer to T". > The result is a pointer to the first element of the array.

Since your string literals both contain one character, they're the same type (char[2], including the null character.)

Therefore the following paragraph applies:

§5.9

> 2 [...] > > Pointers to objects or functions of the same type (after pointer > conversions) can be compared, with a result defined as follows: > > > [...] > > > > — If two pointers p and q of the same type point to different > > objects that are not members of the same object or elements of the > > same array or to different functions, or if only one of them is null, > > the results of p<q, p>q, p<=q, and p>=q are unspecified.

Unspecified means that the behavior depends on the implementation. We can see that GCC gives a warning about this:

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

The behavior may change across compilers or compiler settings but in practice for what happens, see Wintermute's answer.

Solution 6 - C++

You are comparing memory addresses. The example that follow explains how to compare 2 strings:

#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;
}

Solution 7 - C++

The string constants ("A" and "Z") in C++ are represented by the C concept - array of characters where the last character is '\0'. Such constants have to be compared with strcmp() type of function.

If you would like to use the C++ std::string comparison you have to explicitly state it:

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

Solution 8 - C++

A String is representing a pointer to memory area. So you at first compare only memory addresses with such code

"Z"< "A"

comparing strings is done with functions. They depend on "what kind of string" you have. You have char array strings, but they mid also be objects. These objects have other comparision functions. For instance the CString in MFC has the Compare but also the CompareNoCase function.

For your strings you best use the strcmp. If you debug and step in you see what the function does: it compares every char of both strings and return an integer if the first difference occurs or zero if the same.

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

Here you find some further sample code

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsimusidView Question on Stackoverflow
Solution 1 - C++WintermuteView Answer on Stackoverflow
Solution 2 - C++Vlad from MoscowView Answer on Stackoverflow
Solution 3 - C++shuttle87View Answer on Stackoverflow
Solution 4 - C++tadmanView Answer on Stackoverflow
Solution 5 - C++user3920237View Answer on Stackoverflow
Solution 6 - C++Thomas PapamihosView Answer on Stackoverflow
Solution 7 - C++user2038893View Answer on Stackoverflow
Solution 8 - C++KarstenView Answer on Stackoverflow