Strings and Vectors
Strings and Vectors
Work with dynamic text and lists using the most common standard library types.
Strings and Vectors
Work with dynamic text and lists using the most common standard library types.
std::stringstd::string text = "hello";
text += " world";
auto pos = text.find("world");
auto prefix = text.substr(0, 5);
find and substr cover a large amount of practical text work before you need more advanced parsing tools.
Strings grow dynamically and manage their own memory, which makes them the normal choice for text in modern C++.
std::vectorstd::vector<int> scores{10, 20, 30};
scores.push_back(40);
Vectors are the default dynamic sequence type because they are contiguous, efficient, and work well with algorithms and views.
for (const auto& score : scores) {
std::cout << score << '\n';
}
#include <iostream>
#include <vector>
int main() {
std::vector<int> values{4, 8, 15, 16, 23, 42};
int sum = 0;
for (int value : values) {
sum += value;
}
std::cout << "Average: " << sum / values.size() << '\n';
}
std::istringstream input{"Ada,Bjarne,Grace"};
std::string token;
while (std::getline(input, token, ',')) {
std::cout << token << '\n';
}
This is a simple way to break delimited text into pieces before you move to more specialized parsing tools.
std::vector over manual dynamic arraysconst&std::vector<std::string> names;
names.reserve(100);
Reserve capacity when you know approximate growth. It reduces reallocations and iterator invalidation.
for (std::string line; std::getline(std::cin, line); ) {
names.push_back(line);
}
If you expect many insertions, reserving up front can avoid repeated reallocations as the vector grows.
int first = values[0];
int checked = values.at(0);
Use [] when you already know the index is valid. Use .at() when you want bounds checking and are willing to pay for that safety.
std::string title = "Modern C++";
std::string_view view = title;
Use std::string_view for read-only access, but remember it does not own the string.
std::vector<int> numbers{1, 2, 3};
int* ptr = &numbers[0];
numbers.push_back(4);
After growth, pointers, references, and iterators into a vector may no longer be valid if reallocation happened. That is one of the most important vector rules to remember.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
int main() {
std::string line{"10 20 30 40"};
std::istringstream input{line};
std::vector<int> values;
values.reserve(4);
for (int value{}; input >> value; ) {
values.push_back(value);
}
std::cout << "count = " << values.size() << '\n';
}
This pattern shows how strings and vectors often work together: text input is parsed into typed values, then stored for later processing.
std::string path = "content/tutorials/getting-started.md";
if (path.ends_with(".md")) {
std::cout << "markdown file\n";
}
Modern string operations such as starts_with and ends_with make many small text checks much clearer.
Once vectors and strings feel comfortable, start replacing manual loops with algorithms such as std::ranges::sort, std::ranges::find, and std::ranges::transform.
#include <string>
#include <vector>
int main() {
std::vector<std::string> names{"Ada", "Bjarne"};
names.push_back("Grace");
return static_cast<int>(names.size());
}
Reserve space before growth and pass read-only text as `std::string_view`. That introduces both allocation control and borrowing in one small step.
#include <string_view>
#include <vector>
void add_name(std::vector<std::string>& names, std::string_view name) {
names.emplace_back(name);
}