Albatossable
Albatossable

Reputation: 83

Extra zero char at end of string appears in C++ for range loop

The following code

#include <iostream>
#include <string>
int main()
{
    std::string s = "abc";
    for (char c : s)
        std::cout << (int) c << " ";
}

prints "97 98 99 ".

The following code

#include <iostream>
int main()
{
    for (char c : "abc")
        std::cout << (int) c << " ";
}

prints "97 98 99 0 ".

Where is the extra 0 coming from in the second code?

Upvotes: 8

Views: 817

Answers (3)

Martin Konrad
Martin Konrad

Reputation: 1095

C++ has two types of strings with different properties:

C Strings and String Literals

They are fixed-size null-terminated character arrays (max. size determined at compile time). "abc" is called a string literal which you can think of as a character array containing { 'a', 'b', 'c', '\0' }. Your range-based for loop is iterating over all characters in the array including the null terminator. The C way of printing the data without the null termination would be:

char ca[] = "abc";

char *c = ca;
while (*c)
    std::cout << (int) *(c++) << " ";

Note that this old-fashioned way of fiddling with raw pointers is not recommended - it's just too easy to shoot yourself in the foot.

C++ Strings and C++ String Literals

std::string provides a string implementation that can handle arbitrary length strings (memory allocated dynamically at run time). C++ strings are objects that have their own way of handling length which doesn't require null termination. The std::string class provides iterators that enable us to write loops like

std::string s = "abc";

// Traditional loop with iterators:
for (auto i = s.begin(); i != s.end(); i++)
    std::cout << (int) *i << " ";

// Range-based for loop:
for (char c : s)
    std::cout << (int) c << " ";

The C string "abc" is passed to std::string's constructor which stores it in its internal format.

Note that C++14 also supports C++ string literals: "abc"s (note the operator s at the end). In your example you can use them like so:

using namespace std::string_literals;

for (char c : "abc"s)
    std::cout << (int) c << " ";
}

Upvotes: 2

Ron
Ron

Reputation: 15541

In the first snippet you are iterating over a string using a range based loop. The std::string type has .begin() and .end() iterators. The range based loop uses those to mark the beginning and the end of the range.

In the second snippet, you are using a range based loop to iterate over a string literal. A string literal is basically an array of characters that has an extra hidden \0 character at the end. This character is convertible to integer value of 0. Hence the extra 0 in the output.

Upvotes: 4

Bathsheba
Bathsheba

Reputation: 234875

The literal "abc" is a const char[4] type: the final element is the NUL terminator (with value 0).

In the second snippet, the value of the NUL terminator is printed as the code is describing an iteration over that entire const char[4] array.

In the first snippet, the underlying iterator technology of the std::string class sets the end iterator (which is not reached in the short form for loop) to the NUL terminator. This behaviour is consistent with s.size().

Upvotes: 11

Related Questions