Strings
C++ offers two ways to work with strings: C-style character arrays (char[]) inherited from C, and the modern std::string class from the standard library. Always prefer std::string in C++ — it manages its own memory, provides a rich interface, and eliminates an entire class of buffer-overflow bugs.
Creating Strings
#include <iostream>
#include <string>
using namespace std;
int main() {
// Construction
string s1 = "Hello"; // Copy initialisation
string s2("World"); // Direct initialisation
string s3{", C++!"}; // Uniform initialisation
string s4(5, '*'); // 5 asterisks: "*****"
string s5 = s1 + " " + s2; // Concatenation: "Hello World"
cout << s1 << "\n"; // Hello
cout << s4 << "\n"; // *****
cout << s5 << "\n"; // Hello World
// Empty string
string empty;
cout << empty.empty() << "\n"; // 1 (true)
cout << empty.length() << "\n"; // 0
return 0;
}Common String Operations
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "Hello, World!";
// Size and capacity
cout << s.size() << "\n"; // 13
cout << s.length() << "\n"; // 13 (same as size())
cout << s.empty() << "\n"; // 0 (false)
// Access individual characters
cout << s[0] << "\n"; // H (no bounds check)
cout << s.at(0) << "\n"; // H (throws if out of range)
cout << s.front() << "\n"; // H (first character)
cout << s.back() << "\n"; // ! (last character)
// Modify
s[0] = 'h';
cout << s << "\n"; // hello, World!
// Append
s += " How are you?";
s.append(" Fine!");
s.push_back('?'); // Add one character
// Insert and erase
s.insert(5, " dear"); // Insert at position 5
s.erase(5, 5); // Erase 5 chars starting at pos 5
return 0;
}Searching
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "The quick brown fox jumps over the lazy dog";
// find — returns index, or string::npos if not found
size_t pos = s.find("fox");
if (pos != string::npos) {
cout << "Found 'fox' at position: " << pos << "\n"; // 16
}
// Find from a position
size_t pos2 = s.find("the", 10); // Search from index 10
cout << "Second 'the' at: " << pos2 << "\n"; // 31
// rfind — search from the right
size_t last = s.rfind("o");
cout << "Last 'o' at: " << last << "\n"; // 41
// find_first_of — find any of a set of characters
size_t vowel = s.find_first_of("aeiou");
cout << "First vowel at: " << vowel << "\n"; // 2 ('e')
// find_last_of
size_t lastVowel = s.find_last_of("aeiou");
cout << "Last vowel at: " << lastVowel << "\n"; // 41 ('o')
// Check prefix and suffix (C++20)
cout << s.starts_with("The") << "\n"; // 1 (true)
cout << s.ends_with("dog") << "\n"; // 1 (true)
return 0;
}Substrings, Trimming, and Replacing
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
string s = " Hello, World! ";
// Substring
string sub = s.substr(2, 5); // Start at 2, length 5
cout << sub << "\n"; // Hello
// Replace
string text = "I love cats. Cats are great.";
size_t p = text.find("cats");
if (p != string::npos) {
text.replace(p, 4, "dogs"); // Replace 4 chars at p with "dogs"
}
cout << text << "\n"; // I love dogs. Cats are great.
// Trim leading whitespace
string trimmed = s;
trimmed.erase(0, trimmed.find_first_not_of(" \t\n\r"));
// Trim trailing whitespace
trimmed.erase(trimmed.find_last_not_of(" \t\n\r") + 1);
cout << "|" << trimmed << "|\n"; // |Hello, World!|
// Convert to uppercase
string upper = text;
transform(upper.begin(), upper.end(), upper.begin(), ::toupper);
cout << upper << "\n"; // I LOVE DOGS. CATS ARE GREAT.
return 0;
}String Comparison
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main() {
string a = "apple";
string b = "banana";
string c = "apple";
// Comparison operators — lexicographic
cout << (a == c) << "\n"; // 1 (true)
cout << (a < b) << "\n"; // 1 ("apple" < "banana" alphabetically)
cout << (b > a) << "\n"; // 1
// compare() — like strcmp
// Returns negative if a < b, 0 if equal, positive if a > b
cout << a.compare(c) << "\n"; // 0
cout << a.compare(b) << "\n"; // negative
// Case-insensitive comparison (using transform)
string s1 = "Hello";
string s2 = "hello";
string lower1 = s1, lower2 = s2;
transform(lower1.begin(), lower1.end(), lower1.begin(), ::tolower);
transform(lower2.begin(), lower2.end(), lower2.begin(), ::tolower);
cout << (lower1 == lower2) << "\n"; // 1 (true — case insensitive)
return 0;
}Type Conversions
#include <iostream>
#include <string>
using namespace std;
int main() {
// Number → string
int i = 42;
double d = 3.14;
string si = to_string(i); // "42"
string sd = to_string(d); // "3.140000"
cout << si << " " << sd << "\n";
// string → number
string numStr = "123";
int parsed = stoi(numStr); // string to int: 123
long parsed2= stol("9999999"); // string to long
double parsedD= stod("3.14"); // string to double
cout << parsed + 1 << "\n"; // 124
// Safe conversion with error handling
try {
int x = stoi("not a number");
} catch (const invalid_argument& e) {
cout << "Invalid: " << e.what() << "\n";
} catch (const out_of_range& e) {
cout << "Out of range: " << e.what() << "\n";
}
// String to C-string (for APIs that need char*)
const char* cstr = si.c_str(); // "42"
cout << cstr << "\n";
// C-string to std::string
const char* literal = "Hello from C";
string cpp_str(literal);
cout << cpp_str << "\n";
return 0;
}string_view (C++17)
string_view is a non-owning reference to a string — it avoids copying when you only need to read:
#include <iostream>
#include <string>
#include <string_view>
using namespace std;
// Using string_view — works with std::string, literals, and char arrays
// without copying
void printLength(string_view sv) {
cout << "'" << sv << "' has " << sv.size() << " characters\n";
}
bool startsWith(string_view str, string_view prefix) {
return str.substr(0, prefix.size()) == prefix;
}
int main() {
string s = "Hello, World!";
const char* cs = "Raw literal";
printLength(s); // 'Hello, World!' has 13 characters
printLength(cs); // 'Raw literal' has 11 characters
printLength("Direct"); // 'Direct' has 6 characters (no copy!)
cout << startsWith(s, "Hello") << "\n"; // 1
// string_view is cheap to copy and pass by value
string_view sv = s;
sv.remove_prefix(7); // Skip "Hello, "
cout << sv << "\n"; // World! (original string unchanged)
return 0;
}Note: Never return a string_view that refers to a local string — the view becomes a dangling reference when the string is destroyed.
Raw String Literals
#include <iostream>
using namespace std;
int main() {
// Normal string — escape sequences required
string path = "C:\\Users\\Alice\\Documents";
string html = "<div class=\"main\">\n <p>Hello</p>\n</div>";
// Raw string literal — no escape sequences needed
string rawPath = R"(C:\Users\Alice\Documents)";
string rawHtml = R"(
<div class="main">
<p>Hello</p>
</div>)";
string regex = R"(\d{4}-\d{2}-\d{2})"; // Regex without escaping
cout << rawPath << "\n"; // C:\Users\Alice\Documents
cout << regex << "\n"; // \d{4}-\d{2}-\d{2}
return 0;
}Practical Example: CSV Parser
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
using namespace std;
vector<string> splitCSV(const string& line, char delimiter = ',') {
vector<string> fields;
stringstream ss(line);
string field;
while (getline(ss, field, delimiter)) {
// Trim whitespace from each field
size_t start = field.find_first_not_of(" \t");
size_t end = field.find_last_not_of(" \t");
if (start != string::npos) {
fields.push_back(field.substr(start, end - start + 1));
} else {
fields.push_back("");
}
}
return fields;
}
int main() {
vector<string> csvData = {
"Alice, 30, Engineer, 85000",
"Bob, 25, Designer, 72000",
"Charlie, 35, Manager, 95000",
};
cout << left;
cout << setw(12) << "Name"
<< setw(6) << "Age"
<< setw(12) << "Role"
<< setw(10) << "Salary" << "\n";
cout << string(40, '-') << "\n";
for (const auto& row : csvData) {
vector<string> fields = splitCSV(row);
if (fields.size() >= 4) {
cout << setw(12) << fields[0]
<< setw(6) << fields[1]
<< setw(12) << fields[2]
<< setw(10) << fields[3] << "\n";
}
}
// Output:
// Name Age Role Salary
// ----------------------------------------
// Alice 30 Engineer 85000
// Bob 25 Designer 72000
// Charlie 35 Manager 95000
// stringstream for building strings
ostringstream oss;
oss << "Today: " << 2025 << "-" << setfill('0') << setw(2) << 3 << "-01";
string result = oss.str();
cout << result << "\n"; // Today: 2025-03-01
return 0;
}Summary
- Always prefer
std::stringover C-stylechar[]in C++ — it is safe, resizable, and richly featured - Key methods:
size(),empty(),find(),substr(),replace(),insert(),erase(),append() string::nposis the sentinel returned whenfind()does not find a match- Use
to_string()to convert numbers to strings; usestoi(),stod()etc. to parse numbers from strings string_view(C++17) provides a zero-copy read-only view — use for function parameters that just read a string- Raw string literals
R"(...)"eliminate escape sequences — great for file paths, HTML, and regex patterns stringstream/ostringstreambuild strings from mixed types likecoutdoes — useful for formatting
Next, we'll cover control flow — if/else, the ternary operator, and making decisions in your programs.