Docs

README

Strings in C++

Table of Contents

  1. Introduction
  2. String Types in C++
  3. Creating Strings
  4. Accessing Characters
  5. String Operations
  6. Searching and Finding
  7. Modifying Strings
  8. String Comparison
  9. String Conversion
  10. String Views (C++17)
  11. Raw String Literals
  12. Regular Expressions
  13. Unicode and Wide Strings
  14. Performance Considerations
  15. Best Practices
  16. 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?

FeatureC-Style Stringsstd::string
Memory ManagementManualAutomatic
Size Trackingstrlen() needed.size() method
Bounds CheckingNone.at() available
Concatenationstrcat (unsafe)+ operator
Comparisonstrcmp==, <, > operators
Dynamic SizingComplexAutomatic
STL CompatibleLimitedFull 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

OperationTime 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

  1. std::string is the preferred way to work with strings in C++
  2. Automatic memory management - no manual allocation/deallocation
  3. Rich API - search, replace, compare, convert operations
  4. STL compatible - works with algorithms and iterators
  5. string_view (C++17) for non-owning references
  6. 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
README - C++ Tutorial | DeepML