The very first C++ program you wrote probably looked something like this:
1 2 3 4 5 6 7 |
#include <iostream> int main() { std::cout << "Hello, world!\n"; return 0; } |
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!\n”) are placed between double quotes to identify them as strings.
Because strings are commonly used in programs, most modern programming languages include a fundamental string data type. In C++, strings aren’t a fundamental type (they’re actually a compound type
, and defined in the C++ standard library rather than as part of the core language). But strings are straightforward and useful enough that we’ll introduce them here rather than wait until the chapter on compound types (chapter 8).
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.
1 2 3 |
#include <string> // allows use of std::string std::string myName {}; // empty string |
Just like normal variables, you can initialize or assign values to strings as you would expect:
1 2 |
std::string myName{ "Alex" }; // initialize myName with string literal "Alex" myName = "John"; // assign variable myName the string literal "John" |
Note that strings can hold numbers as well:
1 |
std::string myID{ "45" }; // "45" is not the same as integer 45! |
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 output
Strings can be output as expected using std::cout:
1 2 3 4 5 6 7 8 9 10 |
#include <iostream> #include <string> int main() { std::string myName{ "Alex" }; std::cout << "My name is: " << myName << '\n'; return 0; } |
This prints:
My name is: Alex
Empty strings will print nothing:
1 2 3 4 5 6 7 8 9 10 |
#include <iostream> #include <string> int main() { std::string empty{ }; std::cout << '[' << empty << ']'; return 0; } |
Which prints:
[]
String input with std::cin
Using strings with std::cin may yield some surprises! Consider the following example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> #include <string> int main() { std::cout << "Enter your full name: "; std::string name{}; std::cin >> name; // this won't work as expected since std::cin breaks on whitespace std::cout << "Enter your age: "; std::string age{}; std::cin >> age; std::cout << "Your name is " << name << " and your age is " << age << '\n'; return 0; } |
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 std::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. When we then used operator>> to get variable age
, it extracted "Doe"
instead of waiting for us to input an age. Then the program ends.
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():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <string> // For std::string and std::getline #include <iostream> #include <iomanip> // For std::ws int main() { std::cout << "Enter your full name: "; std::string name{}; std::getline(std::cin >> std::ws, name); // read a full line of text into name std::cout << "Enter your age: "; std::string age{}; std::getline(std::cin >> std::ws, age); // read a full line of text into age std::cout << "Your name is " << name << " and your age is " << age << '\n'; return 0; } |
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
What the heck is std::ws?
In lesson 4.8 -- Floating point numbers, we discussed output manipulators
, which allow us to alter the way output is displayed. In that lesson, we used the output manipulator
function std::setprecision()
to change the number of digits of precision that std::cout displayed.
C++ also supports input manipulators (defined in the iomanip
header), which alter the way that input is accepted. The std::ws
input manipulator
tells std::cin
to ignore any leading whitespace. Note that std::ws
is not a function.
Let’s explore why this is useful. Consider the following program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <string> #include <iostream> int main() { std::cout << "Pick 1 or 2: "; int choice{}; std::cin >> choice; std::cout << "Now enter your name: "; std::string name{}; std::getline(std::cin, name); // note: no std::ws here std::cout << "Hello, " << name << ", you picked " << choice << '\n'; return 0; } |
Here’s some output from this program:
Pick 1 or 2: 2 Now enter your name: Hello, , you picked 2
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” string, and then exits. What happened?
It turns out, when you enter a value using operator>>, std::cin not only captures the value, it also captures the newline character ('\n'
) that occurs when you hit the enter
key. So when we type 2
and then hit enter
, std::cin receives gets the string "2\n"
. It then extracts the 2
to variable choice
, leaving the newline character behind for later. Then, when std::getline() goes to read the name, it sees "\n"
is already in the stream, and figures we must have previously entered an empty string! Definitely not what was intended.
We can amend the above program to use the std::ws
input manipulator, to tell std::getline()
to ignore any leading whitespace characters:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <string> #include <iostream> #include <iomanip> // For std::ws int main() { std::cout << "Pick 1 or 2: "; int choice{}; std::cin >> choice; std::cout << "Now enter your name: "; std::string name{}; std::getline(std::cin >> std::ws, name); // note: added std::ws here std::cout << "Hello, " << name << ", you picked " << choice << '\n'; return 0; } |
Now this program will function as intended.
Pick 1 or 2: 2 Now enter your name: Alex Hello, Alex, you picked 2
Best practice
If using std::getline
to read strings, use the std::ws
input manipulator
to ignore leading whitespace.
Key insight
Using the extraction operator (>>) with std::cin ignores leading whitespace.
std::getline does not ignore leading whitespace unless you use input manipulator std::ws.
String length
If we want to know how many characters are in a std::string, we can ask the std::string for its length. The syntax for doing this is different than you’ve seen before, but is pretty straightforward:
1 2 3 4 5 6 7 8 9 |
#include <iostream> #include <string> int main() { std::string myName{ "Alex" }; std::cout << myName << " has " << myName.length() << " characters\n"; return 0; } |
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 -- 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. 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 time
Question #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.
![]() |
![]() |
![]() |
i think the quiz answer is kinda hard to read and in this example we're not using those variables again so for the sake of simplicity i reduced the code here's my answer:
I'm sure the developer himself will be proud of you.
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
do we need that for getline too ?
You can use std::cin.ignore whenever you want to clear any stored but unextracted input from std::cin.
I updated this lesson today in such a way that use of std::cin.ignore is no longer required for the examples in this lesson.
std::getline(std::cin, name) also has its faults...(https://stackoverflow.com/questions/62374433/alternatives-of-getline)
I prefer using std::getline(std::cin >> std::ws, name);
Lesson updated to incorporate this information. Much appreciation to you.
Minor edit: I think for “What the heck is std::ws?" it should link 4.8, not 4.12
Indeed. Thank you much!
Typo in String Length section:
"If we want to know how many characters are in a std::string is,"
-> "If we want to know how many characters are in a std::string,"
Thanks TypoMan
Hey, what's the best way to convert a non-literal int to a std::string so I can append it to said string? I found a bunch of different ways on the internet, but I don't know which is best:
- std::ostringstream
- std::to_string
- boost::lexical_cast
- std::stringstream
That depends on how you define "best".
`boost::lexical_cast` requires an external library, that's not good (It's stream-based, you could just use `std::ostringstream`).
`std::stringstream` is `std::ostringstream` but supports input, you only want output.
You only want to convert 1 integer, you don't need a stream, that leaves `std::to_string`.
`std::to_string` constructs a new `std::string`, that's expensive.
All gone.
If you already have a `std::string`, you can use `std::to_chars` to write the result directly into that string, but you have to reserve memory.
Simplest is `std::to_string`, fastest should be `std::to_chars`, pick your poison.
Thanks! Didn't expect it to be this kinda choice lol
....It turns out, when you enter a value using operator<<, std::cin not only captures the value........
operator<< or operator>>
Should be operator>>. Fixed! Thanks for the catch.
Why do we need to do a static_cast<int>name.length() ? Isn't name.length() already an integer?
int letters{ static_cast<int>(name.length()) };
1) Why do we need to use static_cast<int> for name.length()? Isnt it integer by default?
2) How can we check what type does name.length() have? I tried typeid(name.length()).name, but it constantly gives me compiler error. I included <typeinfo>;
1. Section 'Mixing std::cin and std::getline()'
why do we have a newline if we didn't type it?
Whenever you press enter, that's a newline
You say here that myName.length() is the first use of member function syntax, but in fact, we've seen it earlier with std::cin.ignore().
Hey, you asked us to tell you if you passed 32767 to std::cin.ignore(). You use it here and also advocate its use, so there ya go
Hello alex and nascardriver, i was wondering about the line feed issue by using std::getline after std::cin. Is it true that since std::cin does not extract \n, it's left in the input buffer? Due to this, std::getline thinks it's the end of the string, and mistakes it at the end of the string. Does it discard everything after it? Or does it remain in the input buffer.
I was thinking about this, what if i had this program. I inputted "\n hi" witht he intention of tricking the interpreter that it's the end of the line, and not extract anything. Surprisingly, it didn't work. Are you able to explain to me why? Once again, thank you for your time!
I don't think I understand your question.
You input a line feed, `std::getline()` stops extraction (Discarding the line feed), `myString` is empty, " hi" remains in the stream.
What i mean is that in your above example provided, std::getline sees that \n is already in the stream, and stops extraction. When i try to manipulate a std::getline by inputting a string like "\n hi", why does it not stop extracting? Or does c++ interprete everything i entered as a string? Thanks for clarification.
Interestingly enough, i tried it with std::cin and integers, and i inputted \n4 4, and somehow both variables got output as 0, did std::cin fail here and why so? I felt it was weird, as shdn't std::cin ignore \n?
\escape codes only work in literals, you can't enter them on the command line. If you enter a \ on the command line, that's literally a \ character.
Thanks so much! I had so much trouble understanding this, sorry for the trouble and thanks for clarification!
Question 1:
Why does this code work in my machine? I haven't # included <string>.
Question 2:
Who is John Doe? Even I saw this name in a stackoverflow answer.
https://www.learncpp.com/cpp-tutorial/header-files/#missing_include_but_works
John Doe is a generic name that's used when you don't want to show a real name. Your country probably has such a name too. It's often used when pictures of identity/insurance/credit/etc cards are shown.
John Doe = 7 letters.
Age = 46.
46 / 7 = 6.571...
The code needs to be modified to include a counter for white space.
This gives the correct answer.
A more compact version of the Quiz 1 solution:
I kept getting the error "Conversion from 'unsigned int' to 'double' requires a narrowing conversion". Changing age from int to double fixed the issue.
Thank you for the lessons
Well explained!
1. Section "Appending strings", first sentence:
> You can use operator+ to concatenate two strings together (returning a new string), or operator+= to append a string to the end of an existing string).
Ends with a stray parenthesis.
2. Why does `std::ignore()` request input when the input buffer is empty?