Searching in Strings
A string is an ordered sequence of characters, and each character has a definite position.
Why a String Is More Than One Value
A string is one of the most common kinds of data a program handles. Names, messages, file paths, and user input are all strings. When you write a string literal or read text from a user, you usually think of the text as a single value. That is a useful way to think about it at first, but working with strings effectively requires a more detailed picture of what that value is and how a program can reach into it. This article introduces that picture. It is the starting point for the rest of the chapter, because searching, regular expression notation, and iterators all depend on it.
What do you think happens?
If you treat the word cat as a row of slots, one character per slot, which slot holds the last character t?
Reveal answer
Slot 2
Positions are numbered from 0, so the three characters of cat sit at positions 0, 1, and 2. The last character t is at position 2, which is the string's length minus 1.
Tracing a String Slot by Slot
The section introduces a simple model. Picture a row of numbered slots with one character in each slot. The slot numbers are the positions. Reading a character means naming its position. Searching, pattern matching, and iteration all reduce to ways of visiting or comparing these slots in some order. Hold this picture in mind as you follow the diagram below, which traces the three characters of cat.
Notice what the diagram shows. Each slot holds exactly one character. The slots are arranged in a definite order, so the first character comes before the second and the second before the third. The position number is what lets a program say which character it means. Nothing about this model depends on the particular characters or on how long the string is. It applies to any string, whatever its length.
Order as the Defining Property
A string is an ordered sequence of characters, and each character has a definite position.
The word ordered is the important part. Order is what makes a string more than a bag of letters. If you had only the letters c, a, and t with no order attached, you could not say which one comes first. Because a string keeps its characters in order, every character has a place that can be referred to, and two strings made of the same letters can still differ when their letters are arranged differently.
Everything else in this chapter depends on the ordered-sequence model. Searching asks where text occurs within that order, regular expression notation describes patterns over that order, and iterators visit the positions in that order. Understanding the model first makes each of those topics easier to learn.
How Positions Are Numbered
Once a string is seen as a sequence, the next question is how its positions are counted. Many programming languages, including C++, number the characters of a string starting from 0 rather than 1. The first character is at position 0. A string with n characters therefore has positions running from 0 up to n minus 1, which can be written as $0 \leq i \leq n-1$ for any valid position i. The last character is always at length minus 1, not at the length itself.
This convention is worth fixing in your mind early. It affects nearly every operation that touches a string's contents, because every search result, every iteration, and every reference to a character is expressed as one of these numbers. If you count from 1 by habit while the string counts from 0, the numbers you compute will point at the wrong characters.
Locating the Last Character
Finding the position of the last character
A string holds the three characters c, a, t, in that order. What is the position of its last character?
- 1Count the characters
The string has 3 characters, so its length n is 3.
- 2Apply the numbering rule
Positions run from 0 up to n minus 1, which here is 3 minus 1.
- 3Compute the last position
The last position is 2, and that slot holds the character t.
- 4Check the first position
The first character c sits at position 0, so positions 0, 1, and 2 cover all three characters with no gap.
The last character t is at position 2, which equals the length minus 1.
Searching Visits Positions in Order
The section names searching as the first of three ways to work with string contents. Searching asks where a piece of text occurs. Its answer is a position: when the pattern is found, the search returns the position of the match, and when it is not found, the search returns a not-found result instead. The flowchart below illustrates the general idea of how a search can move through the ordered positions to reach that answer. It is a generic illustration of visiting slots in order, not a description of one particular library's internals.
Read the flowchart as a loop over the same numbered slots from the earlier diagram. Each pass checks one position, and the loop ends in one of two results. A found result is a position number, which you can then use to refer to the matched character. A not-found result is a different kind of answer, so a program must be prepared to handle it rather than assume a position was always returned.
Three Ways of Working with Contents
The section introduces three topics that build on the sequence model. Each one answers a different question about a string, so it helps to keep them apart. The table below compares what each operates on and what it gives back, based on the roles the section assigns to each.
| Topic | Question it answers | What it works with | What it gives back |
|---|---|---|---|
| Searching | Where does a piece of text occur? | Positions of the string in order | A position of the match, or a not-found result |
| Regular expression notation | Does the text follow a pattern? | Patterns that text may follow | A description of the pattern rather than a single location |
| Iterators | How can I visit each element in turn? | Elements taken one at a time in order | Access to each element as the traversal moves along |
The three ways of working with string contents covered in this section
All three rely on the fact that positions are ordered. That shared dependence is why the chapter presents them in sequence, and why this article covers the ordered model before any of them. The later articles will describe the details of each topic, so here the goal is only to recognise the three roles and the common foundation beneath them.
Tracing an Off-by-One Error
An off-by-one error happens when a position is one too large or one too small. Because the numbering starts at 0, the most common version is treating the length as if it were a valid position. The diagram below compares the intended last character of cat with the position an off-by-one mistake would point to.
The before side shows the correct reasoning: the last character is at length minus 1, which is position 2. The after side shows the error: position 3 is the length, and it does not name any character in cat. The fix is to subtract 1 from the length whenever you need the last position, and to remember that valid positions stop one short of the length.
Mistakes Beginners Make with Positions
Common mistake Counting positions from 1 instead of 0
What it looks likeTreating the first character of cat as position 1 and the last as position 3
Why it failsPositions are numbered from 0, so the first character is at position 0 and the last is at length minus 1.
Do this insteadLabel the first character position 0, then count upward, so cat has positions 0, 1, and 2.
Common mistake Using the length as the last position
What it looks likeAssuming the last character of cat is at position 3 because the string has 3 characters
Why it failsA string of length n has no character at position n. Its positions stop at n minus 1.
Do this insteadCompute the last position as length minus 1, which gives 2 for cat.
Common mistake Treating a string as a bag of letters
What it looks likeBelieving that cat and act hold the same information in the same places
Why it failsA string is an ordered sequence, so the order of its characters is part of its meaning and affects where each character sits.
Do this insteadReason about each character by its position, not merely by which letters appear.
Common mistake Assuming a search always returns a position, without checking for the not-found result
Checking Your Position Reasoning
Consider the string IJK TEC, which has 7 characters including the space. Without counting from a list, work out the position of the last character and the position of the first character. Then explain why the last position is not 7.
Hints
- Positions start at 0, so the first character is always at position 0.
- The last valid position is the length minus 1.
- A string of length 7 has positions 0 through 6.
Describe in one sentence what a search returns when the pattern is found and what it returns when the pattern is not found. Then name one reason a program must handle the not-found case explicitly.
Hints
- Recall the two outcomes shown in the search flowchart.
- Think about what a program would do next with a position number versus a not-found result.
Key Takeaways
- A string is an ordered sequence of characters, and each character has a definite position that a program can refer to.
- Positions are numbered from 0, so the first character is at position 0 and the last is at length minus 1.
- Searching, regular expression notation, and iterators are the three ways of working with string contents introduced in this section, and all three depend on the ordered model.
- Off-by-one errors usually come from treating the length as a valid position, so compute the last position as length minus 1.