Chapter 4

Strings: Text That Doesn't Fight Back

Joining, measuring, slicing and searching text.

Chapter 3 gave you std::string and left it sitting there holding a name. Now let’s make it do some work.

Everything here needs #include <string> at the top, next to <iostream>.

Sticking text together

The + you know from numbers also joins text:

std::string first = "Ada";
std::string last = "Lovelace";

std::string full = first + " " + last;
std::cout << full << '\n';
Ada Lovelace

Note the " " in the middle. Joining doesn’t add a space for you — you get exactly what you asked for, so if you want a gap you have to say so.

There’s a shorter form for adding onto the end of something that already exists:

std::string greeting = "Hello";
greeting += ", world";

greeting now holds Hello, world. Read += as “stick this on the end”.

Exercise 1 · Add two literals on purpose

Compile std::string name = "Ada" + "Lovelace"; and read the message. You should recognise its shape instantly by now: file, line, column, and what it objected to.

Then fix it two ways — once by making one of them a std::string variable first, and once by putting a std::string you already have in the middle.

How long is it?

std::cout << full.size() << '\n';
12

Ada Lovelace is twelve characters, and the space is one of them. Spaces, punctuation and digits all count; size() counts characters, not words.

The dot is new. full.size() means “ask full for its size” — the variable comes first, then a dot, then the thing you want. A std::string carries a pile of these abilities around with it, and you’ll meet several today.

You’ll also see full.length(). It is the same function with a second name, kept for historical reasons. Use whichever reads better; this book uses size().

Positions start at zero

This is the idea that trips up everyone exactly once, so let’s be blunt about it. The first character is at position 0, not 1:

 A   d   a       L   o   v   e   l   a   c   e
 0   1   2   3   4   5   6   7   8   9  10  11

Square brackets get you one character:

std::cout << full[0] << '\n';
A

That A is a char — a single character, the thing single quotes are for. You met single quotes back in chapter 1 with '\n'. Double quotes mean text of any length; single quotes mean exactly one character.

Taking a piece out

substr — short for “substring” — cuts a piece out. Give it a starting position, and optionally how many characters you want:

std::cout << full.substr(0, 3) << '\n';
std::cout << full.substr(4) << '\n';
Ada
Lovelace

The first says “start at 0, give me 3 characters”. The second says “start at 4 and keep going to the end” — leave the second number off and that’s what you get.

Neither of these changes full. It still holds Ada Lovelace; substr hands you a new piece of text and leaves the original alone.

Looking for something

find tells you where something is:

std::cout << full.find(' ') << '\n';
3

The space in Ada Lovelace is at position 3, which lines up with the diagram above. find works with longer pieces too — full.find("Lov") gives you 4.

Exercise 2 · Find the fencepost

With full holding Ada Lovelace, print full[full.size() - 1]. You should get e.

Now try full.substr(4, 3) and predict the answer before you run it. Then full.find("ace"). Getting these right in your head first is the skill; running them is just the confirmation.

Check yourself

1. What does full.size() give for the string "Ada Lovelace"?

Not quite. That is the position of the last character, because counting starts at zero. The count itself is one more.

Yes. Eleven letters and one space. Spaces are characters like any other.

Not quite. size() counts characters, not words. Counting words is something you would have to do yourself.

2. What does full.find('z') return when there is no z in the string?

Not quite. Dangerous if it were true — 0 is a real position, the first character. A "not found" answer must be something that cannot be confused with a real one.

Not quite. That is what some other languages do. C++ uses an enormous positive number instead, for reasons that make more sense once you know the type involved.

Yes. Deliberately impossible as a position, so it can never be mistaken for a real answer.

3. Why does std::string name = "Ada" + "Lovelace"; fail to compile?

Not quite. + joins strings happily. The problem is what is on either side of it here.

Yes. Quoted text is the older kind C++ inherited from C, and it was never taught how to be added. Put one real std::string in the expression and it works.

Not quite. Missing spaces make ugly output, not compiler errors. This one never gets as far as running.

Project

An initials formatter

Roughly 40 minutes

Take a full name and print its initials. Start with the name hardcoded in a const std::string — chapter 5 is where the reader gets to type their own.

From Ada Lovelace, produce:

Ada Lovelace
First name: Ada
Last name:  Lovelace
Initials:   A.L.

The shape of it:

  1. find the space, and keep the position it gives you.
  2. substr from the start up to the space — that’s the first name.
  3. substr from just past the space to the end — that’s the last name.
  4. Take character 0 of each, and join them up with full stops.

Building the initials is where += earns its keep: start with an empty std::string and stick four things on the end of it, one at a time.

Stretch: make it work for a middle name — Ada Byron Lovelace giving A.B.L. — and notice how quickly this gets awkward with the tools you have. You are feeling the shape of a loop, which arrives in chapter 8.