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:

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?

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().

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)

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

  • Jatin

    Hey Alex, in the fourth program where you mixed std::cin and std::getline(), I was wondering why we did not worry about the newline when we used std::cin before .So I replaced the "std::getline (std::cin,name)" with "std::cin >> name" in that program. To my surprise the program ran fine except for the fact that it did not print my last name (which was after a whitespace).So, why std::cin read a newline when we used std::getline() afterwards but not when we used std::cin?

    • Alex

      std::cin skips leading whitespace, but breaks at any non-leading whitespace (space, tab, newline, etc…). So std::cin will stop reading at the space between the first and last name.
      getline gets everything up to the next ‘\n’ character.

  • Nyap

    Here’s my answer for the quiz

    seems about right

  • J3ANP3T3R

    in this example …

    std::cout <> age;

    after std::cin >> age it is no longer safe to use cin as it will ignore the next cin because it has n left in it ?

    i’m a little bit unimpressed with C++ at this point. i hope in the coming new versions they can fix the part where you have to use ignore for the hanging n on numeric inputs OR fix cin to read the whole input altogether.

    • Alex

      Yes, C++’s I/O library is frustratingly inconsistent. It’s my least favorite part of the language.

      The good news is that not many people write complicated console applications these days, and graphical applications usually have other routines for doing I/O.

  • Akhil

    Correct me if i am wrong but i think that i read somewhere that string header is a part of iostream header,so there is no need to include string when iostream header is included.

    The following code is working fine for me.

    • Alex

      You should always explicitly include all of the headers your files need. While iostream might #include string on your system/compiler, that might not be the case on another system or compiler.

  • Kingsident

    Alex, how can I use ‘and’ and  ‘or’ with strings

    • Kingsident

      take for instance when I try to do this

      #include <iostream>
      #include <string>

      using namespace std ;

      void widyConfirm( string widy)
      {
          if (widy == "Ocktaviany" || "OCKTAVIANY" || "ocktaviany")
              {
                  cout << "I’m going to tell you a secret…\n" ;
              }
              else
              {
                  cout << "I don’t know you ba-bye\n" ;  //this line will never be executed unless I comment out the two "or’s" in the conditional statements
              };
      }

      int main ()
      {
          using namespace std ;
          
          
          cout << "What is your name? " ;
          string userName ;
          cin >> userName ;
          cout << "\n" ;
          
          if ( userName == "Widy" || "WIDY" || "widy" )
          {
              cout << "Is this ‘the’ Widy\n" ;
              cout << "Type in your Surname for confirmation : " ;
              string widy;
              cin >> widy;
              cout << "\n" ;
              
              widyConfirm(widy) ;
          }
          
          else {cout << "It’s not her";} ;
          
         return 0 ;

          }
              
              
          
      what am I not doing right?

  • Jim

    Alex,
    Here are some more notes.  You can also use the uniform method on strings as well as numbers. You can allocate memory using empty "" as noted in this Code::Blocks version 16.01.
    [Code]
    #include <string>
    #include <iostream>

    int main()
    {
        std::string myName{""};  // allocate memory
        myName = {"Jim"};       // assign a name
        std::cout << "My name is: " << myName;

        return 0;
    }
    [\Code]

  • Jim

    Alex,
    Yes it’s strange that the Pick 1 or 2 didn’t work right  above, but with the getline for the name it worked okay.

    #include <string>
    #include <iostream>

    int main()
    {
        std::cout << "Pick 1 or 2: ";
        int choice;
        std::cin >> choice;

        std::cout << "Hello, you picked " << choice << ‘n’;

        return 0;
    }

  • Shane M

    Hi Alex,

             Thank you so much for posting this tutorial online, it is amazing and I appreciate your time effort to help coding noobs like me.

    My question is in the statement: [std::cin.ignore(32767, ‘n’) /code]

    what does the "32767" refer to?

    Thanks, Shane

    • Brian, Song

      Hi, Shane M

      32767 means the maximum number of characters to be discarded from ‘cin’ stream

      until the delimiter character(‘n’ in this case) would be reached

      *Note: delimiter character also will be discarded from the stream

      [http://www.cplusplus.com/reference/istream/istream/ignore/]

  • sharaf

    I have a doubt, using string are you defining a variable, i think you are but in my ocurse book which i don’t like at all uses something like this

    and this gets compiled fine in code::blocks..
    so what is the difference??
    plzz tell
    THANK YOU.

    • Alex

      char string[80] declares an array of 80 characters, which can be treated as a string in C and C++. I cover this case in chapter 6, when I talk about arrays and C-style strings. C-style strings used to be used a lot in the old days, but they’re dangerous, so they’re mostly avoided now.

      std::string is a class in the C++ standard library that makes working with strings easier. You should almost always use std::string.

  • sohan

    hey alex your site is helping me lot but the problem is i have to use turbo c++ compiler…. and there is some difference so plzz tell me the actual getline() command needed for turbo c++..
    hey there is visual c++ 2005 also in my school pc what compiler is that

    • Alex

      Turbo C++ is very old, no longer supported, and lacks many of C++’s newer features. I can’t answer any questions for Turbo C++ because it’s so old.

      Visual Studio 2005 is much better (though it still won’t be compliant with C++11 functionality).

  • Shiva

    Hey Alex, 3 things:

    1) ‘<iostream>’ and ‘<string>’ are missing in your reply to Mr. Ank above.
    2) Expected ‘}’ at the end of the solution-program to the quiz.
    3) As you said a header file only contains forward-declarations. The actual definitions are stored in the standard runtime library, which is included automatically by the linker during linking. My question is, is the standard runtime library too split across multiple .cpp files? So that only those files whose corresponding headers are #included in our program are linked? If the whole library is in a single file and is linked everytime, this cannot help compile faster or keep the build smaller, can it?

    • Alex

      re #3: The form the runtime library takes depends on the operating system, but it’s generally distributed as one or more static or dynamic library files that get linked into your program. On windows, these will be in .dll or .lib format. On linux, in .a or .so format.

      • Shiva

        Thanks for the info about the form in which the library is implemented, but I’m more interested to know how ‘only the things you actually need’ gets included during linking. From your explanation I infer that the standard library is a single file (or multiple files) that contains all the routines, definitions and macros for all the math, string manipulation, input/output etc. that we use in our programs. So I’m asking, when we include only iostream and no other headers that refer the standard library, does the linker knows exactly which part of the library to link? Or, since we won’t even be using all functions declared in the iostream header, is the linker smart enough to include _only_ the code of the functions that we actually used in our program? Intuitively the last seems the case, but so far you have only talked about how the standard library get included at link time, and it feels like the whole library get linked to our executables. And if this was the case it would include the code for routines that we never use in our program, which is obviously unnecessary. If I’m wrong on all accounts, can you please tell me the actual mechanism if it is not too complicated for a novice to understand? 🙂

        • Alex

          There are two ways libraries can get linked into your program: statically or dynamically. Static means the library is packaged into your executable. Dynamic means the library is kept as a separate file and loaded at runtime. Most programs load the C++ runtime dynamically, so only one copy needs to exist on the system.

          As far as I can tell, at least with Visual Studio on Windows, the C++ runtime library is a single file (msvcp100.dll).

          • Shiva

            So, put it this way - if I use a function from iostream, the #include-ed header file contains only its forward-declaration to satisfy the compiler, but the actual definition - the code that says what my function does - is linked to my executable only at the time of execution? Is this what a Dynamic Linker does? So if the library does not exist in the target system, my executable won’t run. I remember applications quit on Windows complaining about the absence of a particular Visual C++ Redistributable package. Is this the package that contains Microsoft’s implementation of the C++ runtime library on Windows?

            Sorry for asking so many questions at once..

            • Alex

              Yes, that is pretty much correct.

            • Shiva

              Yay! That’s cool. I suppose the dynamic linker is a part of the OS of the target system, just like the loader. One last question to clear everything up:

              How does the ordinary (static?) linker (which makes our executables) know a particular function is from a runtime support library, so to leave off its linking for dynamic linker? I mean, the linker always throws an error if we declare a function and not define it, but it doesn’t complain about the absence of the definitions of functions from the runtime library. Does the compiled code contain any such indications?

              • Alex

                You can configure whether you want to access the standard library statically or dynamically in your project settings. The linker will then check to ensure all the functions you call have definitions in the static or dynamic version of those libraries.

            • Shiva

              Ah! Now it is clear. This means that even if we are planning to use a dynamic library, which is to be linked at runtime, we need it installed in our systems for the static linker’s reference at build-time. So the linker does not build blindly, right? It ensures that all our functions are well defined either in our own executables or in a dynamic library they are gonna use later at runtime. And only then does it leave those dynamic references unresolved. Very clever.

              I think that’s all I needed to know. I just wanted a basic know-how, and not the nitty-gritty details of how dynamic linking is done, and you gave me just that. Reading your own modules about libraries (Appendix A.1) and some StackOverflow threads also helped a lot. It’s nice to see a lot of good folks like you helping each other out.

              Thank you so much for your time and help. Much appreciated. God Bless. 🙂

  • Ank

    If the namespace used for declaring  string is same as that for header <iostream> i.e std.Whats the need for adding another header i.e <string>?

    • Alex

      Namespaces can be split across multiple files.

      contains input and output routines (e.g. std::cin and std::cout), inside namespace std.
      contains string routines (inside namespace std).

      Having separate header files allows you to include only the things you actually need (which keeps your program smaller and compiling faster).

  • Vaibhav

    Hi Alex;
    I don’t know why but when I try to compile the very first program in this section using string it says undefined symbol string although I have included <string.h>..Please help me.. I am using turbo C++

  • AB

    I have code here, and an error I don’t know how to fix!

    • Alex

      std::string doesn’t come with a conversion to const char*, so the static_cast is failing.

      You can convert a std::string to a const char * by using the c_str() function:

  • hei_xhimi

    No matter what i try still reads numbers end outputs error after two inputs…
    Please can somebody help?!

    • Alex

      First, get rid of the cin.clear() and cin.ignore() lines, they aren’t needed.

      Second, the reason it still reads numbers is because you’re doing a getline(cin, name), which allows numeric input, and then checking to see if the string contains any numbers. If you want to disallow the user from typing numbers at all, you’re better off reading input character by character and only appending the character to the name if it’s alpha.

      Third, the reason your program crashes after entering one bad name is because changing variable name invalidates the iterator, but the iterator is still subsequently used in the for loop. Moving to character by character input is probably the best solution, but if you want to continue to do things this way, I’d write a function to check if name is all alpha or not. If not, then you can read in a new name and loop.

  • Simon

    Alex, thanks for all the tutorial. It’s really fun and easy to follow.

    I tried to put together everything learned since the beginning. And created a program that gather input from the user about his smoking habit then deliver the amount of money wasted in cigarette… (Trying to stop smoking here… and wanted to find a way to see how much i wasted in money)

    Works perfectly!

    Here is the code;

    Could you let me know if it will be a better way to actually do that, or is it ok?
    Thanks again.

    • Alex

      I think this is mostly fine for a program of this length. Stylistically, I’d make better use of whitespace to separate things (e.g. put blank lines between the code that deals with name, age, etc… to conceptually separate them a bit), and I’d put the code that does the output in a separate function. But those are minor gripes.

  • Arda

    Hey Alex. When I build this program it succeedes but when I run it, it pretty does nothing. It doesn’t write anything to the console. What’s wrong with it?

  • Probably a dumb question but how do you integrate the std::string type with calls like fopen? Do I need to do a type cast to (char *)?

  • Ethan

    When I do a basic thing in Code::Blocks such as print a string or add two numbers it builds fine but nothing shows up when it actally runs, any help on this please?

    • Alex

      A few thoughts:
      1) Are you actually running the program after compiling it?
      2) If so, is the window actually showing up and then disappearing immediately?
      3) If not, have you tried disabling your anti-virus?

  • Hridayesh

    hey alex we can also use string like this. what the purpose of using it with scope resolution operator as u did eg std::string name

    Also please tell me u used the std namespace for string type variable. how would compiler know that u are asking it for which std namespace or you are only asking it for std namespace in iostream

    • Alex

      Using the prefix std:: avoids naming conflict since there’s no ambiguity about what name is intended.

      I don’t understand your last question. Can you rephrase?

      • Hridayesh

        i mean when we #include<iostream> header and to use cout or cin objects we use std namespace either by using keyword or :: operator. here i understood that there is a namespace called std in iostream whose objects we want to use in our file. but when we #include<string> again to use its content you specified std::string i.e. your are trying to get into string header file’s std namespace aren’t you?
        my question is :  is there the same namespace in string header file also as in iostream called std?

        My another question is in my version of program i didnot use the prefix std:: for string and it works. how it worked?
        And  in your program u prefixed it with std:: , does it work like this that for string my compiler will first look up in std namespace of iostream and if it didnot find it in there it will look up in string header file and then it will compile correctly?

        • Alex

          Yes, namespaces can be split across multiple files. As you note, the iostream header has its contents inside namespace std, as does the string header. It’s the same namespace, with parts of it defined in different places.

          > My another question is in my version of program i didnot use the prefix std:: for string and it works. how it worked?

          Are you using a using statement anywhere (e.g. using namespace std;)? If so, this will cause “string” to resolve to std::string.

  • Alex

    > Isn’t it true that all assignments to a strings have to be made enclosed in parentheses and quotes like this: std::string a(“45”);or std::string myName(“Alex”);, with this one exception, myName = “John”;?

    The following are initializations (can only be used for initializing newly defined variables):

    The following is an assignment (used with string variables that are already created):

    > will myname = (“John”) work too?

    Yes. (“John”) evaluates to “John”, which can then be assigned to variable myname.

    I don’t understand your last question.

  • Jim

    Alex,

    Isn’t it true that all assignments to a strings have to be made enclosed in parentheses and quotes like this: std::string a("45");or std::string myName("Alex");, with this one exception, myName = "John";?  The latter seems pretty dumb, will myname = ("John") work too?

    Can the latter syntax be used instead of this:
    std::getline(std::cin, end);
    std:: cin(std::getline, end) ?

  • Nathan

    Just wanted to say thank you so much for posting such a detailed yet clear explanations. Your website rocks! 🙂

  • andy mackeroon

    Thank for the reply and suggestion Alex, I did a bit of research and I saw a few things on line that said cin and getline can cause issues when used one after the other, basically for the reason you gave, cin keeps the newline character in the buffer.

    Just tried it and it works like a charm BTW.

  • andy mackeroon

    I’m hoping I am not asking another stupid question here, but I have added a getline to the end of the name/years program (see attached code below), so I could compile it to an .exe and stop the program ending before the user has had time to read the results, but no matter what I do the second getline at the end of the code just falls through, IE it doesn’t wait for input, and I can’t for the life of me work out why. I have tried lots of different things but whatever I do it just falls thru the code. If I was to guess I would take a stab at it has something to do with characters being in the buffer still, do you need to flush the buffer somehow between uses of getline? Doesn’t sound likely, what am I doing wrong?

    • Alex

      It looks like the problem is coming from std::cin >> age. When the user enters “25\n”, the 25 is input into variable age, and the ‘\n’ is left in the input buffer.

      The call to std::getline() then eats the \n instead of waiting.

      You can fix this by adding this line between reading in the user’s age and doing the std::getline():

      • dave

        so
        std::cin >> age;
        std::cin.ignore(32767, ‘n’);
        ?

        you didn’t actually give an example in this section or put it in the quiz solution so it left it all a bit semi-confusing. like, why is 32767 needed? will this be advanced upon later? do we only do it on the final use of cin or is it better practice to flush it every call to prevent buffer errors? does the /n from the previous getline(etc) get overwritten automatically?
        thanks

        • Alex

          I updated the example to show std::cin.ignore() in use (as well as a comment as to what 32767 does). This call removes up to 32767 buffered characters until a \n is removed.

          Generally, you’ll want to use this whenever you read a numeric input from std::cin and then want to use std::getline() immediately after (to prevent std::getline() from reading in the leftover \n).

          • Alexander Kindel

            Is there anything special about the number 32767? That is, is it an arbitrary large number, where the only important thing is that it’s larger than one could reasonably expect the length of the input to be, or does it have to be exactly 32767, not, say, 32766 or 32768?

            • Alex

              I presume you’re talking about the parameter to ignore().

              32767 is the largest 16-bit signed number. 32768 could overflow, and 32766 isn’t quite as big. In most cases, a much smaller number will suffice, but there’s no harm in using a larger one so we might as well.

  • R4Z3R

    I think that just iostream library is enough.
    when I compiled the following code in Dev-C++ worked fine:

    • Alex

      If you’re using std::string, you should #include <string>.

      It’s bad form to rely on other headers including things for you, and even if it works on your system, it may not work on other compilers or systems.

  • John

    When i try to run this:

    it gives me an error that sais
    C:\Users\VeX\Desktop\Void\wofear_ex\StringEx1.cpp|18|error: invalid static_cast from type ‘std::string {aka std::basic_string<char>}’ to type ‘double’|

    Thoughts?

    • Alex

      I pasted your snippet into Visual Studio and it compiled fine. So I’m guessing you have a typo in your version of the code.

      Since the error is complaining about not being able to convert a std::string to a double, my best guess is that either:
      1) You defined age as a std::string instead of an int.
      2) You put “static_cast(name)” instead of “stathttp://www.learncpp.com/blog/wp-admin/edit-comments.php#comments-formic_cast(age)”.

    • techsavvy....aye

      I don’t know if I am only not seeing it but you haven’t put a ‘}’ at the end and afterwards it compiles just fine.

  • Todd

    Typo.

    "std::string is complex… They also have (It also has) a lot of other capabilities"

  • Randy

    In the quiz, why wasn’t the variable age or letters defined as a double instead of using static_cast to change it? Is there an advantage to using static_cast in this situation?

  • Devin

    This is probably not the best place to put ask this, but the

    got me thinking: Is it bad practice to put the

    in a header file? I’ll show you what I mean.

    myName.cpp

    Header.h

    • Alex

      In general, files should directly include the header files that they need. If myName.cpp needs string and iostream, it should include string and iostream itself.

Leave a Comment

Put C++ code inside [code][/code] tags to use the syntax highlighter