Search

4.4b — An introduction to std::string

What is a string?

The very first C++ program you wrote probably looked something like this:

So what is “Hello, world!” exactly? “Hello, world!” is a collection of sequential characters called a string. In C++, we use strings to represent text such as names, addresses, words, and sentences. String literals (such as “Hello, world!”) are placed between double quotes to identify them as a string.

Because strings are commonly used in programs, most modern languages include a built-in string data type. C++ includes one, not as part of the core language, but as part of the standard library.

std::string

To use strings in C++, we first need to #include the <string> header to bring in the declarations for std::string. Once that is done, we can define variables of type std::string.

Just like normal variables, you can initialize or assign values to strings as you would expect:

Note that strings can hold numbers as well:

In string form, numbers are treated as text, not numbers, and thus they can not be manipulated as numbers (e.g. you can’t multiply them). C++ will not automatically convert string numbers to integer or floating point values.

String input and output

Strings can be output as expected using std::cout:

This prints:

My name is: Alex

However, using strings with std::cin may yield some surprises! Consider the following example:

Here’s the results from a sample run of this program:

Enter your full name: John Doe
Enter your age: Your name is John and your age is Doe

Hmmm, that isn’t right! What happened? It turns out that when using operator>> to extract a string from cin, operator>> only returns characters up to the first whitespace it encounters. Any other characters are left inside cin, waiting for the next extraction.

So when we used operator>> to extract a string into variable name, only “John” was extracted, leaving “Doe” inside std::cin, waiting for the next extraction. When we used operator>> again to extract a string into variable age, we got “Doe” instead of “23”. If we had done a third extraction, we would have gotten “23”.

Use std::getline() to input text

To read a full line of input into a string, you’re better off using the std::getline() function instead. std::getline() takes two parameters: the first is std::cin, and the second is your string variable.

Here’s the same program as above using std::getline():

Now our program works as expected:

Enter your full name: John Doe
Enter your age: 23
Your name is John Doe and your age is 23

Mixing std::cin and std::getline()

Reading inputs with both std::cin and std::getline may cause some unexpected behavior. Consider the following:

This program first asks you to enter 1 or 2, and waits for you to do so. All good so far. Then it will ask you to enter your name. However, it won’t actually wait for you to enter your name! Instead, it prints the “Hello” line, and then exits. What happened?

It turns out, when you enter a numeric value using cin, cin not only captures the numeric value, it also captures the newline. So when we enter 2, cin actually gets the string “2\n”. It then extracts the 2 to variable choice, leaving the newline stuck in the input stream. Then, when std::getline goes to read the name, it sees “\n” is already in the stream, and figures we must have entered an empty string! Definitely not what was intended.

A good rule of thumb is that after reading a numeric value with std::cin, remove the newline from the stream. This can be done using the following:

If we insert this line directly after reading variable choice, the extraneous newline will be removed from the stream, and the program will work as expected!

Rule: If reading numeric values with std::cin, it’s a good idea to remove the extraneous newline using std::cin.ignore().

What’s that 32767 magic number in your code?

That tells std::cin.ignore() how many characters to ignore up to. We picked that number because it’s the largest signed value guaranteed to fit in a (2-byte) integer on all platforms.

Technically, the correct way to ignore an unlimited amount of input is as follows:

But this requires remembering (or looking up) that horrendous line of code, as well as remembering what header to include. Most of the time you won’t need to ignore more than a line or two of buffered input, so for practical purposes, 32767 works about as well, and has the benefit of being something you can actually remember in your head.

Throughout these tutorials, we use 32767 for this reason. However, it’s your choice of whether you want to do it the “obscure, complex, and correct” way or the “easy, practical, but not ideal” way.

Appending strings

You can use operator+ to concatenate two strings together, or operator+= to append one string to another.

Here’s an example of both, also showing what happens if you try to use operator+ to add two numeric strings together:

This prints:

4511
45 volts

Note that operator+ concatenated the strings “45” and “11” into “4511”. It did not add them as numbers.

String length

If we want to know how long a string is, we can ask the string for its length. The syntax for doing this is different than you’ve seen before, but is pretty straightforward:

This prints:

Alex has 4 characters

Note that instead of asking for the string length as length(myName), we say myName.length().

The length function isn’t a normal standalone function like we’ve used up to this point -- it’s a special type of function that belongs to std::string called a member function. We’ll cover member functions, including how to write your own, in more detail later.

Conclusion

std::string is complex, leveraging many language features that we haven’t covered yet. It also has a lot of other capabilities that we haven’t touched on here. Fortunately, you don’t need to understand these complexities to use std::string for simple tasks, like basic string input and output. We encourage you to start experimenting with strings now, and we’ll cover additional string capabilities later.

Quiz

1) Write a program that asks the user to enter their full name and their age. As output, tell the user how many years they’ve lived for each letter in their name (for simplicity, count spaces as a letter).

Sample output:

Enter your full name: John Doe
Enter your age: 46
You've lived 5.75 years for each letter in your name.

Quiz solutions

1) Show Solution

4.5 -- Enumerated types
Index
4.4a -- Explicit type conversion (casting)

300 comments to 4.4b — An introduction to std::string

  • Gabe

    Let's say that I have 20 or so strings I want to use throughout my program in different functions, could I store them in a function and be able to use them, without redefining them, in my other functions?

    • Alex

      You could...

      That said, it would be better to use enumerators as indices instead of integers.

  • Lucas

    some more l33t super efficient h4x0r code for yall

  • cppLearner

    I could not quite get the line

    32767 is the largest signed integer number in decimal form that can be stored in int16 but it has only five characters '3','2','7','6','7'.
    The question is what is the relation between number 32767 with number of characters ?? I'm really cofused.

    • nascardriver

      Hi cppLearner!

      Whatever number you give @std::cin.ignore, that's how many characters will be ignored at max. Instead of 32767, std::numeric_limits<std::streamsize>::max() should be used.
      I don't know what you're trying to say with the five characters. The 16 in int16 means that the int is made up of 16 bits.

      • cppLearner

        Hi nascardriver!

        Can you please explain it with an example using input stream and using a small number instead of "32767".
        Thanks in advance!!

        • nascardriver

          Input: 123hello
          i: 123
          str: hello

          123 is extracted from the command line and stored in @i, "hello" remains in the input stream and is extracted into @str.

          Input: 123hello
          i: 123
          str: llo

          123 is extracted into @i, "hello" remains in the input stream. We're ignoring all characters up to a linefeed, but 2 characters max. "he" is removed from the input stream, "llo" remains and is extracted to @str.

          Input: 123hello
          world
          i: 123
          str: world

          123 is extracted to @i, "hello" remains. Everything up to the linefeed is removed from the input stream. The next std::cin wants us to enter something again, because the input stream is empty. I entered "world", "world" is extracted to @str.

  • Milad

    One way to avoid using the magic number and as Alex puts it "obscure, complex, and correct" line in your code is to declare it as an external global constant such as:

    this makes your code much more readable.

    • nascardriver

      Hi Milad!

      This sure is a way of improving the code. However, for std::cin.ignore it still doesn't have any special meaning. 32767 characters will be ignored and everything after that remains in the buffer. Although std::numeric_limits<std::streamsize>::max() is a number like every other it causes std::cin.ignore to ignore indefinitely, because std::cin.ignore checks for it.

      Some sample psuedocode of how to imagine this:

  • nascardriver

    Hi Alex!

    Why does this work?

    I can't find any information about it.

  • Hi Alex,
    I think there might be a typing mistake here. In the statement "Perhaps surprisingly, when you run this program, it will ask you to enter your name, but then skips waiting for you to enter your name! What happened?". I think you wanted to say - "when you run this program, it will ask you to *pick 1 or 2, but then skips waiting for you to enter your name". Isn't it?

    • Alex

      Not a mistake, I just started describing what happens starting from the "Now enter your name" part of the program. However, I can see how this might be confusing, so I've updated the lesson text to be a little more complete.

  • Hi Alex/ nascarrdriver 🙂

    here is my code:

    • nascardriver

      Hi Ali!

      Your code is getting better, good job!

      • so i always have to initialize my variebles?

        and wdy mean by escape single quotes?

        EDIT: thank you vm 🙂

        • nascardriver

          > so i always have to initialize my variebles?
          You don't have to. It doesn't change anything in this program. But if you ever forget to assign a value to the variable before using it you will get undefined behavior which is a pain to debug. Always initializing variables avoids this.

          > and wdy mean by escape single quotes?

          I don't think it makes a difference in strings, but a single quote is a special character so it should be escaped.

          • are you curious to see my original code before editing?

            • nascardriver

              If you have any questions about it or want improvement ideas go ahead and post it. I won't correct it if it has the same mistakes I pointed out on your earlier posts.

              • then i realized the mistake and switched it to double 🙂

  • Matt

    I would like to thank the author again for this amazing tutorial series.  Here is what I came up with for this quiz -- how am I doing?

    • nascardriver

      Hi Matt!

      You're doing pretty good, I added some comments to your code.

      • Alex

        Just a quick note: I recommend using signed numbers even when a number can't be negative (e.g. the user's age). This helps avoid unexpected signed/unsigned issues (covered in chapter 2.4a)

        The only exception to this is when we're doing bit manipulation -- for those, unsigned makes sense.

      • Matt

        Thanks for the feedback! Just to make sure I'm clear, when you say "initialize your variables," even when I'm about to ask the user for input to the variable, I should initialize as an empty string (or as '0' or something random just for the sake of it? Is it dangerous to have an uninitialized variable in a function when the next line of code assigns value to it?

        Thanks again to you and Alex for the feedback.

        • nascardriver

          If you're assigning a value to the variable before using the variable this isn't a problem. But if you ever forget to assign a value before using it you'll have a hard time finding the problem, because uninitialized variables cause undefined behavior.
          Programs should be deterministic, so we initialize variables to make sure that, at any time, we know the value of the variable.

  • Silviu

    Hello, I did try to solve the problem , so i taught i just have to use ".length()" i didn't think it in that way. If you can change it a little bit to see the question without misleading to think something else, thanks . Maybe i rushed...

  • Yus K

    I did it this way, please offer any advice on my code, also would my code be better or worse than the way it was solved in the example. My code seems to be significantly longer but im trying to keep main function clear by using multiple functions.

    Things i believe i could improve this code with are
    1) Use a header file for forward declarations.
    2) Separate the functions into their own .cpp file
    3) Also i realized i made a mistake by using the less preferred c type cast over a static cast

    • nascardriver

      Hi Yus!

      The comment system messed up your code, I'll ignore all error which I think were caused by this.

      Line 8, 14: Initialize your variables
      Line 22: You said it already, here's how

      Only one argument to / needs to be a double for the result to be a double.
      Line 22: Missing std::endl, this will cause malformed output in certain situations.
      Line 27, 28: Uniform initializers are preferred

      > better or worse than the way it was solved in the example
      There's no point in comparing so little code, both are fine. Yours is easier to build upon, because you used functions, that's good.

      1) 2)
      With this little code having multiple files will be more confusing than helpful, but remember this for actual projects. Those should have a minimal main.cpp.

  • Weckersduffer

    Here´s mine, some advice?

    • nascardriver

      Hi Weckersduffer!

      Good code, keep it up

  • ASP

    "Note that strings can hold numbers as well"
    Pls provide some useful examples where we actually use it so that i can better understand. Thanks.

    • nascardriver

      Hi ASP!

      This could be used to figure out how many digits a number has for example.

      Enter a number: 2347924                                                                                                
      The number you entered has 7 digits

  • Bobby der Bob

    Is something behind the number 32767 or is it only a number you chose at random?

    • Alex

      It's the largest signed integer guaranteed to fit in an int (2 bytes).

    • nascardriver

      It should be std::numeric_limits<std::streamsize>::max() instead of 32767 according to the documentation. Apparently Alex doesn't like it 🙁

      • Alex

        Technically, your answer is correct.

        I don't like it because "std::numeric_limits::max()" is extremely hard to commit to memory (and requires bringing in additional headers, which you also have to remember).

        Using 32767 works almost as well, and it's something that doesn't require consulting external documentation every time you want to use it.

        • nascardriver

          I agree and understand the use of 32767 over std::numeric_limits<std::streamsize>::max() for the sake of your tutorials and for making it easier to new learners. I'd just like it to be mentioned in the introduction of std::cin::ignore so readers understand why you chose 32767 and what it's supposed to be.

  • Kaj

    Here's mine, with a little extra functionality. You can kind of tell I was having fun with it (:

  • Muneeb

    Alex do you give on line video tutorial as well??

  • Nick

    Any bad habits to get rid of now?
    Any problems with the code?

    • nascardriver

      Hi Nick!

      Initialize your variables.
      I prefer initialization with curly braces, because they only accept the right type.
      The brackets around name.length() don't do anything.
      @main should return an int.

      In lesson 5.10 you'll learn about input validation, this can be used to detect if the user actually entered a double when you asked for a double.

  • Will

    I did like this:

    Any potential issue?

    • nascardriver

      Hi Will!

      Here's another version of your code

      Although it seems like a lot, those are minor issues, good job on solving the quiz!

    • Alex

      No major issues, but a few nitpicks:
      * You define variable namenumber and then assign a value to it on the next line. You're better off initializing it with a value on the same line as the definition.
      * There isn't really for variable namenumber at all. Just use name.length() in your x initializer.
      * You're using C-style casts. You should use C++ style static_casts instead.

  • Ronan

    I used a float rather than an int for age and that made it much more linear. Observe:

    Any reason you didn't do it like that? Is there a downside to this method?

    • Alex

      There's no downside, we just generally should pick data types that best represent the thing we're trying to model. Since ages are most often reported as whole numbers (you say, "I'm 21", not "I'm 21.2"), an integer is a better choice. Otherwise, you get into questions like how to interpret the decimal value. Does "21.11" mean 21 years and 11 months? Or does "21.11" mean 21 years and 11/100ths of an additional year?

  • Shane

  • Zero Cool

    Here is my solution for the Quiz:

    io.h

    io.cpp

    main.cpp

  • Dat coder

    Hello Alex.
    In your solution you create two variables (letters and ageperletter).Is there a reason to do that over this ?

  • gary

    hi alex, i am sorry i am little bit confuse, what does it mean:
    std::cin.ignore(32767, '\n'); // ignore up to 32767 characters until a \n is removed

    why does it has to be 32767 and i am still little bit confuse of ignore up to 32767 characters purpose. thanks

    • Alex

      32767 is the largest signed 16-bit integer. Any larger number could potentially overflow an int. It doesn't HAVE to be 32767 -- we could use a smaller number, but then if for some reason you had 32767 characters before a '\n' they wouldn't all get cleared out. Unlikely, but there's no harm in choosing 32767 over some smaller number, so we might as well.

  • The Perplexed Programmer

    Hello Alex!
    Following is a program, which is a kind of quiz. As of now, there are just 2 questions. Anyway, how do we display the score at the end? Something like "You score 1 out of 2"

  • The Perplexed Programmer

    Hello Alex!
    The following program does'nt seem to work out. Could you please help me out?

    • Alex

      What doesn't work about it?

      • The Perplexed Programmer

        It doesnt really ask for any input after "Would you like to enter the common difference or last term?" No matter what I enter, the program ends. Please help!
        Also there was supposed to be a '#include <string>' at the top. I fixed it, but the problem persists.
        Thanks!

        • Alex

          Oh. Best guess is that after extracting variable n from the input stream, the '\n' is still left in the stream. So when you go to getline something, you're extracting the '\n'. You can address this by calling std::cin.ignore(32767, '\n'); just before doing your getline call.

  • Bálint

    Hi Alex!

    I've done the quiz question, but when I checked the result, I noticed it is off.
    After some thinking, I realized that in my name I has UTF-8 characters, and they has length 2.
    I don't know, probably it is compiler specific feature as well, but maybe it is worth to mention it in the tutorial, in case there are others facing the same problem..

  • Francesco

    Hi Alex,
    thanks for your tutorial.

    I'm a hobbiest Python programmer and I would like to learn C++.

    I read a lot on this site but I don't understand how to interact with operating system.

    In Python if I want to take the list of files present in a directory and put them in a vector (array) I have to wrote a few lines of code using the standard library.

    Is there a way to do this with C++ STL? C++ is very complicated and I don't understand how to write a function that does this.

    How about a string search in a file and put some data in an array?

    Thanks

    • Alex

      Some things that are easy in modern languages like python are surprisingly complicated in C++. Directory access is one of those things that C++ does not make easy to do in a cross-platform compatible way.

      In C++17 (slated to be released later this year), it looks like they're adding a std::filesystem library to iterate through a directory. You could also use a third party library like Boost.

      C++ does provide the ability to open and read file data. That's covered in chapter... 19 I think.

      • Francesco

        Thank you, so my doubt is foundated 😀

        If I understood correctly the external library that performs directory access uses C code, isn't it correct?

        So, If I would like to write a Linux-only application the only easy-way to access to file system (without using external library) is to use C++ system() function, correct?

        Thanks a lot

        • Alex

          > If I understood correctly the external library that performs directory access uses C code, isn’t it correct?

          If you're talking about Boost, I'm not sure what they're using under the hood.

          If you're writing a linux only application, the unix OS should provide functionality to directly access the file structure (e.g. via OS-specific functions opendir(), readdir(), and closedir()). See this thread on Stack Overflow for more information about how to do this.

  • Bowen

    Hello Alex,

    I'm pretty sure this will be answered in a future lesson (or maybe in this comment section if I missed it), but is there a way to not consider the space between the person's first and last name since the number of letters in a person's full name will always be 1 more than it actually is because of the space.

    Thanks in advance! 😀

    • Alex

      Not trivially. Probably the best thing to do would be to iterate through the string, counting how many spaces the user entered, and then subtract those out.

  • Ritesh

    hi alex
    like you said when we have to enter name after choice, it skips because 2n is entered, and n is stored in the input stream, i am getting a little confused on this simple program
    #include<iostream>
    using namespace std;
    int main()
    {
           int x;
           cin>>x;
           char c;
           cin>>c
           cout<<x<<" "<<c;
           return 0;
    }
    when i run the program it asks to enter both integer and character and then displays them as both so my question is if numericn is always entered then shouldn't the output skip the part when it has to enter the character as n would be in the input stream same to what is happening in that choice, name program

  • Deepti

    Hi Alex,

    I am practicing some problems on strings. I wanted to know whether string class or c-style strings are widely used? Basically which one should I get familiarized with.
    Deepti

    • Alex

      You should get familiarized with both, as they are both widely used in different cases. But std::string should be favored whenever you can.

      • Deepti

        Thanks for your input.

        Alex,
        Below is program on reverse of a string using string class. In the for loop, the characters are getting printed, however, the cout statement is not displaying the whole string. Please help..

        #include<iostream>
        #include<string>
        using namespace std;

        int main()
        {
            string s;
            string rev_s;

            getline(cin,s);

            int i,j;

            j=s.length();

            for(i=0;i<s.length();++i)
            {
                rev_s[i]=s[j-1];
                cout<<rev_s[i]<<endl;
                j--;
            }

            cout<<rev_s;
            return 0;
        }

        • Alex

          This program doesn't work because the length of rev_s is 0, and you're using [] to try to set characters in the empty string.

          To fix this you can use the reserve function to first reserve memory for rev_s:

          Then set your characters. Don't forget to ensure rev_s has a valid null terminator.

          • Deepti

            Thanks Alex.
            Not sure why this is not running as expected.
            #include<iostream>
            #include<string>

            using namespace std;

            int main()
            {
                string s,rev_s;
                //string rev_s;

                getline(cin,s);

                int i,j;

                j=s.length();
                rev_s.reserve(j);

                for(i=0;i<s.length();++i)
                {
                    rev_s[i]=s[j-1];
                    cout<<rev_s[i];
                    j--;
                }
                //rev_s[i]='\0';
                cout<<rev_s;
                return 0;
            }
            No output is shown at  cout<<rev_s statement.

            • Alex

              Because I told you the wrong thing. Sorry. You should be using the resize() function, not the reserve() function.

              • Deepti

                Thanks Alex.
                This program worked now.
                I have another question... Are there any specific sites that you are aware of for practicing C++ problems? As the OOPS concepts for me, seem quite difficult and am not able to find sites that provide problems from basic level..
                It would be great if you could help me in this direction.

  • Hi again Alex and other commenters,

    I came up with this as a solution to the quiz, but instead of using static_cast I simply made the age variable a double and moved the calculation to a function, it seems to work ok but I'm not sure if I made an error along the way, what do you think?

    • Alex

      This is fine, although it would be better to read in the user's age as an integer.

      • Hi Alex thank you for your reply,
        I had a feeling that you might say that, for my listing that would suggest passing the age as an integer into the function and then using static_cast<double>age at line 30 in my function, is this what you mean?

          • Ok thanks, noted and applied Alex, I am sorry for all the questions but, as I am just getting started with C++ it's nice to understand how to apply best coding practices right from the start.

            And guess what, it still works great
            Thank you again 🙂

Leave a Comment

Put all code inside code tags: [code]your code here[/code]