Skip to content
Lesson 4 of 15

Step 1 of 5 · Reading · ~4 min

Learn

Strings

std::string

If you arrive from C, this lesson is the payoff for all that null-terminator suffering: std::string is a real string type — it knows its length, grows on demand, cleans up after itself, and compares with == like a civilized value. If C++ is your first systems language: enjoy; you're skipping a generation of segfaults.

A value type that acts like one

#include <string>

std::string name = "Ada";
std::string full = name + " Lovelace";     // + concatenates
full += "!";                               // append in place

full.size()          // 13 — it KNOWS its length (O(1), no strlen walk)
full.empty()         // false
full == "Ada Lovelace!"   // true — == compares CONTENTS

Every line of that would be a function call, a buffer-size prayer, or a bug in C. Assignment copies, comparison compares text, destruction frees the memory — std::string behaves like int with letters in it, and that "value semantics" discipline is the heart of well-written C++.

Indexing and characters

std::string s = "hello";
s[0]            // 'h' — a char, mutable: s[0] = 'H' works!
s.front()       // 'h'
s.back()        // 'o'
s.at(99)        // throws std::out_of_range — bounds-CHECKED access
s[99]           // undefined behavior — unchecked, C-style speed

The [] vs .at() pair is a C++ signature you'll see again on vector: the fast door that trusts you and the checked door that throws. Note strings are mutable here (unlike Go/Rust/Python) — in-place algorithms like reversal are natural.

The toolbox

s.substr(1, 3)              // "ell" — from index 1, length 3
s.find("lo")                // 3 — index, or std::string::npos if absent
s.find("xyz") == std::string::npos    // the "not found" test — memorize npos
std::to_string(42)          // "42"
std::stoi("123")            // 123 — string to int (throws on garbage)

for (char c : s) {          // range-for: each char in turn
    std::cout << c << ' ';  // prints h, space, e, space, ... — "h e l l o "
}

(Byte-level honesty for later: std::string is a sequence of chars with no Unicode opinions — size() counts bytes, and non-ASCII text has the same multi-byte realities as every language. For this course's ASCII graders, chars are characters.)

Reading strings: the trap that eats half your input

There are two doors in, and they are not interchangeable:

std::string s;

std::cin >> s;               // for input "hello world"  ->  s == "hello"
                             // stops dead at the first space; "world" is left behind

std::getline(std::cin, s);   // for input "hello world"  ->  s == "hello world"
                             // takes the whole line, spaces and all

>> is right when the input genuinely is one token — a number, a flag, a single word. Given two words it hands you a fragment without complaining, so the program looks perfect on every short example you tried. When the spec says "a line", read a line. (Follow-on gotcha, for when you meet it: >> leaves the newline in the buffer, so a later getline returns an empty line; std::cin.ignore() clears it.)

Your exercise: Reverse a Word

Despite the name, the input is a whole line — it may contain spaces, and one of the graded tests does. The starter already reads it with std::getline and already prints at the end; the statement in the middle is yours.

// s = "hello"     s[0]=='h'   s[4]=='o'   s.size()==5
//      01234      i is a POSITION (a number); s[i] is the CHARACTER there

std::reverse(s.begin(), s.end());      // in place: s becomes "olleh"
std::string r(s.rbegin(), s.rend());   // or: build a reversed copy, s untouched
for (int i = s.size() - 1; i >= 0; i--) std::cout << s[i];   // or: walk backwards

std::reverse comes from <algorithm> (already included) and it prints nothing — it rearranges s and hands you back silence. Reverse the line, then fall straight into return 0;, and your output is byte-identical to a starter you never touched: empty. That is why the mistake is so hard to see, and why the std::cout line is already written for you.

Two mistakes worth recognising on sight, because this exercise catches a lot of people with them:

std::reverse(s.begin(), s.end())     // <- no semicolon; the statement never ended
return 0;
// main.cpp:9:37: error: expected ‘;’ before ‘return’

for (int i = s.size() - 1; i >= 0; i--) std::cout << i;    // prints 43210, not olleh

Read that message the way the compiler meant it: it names return, but the caret it draws sits at the end of the line above, just past the closing ). Nothing is wrong with return — it is simply the first token reached after a statement you never finished. That is easy to lose when a call is spread over several lines. In the loop, i is a number and s[i] is a letter, so printing the counter gives you positions counting down. And size() returns an unsigned type: for (unsigned i = s.size()-1; i >= 0; ...) never ends, because unsigned is always ≥ 0 and stepping below zero wraps to 18446744073709551615. Nothing warns you — the grader reports errors, not warnings — so use int i, or take a one-line route.

Up nextOutput FormattingStrings

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…

std::string — C++ Fundamentals