Reputation: 83
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
Reputation: 1095
C++ has two types of strings with different properties:
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.
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
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
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