C-Style String Representation
Choose the access style by intent. Use at() when a position may be invalid and a range check is wanted. Use iterators or the [ ] operator when speed matters and the program is already sure its positions are valid.
A Position That Does Not Exist
Suppose a program holds the three-character string cat and is asked for the character at position 3. What should happen? Before reading any further, decide what you think the answer is. The position is simply a number, and nothing about the number itself tells you whether a character lives there. This article is about that gap between a requested position and a real character, and about how the way you access a string decides what the program does when the request is invalid.
The source material states the core idea directly: positions in a string run over a fixed range, and a position outside that range does not refer to a character in the string. The rest of the article follows from that one sentence. Once you know the valid range, you can ask whether a given request falls inside it, and you can choose an access method that matches how much you need to be sure.
Valid Positions in a String
A string is an ordered collection of characters, and each character can be reached by its position. Positions are counted from zero, so a string with a given number of characters has valid positions running from the first character up to the last one. For a string of length n, the valid positions are 0 through n minus 1. Any position outside that run does not refer to a character in the string at all.
Read the diagram from left to right. Positions 0, 1, and 2 each hold one character of cat. Position 3 is marked as a request that lands outside the string. The count of characters tells you where the valid run ends, so a position one past the last character is never a character. Notice that the string's length, not the largest number you happen to know, determines the boundary.
Valid position: a position at or after the first character and at or before the last character of the string. Any other position is outside the string and does not refer to a character in it.
Tracing an Index Past the End
Now trace the state of the same string step by step. At each valid position the program can read a character, and that is the normal case. Then ask what a request for position 3 would find. Position 3 is not one of the three character positions, so the request does not land on a character. Whether the program notices this depends on which access method it uses, and that is the decision the rest of this article turns on.
The unchecked request in the diagram reaches past the last character. The source does not describe what memory or value that position would produce, and a learner should not assume one. What the source does establish is the intent: a position outside the valid run does not refer to a character, so using it as if it did is a logic error even when the program keeps running.
Deciding whether a requested position is valid
A string holds the word cat, which has 3 characters. A program requests the character at position 2, then the character at position 3. Which request is valid?
- 1Find the length
The string has 3 characters, so its length is 3.
- 2Find the last valid position
Positions start at 0, so the last valid position is length minus 1, which is 2.
- 3Check position 2
2 lies within 0 through 2, so it refers to the character t. The request is valid.
- 4Check position 3
3 is greater than 2, so it lies outside the valid run. It does not refer to a character in the string.
The request for position 2 is valid and returns t. The request for position 3 is invalid, and it is the case that needs a range check.
Choosing Between at() and [ ]
The source identifies at() as the access method to use when the program wants range checking. Range checking means verifying that a position is valid before the element is used. The source also gives the opposite advice for speed: when the goal is to optimize speed, iterators and the [ ] operator are the recommended choices rather than at(). Put simply, at() trades some speed for the safety of a range check, while iterators and [ ] are the faster options when the program is already sure its positions are valid.
The source does not describe the exact error behavior when at() detects an invalid position, so do not memorize a specific error message as part of this topic. The lesson to take from it is the intent. at() is the choice when an out-of-range request must be caught rather than silently attempted. The [ ] operator does not promise that check, so it belongs in code where the program has already confirmed that the position is valid.
a
a
tword.at(1)asks for the range-checked form of the access at a valid position.- word[1] reads the same character, because the position is valid.
- The last valid position for cat is 2, which is length minus 1.
The code above shows the two access styles on the same string so the difference in intent is visible. Both lines read the same character because the position is valid. The difference matters only when a position is not valid, which is the situation the earlier trace examined. A program that might ask for position 3 should use the checked form, while a loop whose bounds were already proven against the length can use the faster form.
Mistakes With Unchecked String Access
The mistakes below all share one root cause: the program assumes a position is valid without establishing that it is. Each one is easiest to avoid when you ask the validity question before the access happens.
Common mistake Looping up to the length instead of the last valid position
What it looks likefor (size_t i = 0; i <= word.size(); ++i) reads word[i] for every i in the loop, including the final pass.Why it failsThe valid positions run from 0 through length minus 1. The final pass asks for the position equal to the length, which lies outside the string.
Do this insteadUse a loop that stops before the length, such as i < word.size(), so every position read is one of the valid positions.
Common mistake Indexing at the length of the string
What it looks likeFor cat, word[3] is requested as if a fourth character existed.
Why it failsThe string has three characters, so position 3 does not refer to a character in it.
Do this insteadCompute the valid run from the length first, or use at() when the position comes from outside the program's control.
Common mistake Assuming the speed-oriented form also checks the range
What it looks likeA program uses word[i] with an index read from user input and never compares it to the length.
Why it failsThe source identifies at() as the range-checking tool. The [ ] operator is the speed choice and is recommended when validity is already established.
Do this insteadChoose at() when the position is not guaranteed valid, and reserve [ ] for positions the program has already verified.
Practice Tracing Valid and Invalid Requests
A string holds the word dog. List every valid position, then say which of the requests for positions 0, 2, 3, and 5 would fall outside the string. For each invalid request, state whether at() or [ ] is the better choice if the program cannot guarantee the position is valid.
Hints
- Count the characters in dog first, then the last valid position is that count minus 1.
- Positions outside the range 0 through 2 do not refer to a character in the string.
- The source ties at() to range checking and the [ ] operator to speed when validity is already established.
A loop reads every character of a string named name using name[i] for i from 0 up to and including the length. Explain which index causes the problem, what that index refers to, and how you would change the loop so it stays within the valid positions.
Hints
- Ask which index is the first one past the last valid character.
- Changing the upper bound from less-than-or-equal to less-than removes that index.
Key Takeaways for Safe Access
Choose the access style by intent. Use at() when a position may be invalid and a range check is wanted. Use iterators or the [ ] operator when speed matters and the program is already sure its positions are valid.
At a glance
- A string's valid positions run from 0 through its length minus 1, and any other position does not refer to a character in the string.
- Requesting a position outside that run is a logic error, and the program must decide what to do about it rather than assume the position is valid.
- at() is the access method the source associates with range checking, so it is the choice when an out-of-range request must be caught.
- Iterators and the [ ] operator are the source's recommended choices when the goal is speed, and they fit positions the program has already verified.
- Most unchecked-access mistakes come from looping to the length or assuming validity without checking, so ask the validity question before every access.