Accessing Strings
Accessing Characters
In C++, you can access individual characters in a std::string using array subscript notation `[]` or the `at()` method. The subscript operator is fast but does not check bounds, while `at()` checks the index and throws an exception if it is out of range.
Both `operator[]` and `at()` return references for non-const strings, allowing modification; for const strings they return const references.
#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "Hello";
cout << "First char: " << str[0] << '\n';
cout << "Last char: " << str.at(str.length() - 1) << '\n';
return 0;
}
First char: H Last char: o
Modifying Characters
You can modify characters in a string using either array notation or the `at()` method. Since C++ strings are mutable, the changes are applied directly to the string (provided you have a non-const string).
#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "Hello";
str[0] = 'J'; // OK: non-const string
str.at(1) = 'o'; // Bounds-checked write
cout << str << '\n';
return 0;
}
Jollo
Bounds Checking
The `at()` method checks whether the index is within the valid range and throws `std::out_of_range` if it is not. By contrast, using array notation with an invalid index results in undefined behavior.
Time complexity for both `[]` and `at()` is constant; the difference is the bounds check and potential exception.
#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "Test";
// cout << str[10]; // ❌ Undefined behavior
try {
cout << str.at(10); // ❌ Throws std::out_of_range
} catch (const out_of_range& e) {
cout << "Caught: " << e.what() << '\n';
}
return 0;
}
Front and Back Access
C++11 added the `front()` and `back()` methods to access the first and last characters of a string. These methods make the intent clearer and avoid manual index calculations.
#include <iostream>
#include <string>
using namespace std;
int main() {
string str = "Hello";
cout << "First: " << str.front() << '\n';
cout << "Last: " << str.back() << '\n';
return 0;
}
First: H Last: o
Const-Correctness & References
`operator[]`, `at()`, `front()`, and `back()` return `char&` on non-const strings and `const char&` on const strings. To modify characters, you must have a non-const string (or a non-const reference to it).
Taking references or iterators to string elements is fine, but remember they can be invalidated by operations that reallocate the string (e.g., growth).
Pointers, Data, and Validity
`c_str()` returns a pointer to a null-terminated read-only character array. Do not write through it.
Since C++17, `data()` returns a writable pointer for non-const strings. You may write through it within the current size of the string, but any operation that causes reallocation invalidates the pointer. Never write past `size()`.
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
int main() {
string s = "abc";
char* p = s.data(); // writable since C++17
p[1] = 'X'; // OK: within bounds
cout << s << '\n'; // prints aXc
// WARNING: avoid storing 'p' across operations that may reallocate 's'
return 0;
}
aXc
Unicode / UTF-8 Caveat
std::string stores bytes, not Unicode code points. With UTF-8 text, a user-visible character may span multiple bytes. Indexing by `[]` or `at()` steps bytes, so it can land in the middle of a multi-byte sequence and corrupt your string.
If you need Unicode-aware character access, use a proper Unicode library or encode as `std::u16string` / `std::u32string` (and handle grapheme clusters with a library).