1

Learning C++. I just want to grab the first character in a string, then make a new string based on such character, and then print it out:

#include <iostream>
using namespace std;

int main(int argc, const char * argv[]) {
    string name = "Jerry";
    char firstCharacter = name.at(0);
    string stringOfFirstCharacter = string(&firstCharacter);
    cout << stringOfFirstCharacter;
    return 0;
}

The output is:

J
Jerry

I don't really know why is it also printing Jerry. Why is that?

Saturn
  • 17,888
  • 49
  • 145
  • 271
  • Completely unrelated, just looking for information, and not intended as a judgment: did you type `using namespace std;` in the code, or did some tool insert it? – Pete Becker Apr 17 '13 at 20:22
  • @PeteBecker: I saw it in some example code a while back, and since then I begun doing it by my own. I used to put it inside each block, but this way seemed more convenient to me. No tool did it. Why, is it a weird practice? – Saturn Apr 17 '13 at 20:23
  • It's not particularly good (`std::string` is generally better), but I've seen so many code examples that put the same using declaration directly after the `#include`s that I suspect some tool is doing it. Thanks for the information. – Pete Becker Apr 17 '13 at 20:25
  • @PeteBecker It's commonly found in beginner C++ books, which often inadequately explain that they've done it to make their code samples simpler, and not because it is good practice. – JBentley Apr 17 '13 at 20:26
  • @JBentley - too bad. But I'm struck by the consistency of seeing it **immediately** after the `#include`s: no blank line, as if it's just automatically part of the `#include` directives. – Pete Becker Apr 17 '13 at 20:30
  • @PeteBecker: Hey, actually, I found a tool that does insert that line after the imports! Code::Blocks, when creating a new console application with C++, gives you the following program: http://pastebin.com/DdgxuBa9 – Saturn Apr 19 '13 at 21:13
  • @Omega - thanks. I do see lots of people using Code::Blocks here. It's a bad habit to get into. – Pete Becker Apr 19 '13 at 21:17

4 Answers4

8

Your code has undefined behavior. The signature of the constructor that takes a pointer to char requires that it is a pointer to a null terminated string, which it is not in your case since it is a single character.

My guess is that the implementation you have uses the small object optimization, and that "Jerry" is small enough that it is stored inside the std::string object rather than dynamically allocated. The layout of the two objects in the stack happens to be first firstCharacter, then name. When you call std::string(&firstCharacter) it reads until it hits the first null character (inside the std::string buffer) and stops there.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
3

You are constructing an std::string object from a char* (because you are taking the address of firstCharacter). A pointer to a character is not interpreted as a character itself by the constructor of std::string, but rather as a null-terminated string.

In this case, your program has Undefined Behavior, because the address of firstCharacter is not the address of the first character of a null-terminated string.

What you should be doing is:

string stringOfFirstCharacter(1, firstCharacter);
cout << stringOfFirstCharacter;

If you really want to create a one-character string. However, notice that in order to print the character to the standard output, you could have simply written:

cout << firstCharacter;

Or even:

cout << name.at(0);
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • +1. I'd prefer "null-terminated" (lower case) or "`\0`-terminated", though. `NULL` makes me think of the null pointer constant. – Carl Norum Apr 17 '13 at 20:19
2

With string(&firstCharacter), you are using the std::string constructor of the form

std::string( const char* s, const Allocator& alloc = Allocator() );

That form expects a pointer to a null-terminated array of characters. It is incorrect to pass a pointer to character(s) that are not null-terminated.

With your intention of initializing the string with 1 char, you should use the form:

string( 1, firstCharacter )
Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
1

The string constructor you're using (the one that takes a char * argument), is intended to convert a C-style string into a C++ string object - not a single character. By passing it a single character you cause undefined behaviour.

In your specific case, there appears to not be a zero byte in memory after firstCharacter, so the constructor runs through and includes all of name along with it!

Carl Norum
  • 219,201
  • 40
  • 422
  • 469