Menu

C++ Strings: std::string Basics, Methods, and Gotchas

How to use std::string in C++ - building, joining, searching, and slicing text safely, plus why you almost never want a raw char* for real work.

This page includes runnable editors - edit, run, and see output instantly.

std::string: Text That Manages Itself

On the previous page you saw how smart pointers let an object own a resource and clean it up automatically. std::string is that same idea applied to text: it owns a buffer of characters, grows it when you append, and frees it when the string goes out of scope. You never call new, never count bytes, and never worry about a missing null terminator.

To use it, include <string>. The class lives in the std namespace.

That + operator is doing real work - it allocates a new buffer big enough for both pieces and copies them in. With a raw char* - a plain pointer into a character buffer - you would be reaching for strcpy and strcat and hoping your buffer was large enough. std::string makes that whole class of mistakes disappear.

Building and Joining Strings

You can concatenate with +, but the workhorse for growing a string in place is +=. It appends to the existing buffer instead of producing a brand-new string each time, which matters inside loops.

A common surprise: + needs at least one operand to already be a std::string. Two string literals are just const char*, so "a" + "b" does not compile - there is no operator+ for two raw pointers. Make one of them a string first:

string s = "a" + "b";              // error: can't add two const char*
string s = string("a") + "b";      // fine - left side is a std::string
string s = "a"s + "b";             // fine in C++14+, the "s" literal suffix

Note that last form uses the s suffix from <string> (using namespace std::string_literals;), which turns a literal directly into a std::string.

Reaching Into a String

A std::string behaves like a container of char, so you can index it, loop over it, and ask for pieces of it.

substr(pos, len) returns a brand-new string copied from the original; it does not modify the source. Watch the bounds: word[10] on a 5-character string is undefined behavior - it won't throw, it just reads garbage. If you want a checked access that throws std::out_of_range, use word.at(10) instead of word[10].

Another classic trap: .size() returns an unsigned type (size_t). Writing a backward loop like for (size_t i = word.size() - 1; i >= 0; --i) never ends, because an unsigned i can never go below zero - it wraps around to a huge number. Loop with a signed index or restructure the condition when you need to walk a string in reverse.

Searching and Replacing

find locates a substring or character and returns the starting index. When the target isn't present, it returns the special constant std::string::npos - always compare against that rather than assuming find returns -1.

To change text in place, replace(pos, len, text) swaps a span for new content (which can be a different length), and insert/erase add or remove pieces:

Strings and Numbers

Text and numbers don't convert by themselves - "42" is three characters, not the integer 42. The standard library gives you conversion functions both ways. Use stoi, stod, and friends to parse text into numbers, and to_string to go the other direction.

Two gotchas here. First, stoi("abc") throws std::invalid_argument, so guard untrusted input with a try/catch block. Second, to_string(3.99) gives the full 3.990000 - if you need control over precision and formatting, that's a job for string streams, which is exactly where we head next.

try {
    int n = std::stoi(userInput);
} catch (const std::invalid_argument&) {
    std::cout << "That wasn't a number.\n";
}

Next: Input and Output

You've been printing strings with cout all along, but reading them back from the user has its own surprises - cin >> name stops at the first space, so a full line like "Ada Lovelace" needs std::getline instead. The next page covers C++ input and output properly: stream operators, reading whole lines, and mixing >> with getline without tripping over leftover newlines.

Frequently Asked Questions

What is the difference between std::string and char* in C++?

std::string is a class that owns and manages its own memory, grows as needed, and cleans up automatically. A char* is just a raw pointer to characters with a terminating '\0' - you manage the buffer, the length, and the lifetime yourself. Prefer std::string for almost everything; it removes whole categories of buffer-overflow and dangling-pointer bugs.

How do you get the length of a string in C++?

Call .size() or its alias .length() on a std::string: name.size() returns the number of characters as a size_t. Both return the same value; size() is the more common style because it matches every other STL container.

How do you convert a string to a number in C++?

Use std::stoi for int, std::stod for double, and similar (stol, stof). Example: int n = std::stoi("42");. These throw std::invalid_argument if the text isn't a number, so wrap them in a try/catch when the input isn't trusted.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED