Strings (std::string)
std::string is the safe, flexible way to handle text in C++. It grows on demand, manages its own memory, and comes with a rich toolkit for joining, searching, slicing, and transforming text. This lesson takes you from + concatenation to bounds-checked access, searching with find , and converting between strings and numbers.
Learn Strings (std::string) in our free C++ course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick recall.
Part of the free C++ course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn
💡 Real-World Analogy
A std::string is like a magnetic letter board that resizes itself. You can snap letters on the end ( += ), read the letter at any slot ( s[3] ), search for a word ( find ), or peel off a strip of letters ( substr ) — and the board automatically makes room when you add more. A raw char[] array, by contrast, is a fixed-size board: run out of slots and letters spill off the edge, corrupting whatever is next to it in memory. That spill is the infamous buffer overflow, and std::string exists to prevent it.
1. Creating & Joining Strings
Build text with + to concatenate and += to append in place. .size() (or its synonym .length() ) gives the character count, .front() / .back() read the ends, and .empty() checks for an empty string.
2. Accessing Characters
Index individual characters with s[i] starting from 0 . For untrusted indexes prefer s.at(i) , which throws std::out_of_range instead of silently reading garbage. A range-based for visits every character in turn.
3. Searching & Slicing
find returns the index of a substring, or the special value string::npos when it isn't there — always test against npos , never -1 . substr(start, length) extracts a slice, and replace swaps out a section.
4. Converting Between Strings & Numbers
to_string turns a number into text (handy for building messages), while stoi and stod parse text back into an int or double . Note that to_string(4.5) prints with trailing zeros — use <iomanip> formatting if you need control.
5. Transforming Text
Combine std::transform with toupper / tolower to change case, and the erase-remove idiom to strip characters. These standard-library tools are faster and clearer than hand-written loops once you recognize the pattern.
Your turn. Build a username and report its length:
🧩 Reorder Challenge
These lines should find a word and print the text after it. Reorder them so the program prints fox .
Why: first you need the string (A), then locate "fox" with find (B). You must check the result against string::npos (C) before using it, because substr with an out-of-range index would throw. Only then is it safe to slice from p to the end (D), giving fox . Return last (E).
🧠 Quick Recall
Predict the output before revealing each answer.
cde — substr(2, 3) starts at index 2 and takes 3 characters.
1 — "z" isn't in "cat" , so find returns npos and the comparison is true (prints as 1).
46 — both strings are parsed to ints first, so it's numeric addition (12 + 34), not string concatenation.
Pro Tips
- 💡 Pass big strings by const& : void f(const string& s) avoids copying.
- 💡 Compare with npos , not -1 : find returns an unsigned type.
- 💡 Use .at() for untrusted indexes: it throws instead of corrupting memory.
- 💡 "text"s with using namespace std::string_literals makes a std::string literal directly.
Common Errors (and the fix)
- Forgetting #include <string> : using string without it fails to compile.
- Out-of-range [] : s[s.size()] is undefined behavior. Use .at() to catch it.
- Adding two string literals: "a" + "b" doesn't compile — at least one side must be a std::string . Use string("a") + "b" .
- stoi on bad text: stoi("abc") throws std::invalid_argument . Validate or wrap in try/catch.
📋 Quick Reference
Operation
Description
Example
s.size() / s.length()
number of characters
"abc".size() → 3
s.empty()
true if length is 0
"".empty() → true
a + b, s += b
concatenate / append
"Hi" + " there"
s[i]
char at index (no check)
fast; UB if out of range
s.at(i)
bounds-checked access
throws std::out_of_range
s.front() / s.back()
first / last character
"abc".back() → 'c'
s.substr(pos, len)
extract a slice
"abcdef".substr(2,3) → "cde"
s.find(sub)
index of substring
returns string::npos if absent
s.replace(pos, len, str)
swap part of the string
in place
s.insert(pos, str)
insert text at pos
"hello".insert(2,"XY") → "heXYllo"
s.erase(pos, len)
remove characters
"hello".erase(1,2) → "hlo"
a == b, a < b
compare lexicographically
"abc" < "abd" → true
to_string(n)
number → string
to_string(42) → "42"
stoi(s) / stod(s)
string → int / double
throws on non-numeric text
s.c_str()
C-style null-terminated text
for old C APIs
Frequently Asked Questions
Mini-Challenge: Initials Generator
Read a full name and print the initials, each followed by a period. Match the expected output in the comments.
🎉 Lesson Complete
- ✅ + / += join strings; .size() measures them
- ✅ s[i] is fast, s.at(i) is bounds-checked
- ✅ find returns an index or string::npos
- ✅ substr slices; replace / erase edit
- ✅ to_string , stoi , stod convert between text and numbers
- ✅ Next lesson: Type Casting — convert between types deliberately with static_cast
Practice quiz
Which operators join (concatenate) strings in C++?
- & and &=
- * and *=
- + and +=
- , and ;
Answer: + and +=. + concatenates two strings and += appends in place.
Which member function returns the number of characters in a string?
- s.size()
- s.count()
- s.chars()
- s.length() only
Answer: s.size(). s.size() (a synonym of s.length()) returns the character count.
What does s.substr(2, 3) return for the string 'abcdef'?
- 'abc'
- 'bcd'
- 'def'
- 'cde'
Answer: 'cde'. substr(2, 3) starts at index 2 and takes 3 characters: cde.
What does std::string::find return when the substring is NOT present?
- -1
- string::npos
- 0
- an empty string
Answer: string::npos. find returns string::npos when the substring is absent; compare against npos, not -1.
Which access is bounds-checked and throws std::out_of_range on a bad index?
- s.at(i)
Answer: s.at(i). s.at(i) checks bounds and throws; s[i] does not check for speed.
Which function converts an int to a std::string?
- stoi
- stod
- to_string
- atoi
Answer: to_string. to_string(42) turns a number into a string.
What does stoi('12') + stoi('34') evaluate to?
- '1234'
- 46
- '46'
- 1234
Answer: 46. Both strings are parsed to ints first, so it is numeric addition: 12 + 34 = 46.
Why must you compare find's result against string::npos rather than -1?
- npos is faster
- -1 is reserved
- find never returns -1 by accident
- find returns an unsigned type
Answer: find returns an unsigned type. find returns an unsigned size_t, so comparing to -1 is unreliable; use string::npos.
Why does 'a' + 'b' (two string literals with +) fail to compile?
- Literals are too short
- At least one side must be a std::string
- + is not defined for text
- You need three operands
Answer: At least one side must be a std::string. You cannot add two C-string literals; wrap one in std::string, e.g. string("a") + "b".
What does stoi('abc') do at runtime?
- Returns 0
- Returns -1
- Throws std::invalid_argument
- Returns the ASCII code
Answer: Throws std::invalid_argument. stoi on non-numeric text throws std::invalid_argument; validate or wrap in try/catch.
Continue this course
- Previous: Input & Output (cin & cout)
- Next: Type Casting (static_cast & more)