Docs
README
Strings in C++
Table of Contents
- •Introduction
- •String Types in C++
- •Creating Strings
- •Accessing Characters
- •String Operations
- •Searching and Finding
- •Modifying Strings
- •String Comparison
- •String Conversion
- •String Views (C++17)
- •Raw String Literals
- •Regular Expressions
- •Unicode and Wide Strings
- •Performance Considerations
- •Best Practices
- •Summary
Introduction
Strings are sequences of characters used to represent text. C++ offers multiple ways to work with strings, from C-style character arrays to the modern std::string class. Understanding strings is essential for text processing, user input handling, file operations, and data manipulation.
Why Use std::string?
| Feature | C-Style Strings | std::string |
|---|---|---|
| Memory Management | Manual | Automatic |
| Size Tracking | strlen() needed | .size() method |
| Bounds Checking | None | .at() available |
| Concatenation | strcat (unsafe) | + operator |
| Comparison | strcmp | ==, <, > operators |
| Dynamic Sizing | Complex | Automatic |
| STL Compatible | Limited | Full support |
String Types in C++
1. C-Style Strings (Character Arrays)
char str1[] = "Hello"; // Array of 6 chars (includes '\0')
char str2[10] = "World"; // Fixed size array
const char* str3 = "C-string"; // Pointer to string literal
2. std::string (Recommended)
#include <string>
std::string str = "Hello, World!";
3. std::wstring (Wide Characters)
#include <string>
std::wstring wstr = L"Wide string";
4. std::u16string and std::u32string (C++11)
std::u16string u16str = u"UTF-16 string";
std::u32string u32str = U"UTF-32 string";
5. std::string_view (C++17)
#include <string_view>
std::string_view sv = "Non-owning view";
Creating Strings
Method 1: Default Constructor
string s1; // Empty string ""
Method 2: From C-String
string s2 = "Hello";
string s3("World");
Method 3: Fill Constructor
string s4(5, 'a'); // "aaaaa"
string s5(10, '*'); // "**********"
Method 4: Copy Constructor
string original = "Copy me";
string copy(original); // "Copy me"
Method 5: Substring Constructor
string full = "Hello, World!";
string sub(full, 7, 5); // "World" (start at 7, length 5)
Method 6: Range Constructor
string full = "Hello, World!";
string part(full.begin(), full.begin() + 5); // "Hello"
Method 7: Initializer List (C++11)
string s6 = {'H', 'i', '!'}; // "Hi!"
Method 8: Move Constructor (C++11)
string temp = "Move me";
string moved = move(temp); // temp is now empty
Accessing Characters
Operator [] (No Bounds Checking)
string s = "Hello";
char first = s[0]; // 'H'
char last = s[4]; // 'o'
s[0] = 'J'; // s = "Jello"
// s[100] = 'X'; // UNDEFINED BEHAVIOR!
at() Method (Bounds Checking)
string s = "Hello";
char c = s.at(1); // 'e'
try {
char x = s.at(100); // Throws std::out_of_range
} catch (const out_of_range& e) {
cerr << "Error: " << e.what() << endl;
}
front() and back()
string s = "Hello";
char first = s.front(); // 'H'
char last = s.back(); // 'o'
s.front() = 'J'; // "Jello"
s.back() = 'y'; // "Jelly"
Iteration
string s = "Hello";
// Index-based
for (size_t i = 0; i < s.size(); i++) {
cout << s[i];
}
// Range-based (recommended)
for (char c : s) {
cout << c;
}
// Range-based with reference
for (char& c : s) {
c = toupper(c); // Modifies in place
}
// Iterator-based
for (auto it = s.begin(); it != s.end(); ++it) {
cout << *it;
}
String Operations
Concatenation
string a = "Hello";
string b = "World";
// Using + operator
string c = a + " " + b; // "Hello World"
// Using +=
a += " ";
a += b; // a = "Hello World"
// Using append()
string d = "Say: ";
d.append("Hello"); // "Say: Hello"
d.append(3, '!'); // "Say: Hello!!!"
d.append(b, 0, 3); // "Say: Hello!!!Wor"
Length and Size
string s = "Hello";
cout << s.size(); // 5
cout << s.length(); // 5 (same as size)
cout << s.capacity(); // >= 5
cout << s.max_size(); // Very large number
cout << s.empty(); // false
s.clear();
cout << s.empty(); // true
Substrings
string s = "Hello, World!";
string sub1 = s.substr(7); // "World!" (from index 7 to end)
string sub2 = s.substr(0, 5); // "Hello" (from 0, length 5)
string sub3 = s.substr(7, 5); // "World" (from 7, length 5)
C-String Conversion
string s = "Hello";
// Get C-string (null-terminated)
const char* cstr = s.c_str();
// Get pointer to data
const char* data = s.data();
// Copy to character array
char buffer[100];
s.copy(buffer, s.size());
buffer[s.size()] = '\0';
Searching and Finding
find() - First Occurrence
string s = "Hello, World!";
size_t pos = s.find("World"); // 7
pos = s.find('o'); // 4 (first 'o')
pos = s.find("o", 5); // 8 (start searching from index 5)
if (pos == string::npos) {
cout << "Not found";
}
rfind() - Last Occurrence
string s = "Hello, World!";
size_t pos = s.rfind('o'); // 8 (last 'o')
pos = s.rfind("l"); // 10 (last 'l')
find_first_of() / find_last_of()
string s = "Hello, World!";
// Find first occurrence of any character in set
size_t pos = s.find_first_of("aeiou"); // 1 ('e')
pos = s.find_last_of("aeiou"); // 8 ('o')
// Find first vowel
pos = s.find_first_of("aeiouAEIOU"); // 1
find_first_not_of() / find_last_not_of()
string s = " Hello ";
// Find first non-space
size_t start = s.find_first_not_of(" "); // 3
size_t end = s.find_last_not_of(" "); // 7
// Trim whitespace
string trimmed = s.substr(start, end - start + 1); // "Hello"
contains() (C++23)
// C++23
string s = "Hello, World!";
bool has = s.contains("World"); // true
starts_with() / ends_with() (C++20)
// C++20
string s = "Hello, World!";
bool starts = s.starts_with("Hello"); // true
bool ends = s.ends_with("!"); // true
Modifying Strings
Insert
string s = "Hello World";
s.insert(5, ","); // "Hello, World"
s.insert(0, "Say: "); // "Say: Hello, World"
s.insert(s.end(), '!'); // "Say: Hello, World!"
Erase
string s = "Hello, World!";
s.erase(5, 2); // "Hello World!" (remove ", ")
s.erase(s.end() - 1); // "Hello World" (remove '!')
s.erase(5); // "Hello" (erase from index 5 to end)
Replace
string s = "Hello, World!";
s.replace(7, 5, "C++"); // "Hello, C++!"
s.replace(0, 5, "Hi"); // "Hi, C++!"
// Replace all occurrences (manual loop)
string text = "cat dog cat bird cat";
while (text.find("cat") != string::npos) {
text.replace(text.find("cat"), 3, "kitty");
}
// "kitty dog kitty bird kitty"
Swap
string a = "Hello";
string b = "World";
a.swap(b); // a = "World", b = "Hello"
swap(a, b); // Swap back using std::swap
push_back() / pop_back()
string s = "Hello";
s.push_back('!'); // "Hello!"
s.push_back('!'); // "Hello!!"
s.pop_back(); // "Hello!"
s.pop_back(); // "Hello"
resize()
string s = "Hello";
s.resize(10); // "Hello " (padded with '\0')
s.resize(10, '-'); // "Hello-----" (padded with '-')
s.resize(3); // "Hel" (truncated)
Transform to Upper/Lower Case
#include <algorithm>
#include <cctype>
string s = "Hello World";
// To uppercase
transform(s.begin(), s.end(), s.begin(), ::toupper);
// "HELLO WORLD"
// To lowercase
transform(s.begin(), s.end(), s.begin(), ::tolower);
// "hello world"
String Comparison
Comparison Operators
string a = "apple";
string b = "banana";
bool eq = (a == b); // false
bool ne = (a != b); // true
bool lt = (a < b); // true (lexicographic)
bool gt = (a > b); // false
bool le = (a <= b); // true
bool ge = (a >= b); // false
compare() Method
string a = "apple";
string b = "banana";
int result = a.compare(b);
// result < 0: a comes before b
// result == 0: a equals b
// result > 0: a comes after b
// Partial comparison
result = a.compare(0, 3, "app"); // Compare first 3 chars with "app"
Case-Insensitive Comparison
#include <algorithm>
#include <cctype>
bool equalsIgnoreCase(const string& a, const string& b) {
if (a.size() != b.size()) return false;
return equal(a.begin(), a.end(), b.begin(),
[](char c1, char c2) {
return tolower(c1) == tolower(c2);
});
}
// Usage
bool same = equalsIgnoreCase("Hello", "HELLO"); // true
String Conversion
String to Number
#include <string>
// C++11 functions
int i = stoi("42"); // String to int
long l = stol("123456789"); // String to long
long long ll = stoll("123"); // String to long long
float f = stof("3.14"); // String to float
double d = stod("3.14159"); // String to double
// With base
int hex = stoi("FF", nullptr, 16); // 255
int bin = stoi("1010", nullptr, 2); // 10
// Error handling
try {
int x = stoi("not a number");
} catch (const invalid_argument& e) {
cerr << "Invalid: " << e.what() << endl;
} catch (const out_of_range& e) {
cerr << "Out of range: " << e.what() << endl;
}
Number to String
#include <string>
// C++11 to_string()
string s1 = to_string(42); // "42"
string s2 = to_string(3.14); // "3.140000"
string s3 = to_string(-100); // "-100"
Using stringstream
#include <sstream>
// Number to string with formatting
stringstream ss;
ss << fixed << setprecision(2) << 3.14159;
string formatted = ss.str(); // "3.14"
// String to number
stringstream ss2("42 3.14 Hello");
int num;
double dec;
string word;
ss2 >> num >> dec >> word;
// num = 42, dec = 3.14, word = "Hello"
Character Conversion
// Char to int
char c = '5';
int digit = c - '0'; // 5
// Int to char
int n = 7;
char ch = '0' + n; // '7'
// Character type checks
isalpha('A'); // true
isdigit('5'); // true
isalnum('a'); // true
isspace(' '); // true
isupper('A'); // true
islower('a'); // true
String Views (C++17)
std::string_view provides a non-owning view into a string, avoiding copies.
Basic Usage
#include <string_view>
void printLength(string_view sv) {
cout << sv << " has " << sv.size() << " characters" << endl;
}
// Works with different string types
printLength("C-string"); // No copy
string s = "std::string";
printLength(s); // No copy
printLength(string_view(s, 0, 3)); // "std"
string_view Methods
string_view sv = "Hello, World!";
// Similar to string methods
char c = sv[0]; // 'H'
char front = sv.front(); // 'H'
char back = sv.back(); // '!'
// Substring (creates new view, not copy)
string_view sub = sv.substr(7, 5); // "World"
// Remove prefix/suffix
sv.remove_prefix(7); // "World!"
sv.remove_suffix(1); // "World"
When to Use string_view
✅ Use string_view for:
- •Read-only string parameters
- •Avoiding unnecessary copies
- •Working with substrings
❌ Don't use string_view for:
- •Storing strings (it doesn't own the data!)
- •When you need to modify the string
- •When the underlying string might be destroyed
// DANGEROUS! String goes out of scope
string_view dangerous() {
string temp = "temporary";
return temp; // BAD! temp is destroyed
}
// SAFE: String persists
string_view safe(const string& s) {
return s; // OK if caller keeps s alive
}
Raw String Literals
Raw strings preserve formatting and don't require escape sequences.
Syntax
// Regular string (escapes needed)
string path = "C:\\Users\\name\\Documents";
string json = "{\"name\": \"John\"}";
// Raw string literal (R"(...)")
string path_raw = R"(C:\Users\name\Documents)";
string json_raw = R"({"name": "John"})";
// Multi-line raw string
string poem = R"(Roses are red,
Violets are blue,
C++ is awesome,
And so are you!)";
Custom Delimiter
// If your string contains )"
string tricky = R"delim(
This contains )" in the middle
)delim";
Regular Expressions
C++11 introduced <regex> for pattern matching.
Basic Usage
#include <regex>
// Check if string matches pattern
regex pattern(R"(\d{3}-\d{4})"); // Phone pattern: 123-4567
bool matches = regex_match("555-1234", pattern); // true
// Search for pattern
string text = "Call 555-1234 or 555-5678";
smatch match;
if (regex_search(text, match, pattern)) {
cout << "Found: " << match[0] << endl; // "555-1234"
}
Replace with Regex
string text = "Hello 123 World 456";
regex digits(R"(\d+)");
string result = regex_replace(text, digits, "###");
// "Hello ### World ###"
Find All Matches
string text = "Email: a@b.com and c@d.com";
regex email_pattern(R"(\w+@\w+\.\w+)");
sregex_iterator begin(text.begin(), text.end(), email_pattern);
sregex_iterator end;
for (auto it = begin; it != end; ++it) {
cout << it->str() << endl;
}
// Output:
// a@b.com
// c@d.com
Common Regex Patterns
// Digits only
regex digits(R"(\d+)");
// Word characters
regex word(R"(\w+)");
// Email (simple)
regex email(R"(\w+@\w+\.\w+)");
// Phone (US)
regex phone(R"(\d{3}[-.]?\d{3}[-.]?\d{4})");
// URL (simple)
regex url(R"(https?://[\w./]+)");
Unicode and Wide Strings
Wide Strings (wstring)
#include <string>
wstring ws = L"Wide string 日本語";
wcout << ws << endl;
// Wide character operations
wchar_t wc = L'日';
wstring greeting = L"Hello, 世界!";
UTF-8 Strings
// UTF-8 string (regular string can hold UTF-8)
string utf8 = u8"Hello, 世界!";
// C++20: char8_t type
// u8string s = u8"UTF-8 string";
UTF-16 and UTF-32
// UTF-16
u16string s16 = u"UTF-16 string";
// UTF-32
u32string s32 = U"UTF-32 string";
Converting Between Encodings
#include <codecvt> // Deprecated in C++17, but still usable
#include <locale>
// UTF-8 to UTF-16 (C++11)
wstring_convert<codecvt_utf8_utf16<char16_t>, char16_t> converter;
string utf8 = "Hello";
u16string utf16 = converter.from_bytes(utf8);
// Note: Consider using third-party libraries like ICU for robust Unicode handling
Performance Considerations
String Operations Complexity
| Operation | Time Complexity |
|---|---|
Access [] or at() | O(1) |
size() / length() | O(1) |
append() / += | O(m) amortized |
insert() | O(n + m) |
erase() | O(n) |
find() | O(n * m) |
compare() | O(min(n, m)) |
substr() | O(m) |
Optimization Tips
1. Reserve Capacity
string s;
s.reserve(1000); // Pre-allocate for large strings
for (int i = 0; i < 1000; i++) {
s += 'x'; // No reallocation
}
2. Use += Instead of +
// Inefficient: creates temporaries
string result = a + b + c + d;
// Better: avoids temporaries
string result;
result += a;
result += b;
result += c;
result += d;
// Or use append chain
string result;
result.append(a).append(b).append(c).append(d);
3. Use string_view for Parameters
// Creates copy of argument
void process(string s) { ... }
// No copy (C++17)
void process(string_view sv) { ... }
// Also no copy
void process(const string& s) { ... }
4. Move Semantics
string createString() {
string s = "Large string...";
return s; // Moved, not copied (RVO)
}
string result = createString(); // Efficient
5. Small String Optimization (SSO)
Most implementations store short strings (typically ≤15-22 chars) directly in the string object without heap allocation.
string short_str = "Hi"; // No heap allocation (SSO)
string long_str = "This is a very long string..."; // Heap allocated
Best Practices
1. Prefer std::string Over C-Strings
// Avoid
char buffer[100];
strcpy(buffer, "Hello"); // Unsafe
// Prefer
string s = "Hello"; // Safe, automatic
2. Use const Reference for Function Parameters
// Good: no copy
void process(const string& s) {
cout << s;
}
// C++17: even better for read-only
void process(string_view sv) {
cout << sv;
}
3. Check for Empty Strings Properly
string s;
// Good
if (s.empty()) { ... }
// Also good
if (s.size() == 0) { ... }
// Avoid (may create unnecessary comparison)
if (s == "") { ... }
4. Use Range-Based For Loops
string s = "Hello";
// Prefer
for (char c : s) {
cout << c;
}
// Over
for (size_t i = 0; i < s.size(); i++) {
cout << s[i];
}
5. Handle Encoding Carefully
// Be explicit about encoding
string utf8_text = u8"Unicode: 日本語";
// Use appropriate types
wstring wide_text = L"Wide: 日本語";
6. Use find() Return Value Properly
string s = "Hello";
size_t pos = s.find('x');
// Always check against npos
if (pos != string::npos) {
// Found
} else {
// Not found
}
Summary
Key Points
- •std::string is the preferred way to work with strings in C++
- •Automatic memory management - no manual allocation/deallocation
- •Rich API - search, replace, compare, convert operations
- •STL compatible - works with algorithms and iterators
- •string_view (C++17) for non-owning references
- •Raw string literals for complex strings without escapes
Quick Reference
#include <string>
using namespace std;
// Creation
string s; // Empty
string s = "text"; // From C-string
string s(5, 'x'); // "xxxxx"
string s(other); // Copy
// Access
s[i]; // No bounds check
s.at(i); // Bounds check
s.front(); // First char
s.back(); // Last char
// Properties
s.size(); // Length
s.length(); // Same as size
s.empty(); // Check if empty
s.capacity(); // Allocated space
// Modify
s += other; // Append
s.append(other); // Append
s.insert(pos, text); // Insert
s.erase(pos, len); // Erase
s.replace(pos, len, text); // Replace
s.clear(); // Empty the string
s.push_back(c); // Add char at end
s.pop_back(); // Remove last char
// Search
s.find(text); // First occurrence
s.rfind(text); // Last occurrence
s.find_first_of(chars); // First of any char
s.find_last_of(chars); // Last of any char
// Substring
s.substr(pos); // From pos to end
s.substr(pos, len); // From pos, length len
// Comparison
s == other; // Equal
s.compare(other); // <0, 0, or >0
// Conversion
stoi(s); // String to int
stod(s); // String to double
to_string(num); // Number to string
Practice Files
- •examples.cpp: Comprehensive code examples demonstrating all string operations
- •exercises.cpp: Practice problems from beginner to advanced
Compilation
g++ -std=c++17 -Wall -Wextra examples.cpp -o examples
g++ -std=c++17 -Wall -Wextra exercises.cpp -o exercises
./examples
./exercises