Module 4.2

Strings in C++

Master C++ string handling with the powerful std::string class. Learn string operations, manipulation methods, input/output handling, and conversions for effective text processing.

40 min read
Intermediate
Hands-on Examples
What You'll Learn
  • std::string basics
  • String operations & comparison
  • String manipulation methods
  • Input/output with strings
  • String conversions
Contents
01

Introduction to Strings

C++ provides the std::string class in the <string> header for powerful and safe string manipulation. Unlike C-style character arrays, std::string manages memory automatically and provides many useful methods.

Concept

std::string

std::string is a class that represents a sequence of characters. It automatically manages memory, grows and shrinks as needed, and provides rich functionality for string manipulation.

Header: #include <string>

#include <iostream>
#include <string>  // Required for std::string
using namespace std;

int main() {
    // Create a string
    string greeting = "Hello, World!";
    
    // Print the string
    cout << greeting << endl;
    
    // Get length
    cout << "Length: " << greeting.length() << endl;  // 13
    
    // Strings are mutable
    greeting[0] = 'J';
    cout << greeting << endl;  // "Jello, World!"
    
    // Concatenation with +
    string name = "Alice";
    string message = "Hello, " + name + "!";
    cout << message << endl;  // "Hello, Alice!"
    
    return 0;
}

Why Use std::string?

Memory Safe

Automatic memory management, no buffer overflows

Dynamic Size

Grows and shrinks automatically as needed

Rich API

Many built-in methods for manipulation

02

String Declaration & Initialization

There are many ways to create and initialize strings in C++. The std::string class provides multiple constructors for flexibility.

#include <iostream>
#include <string>
using namespace std;

int main() {
    // Method 1: Default constructor (empty string)
    string s1;
    cout << "s1: \"" << s1 << "\" (empty)" << endl;
    
    // Method 2: Initialize with string literal
    string s2 = "Hello";
    string s3("World");
    string s4{"C++11 style"};  // Uniform initialization
    
    // Method 3: Copy constructor
    string s5 = s2;  // Copy of s2
    string s6(s3);   // Copy of s3
    
    // Method 4: Repeat character n times
    string s7(5, '*');  // "*****"
    string s8(10, 'A'); // "AAAAAAAAAA"
    cout << "s7: " << s7 << endl;
    
    // Method 5: Substring
    string s9 = "Hello, World!";
    string s10(s9, 0, 5);   // "Hello" (from index 0, length 5)
    string s11(s9, 7);      // "World!" (from index 7 to end)
    cout << "s10: " << s10 << endl;
    cout << "s11: " << s11 << endl;
    
    // Method 6: From C-string
    const char* cstr = "C-style string";
    string s12(cstr);
    
    // Method 7: From iterators
    string source = "ABCDEFGH";
    string s13(source.begin(), source.begin() + 4);  // "ABCD"
    
    return 0;
}

Practice Questions: Declaration

Task: Create a string containing 20 dashes ('-').

Show Solution
string dashes(20, '-');
cout << dashes << endl;  // "--------------------"

Task: From "Programming in C++", extract "C++" using substring constructor.

Show Solution
string full = "Programming in C++";
string extracted(full, 15, 3);  // Start at 15, length 3
cout << extracted << endl;  // "C++"
03

String Operations

C++ strings support intuitive operators for concatenation, comparison, and assignment—making string manipulation natural and readable.

Concatenation

#include <iostream>
#include <string>
using namespace std;

int main() {
    string first = "Hello";
    string second = "World";
    
    // Using + operator
    string combined = first + ", " + second + "!";
    cout << combined << endl;  // "Hello, World!"
    
    // Using += operator
    string message = "Count: ";
    message += "1, ";
    message += "2, ";
    message += "3";
    cout << message << endl;  // "Count: 1, 2, 3"
    
    // Concatenate with char
    string s = "ABC";
    s += 'D';  // "ABCD"
    s = s + 'E';  // "ABCDE"
    
    // append() method
    string str = "Hello";
    str.append(" World");      // "Hello World"
    str.append(3, '!');        // "Hello World!!!"
    str.append("12345", 0, 3); // "Hello World!!!123"
    cout << str << endl;
    
    return 0;
}

Comparison

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s1 = "apple";
    string s2 = "banana";
    string s3 = "apple";
    
    // Comparison operators (lexicographic)
    cout << boolalpha;  // Print true/false instead of 1/0
    
    cout << "s1 == s3: " << (s1 == s3) << endl;  // true
    cout << "s1 != s2: " << (s1 != s2) << endl;  // true
    cout << "s1 < s2: " << (s1 < s2) << endl;   // true ('a' < 'b')
    cout << "s2 > s1: " << (s2 > s1) << endl;   // true
    
    // compare() method: returns 0 if equal, <0 if less, >0 if greater
    int result = s1.compare(s2);
    if (result == 0) cout << "Equal" << endl;
    else if (result < 0) cout << "s1 comes before s2" << endl;
    else cout << "s1 comes after s2" << endl;
    
    // Compare substrings
    string str = "Hello, World!";
    // Compare "Hello" with "Hello"
    cout << str.compare(0, 5, "Hello") << endl;  // 0 (equal)
    
    return 0;
}

Assignment

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s1 = "Initial";
    
    // Direct assignment
    s1 = "New value";
    cout << s1 << endl;
    
    // Assign from another string
    string s2 = "Source";
    s1 = s2;
    cout << s1 << endl;  // "Source"
    
    // assign() method
    s1.assign("Assigned");
    s1.assign(5, 'X');       // "XXXXX"
    s1.assign("ABCDEF", 3);  // "ABC" (first 3 chars)
    
    // Swap strings
    string a = "First";
    string b = "Second";
    a.swap(b);  // or swap(a, b);
    cout << "a: " << a << ", b: " << b << endl;  // a: Second, b: First
    
    return 0;
}

Practice Questions: Operations

Task: Write code to check if "cat" comes before "dog" alphabetically.

Show Solution
string s1 = "cat";
string s2 = "dog";

if (s1 < s2) {
    cout << s1 << " comes before " << s2 << endl;
}
// Output: cat comes before dog
04

Accessing Characters

Individual characters in a string can be accessed using the subscript operator [] or the safer at() method which provides bounds checking.

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Hello, World!";
    
    // Using [] operator (no bounds check)
    cout << "First: " << str[0] << endl;   // 'H'
    cout << "Last: " << str[12] << endl;   // '!'
    
    // Using at() method (bounds checked - throws exception)
    cout << "Third: " << str.at(2) << endl;  // 'l'
    
    // Modify characters
    str[0] = 'J';
    str.at(7) = 'C';
    cout << str << endl;  // "Jello, Corld!"
    
    // front() and back()
    cout << "Front: " << str.front() << endl;  // 'J'
    cout << "Back: " << str.back() << endl;    // '!'
    
    // Exception handling with at()
    try {
        char c = str.at(100);  // Out of bounds!
    } catch (const out_of_range& e) {
        cout << "Error: " << e.what() << endl;
    }
    
    // Iterate through characters
    cout << "Characters: ";
    for (char c : str) {
        cout << c << " ";
    }
    cout << endl;
    
    return 0;
}

String Iteration Methods

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Hello";
    
    // Method 1: Index-based loop
    cout << "Index-based: ";
    for (size_t i = 0; i < str.length(); i++) {
        cout << str[i];
    }
    cout << endl;
    
    // Method 2: Range-based for (read-only)
    cout << "Range-based: ";
    for (char c : str) {
        cout << c;
    }
    cout << endl;
    
    // Method 3: Range-based for (modifiable)
    for (char& c : str) {
        c = toupper(c);  // Convert to uppercase
    }
    cout << "Uppercase: " << str << endl;  // "HELLO"
    
    // Method 4: Iterator-based
    cout << "Iterator: ";
    for (auto it = str.begin(); it != str.end(); ++it) {
        cout << *it;
    }
    cout << endl;
    
    // Method 5: Reverse iteration
    cout << "Reverse: ";
    for (auto it = str.rbegin(); it != str.rend(); ++it) {
        cout << *it;
    }
    cout << endl;  // "OLLEH"
    
    return 0;
}

Practice Questions: Accessing

Task: Count the number of vowels in "Programming is fun".

Show Solution
string str = "Programming is fun";
int vowels = 0;

for (char c : str) {
    c = tolower(c);
    if (c == 'a' || c == 'e' || c == 'i' || 
        c == 'o' || c == 'u') {
        vowels++;
    }
}
cout << "Vowels: " << vowels << endl;  // 5
05

String Methods

The std::string class provides many useful methods for querying string properties and modifying string contents.

Size and Capacity

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Hello, World!";
    
    // Length/Size (same thing)
    cout << "length(): " << str.length() << endl;  // 13
    cout << "size(): " << str.size() << endl;      // 13
    
    // Check if empty
    string empty;
    cout << "empty(): " << empty.empty() << endl;  // 1 (true)
    cout << "str empty: " << str.empty() << endl;  // 0 (false)
    
    // Capacity (allocated memory)
    cout << "capacity(): " << str.capacity() << endl;
    
    // Reserve memory
    str.reserve(100);  // Reserve space for 100 chars
    cout << "After reserve: " << str.capacity() << endl;
    
    // Resize string
    str.resize(5);  // Keep first 5 chars: "Hello"
    cout << "After resize(5): \"" << str << "\"" << endl;
    
    str.resize(10, '!');  // Extend with '!'
    cout << "After resize(10, '!'): \"" << str << "\"" << endl;  // "Hello!!!!!"
    
    // Clear string
    str.clear();
    cout << "After clear: empty = " << str.empty() << endl;  // true
    
    return 0;
}

Substring Extraction

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Hello, World!";
    
    // substr(pos, len) - extract substring
    string sub1 = str.substr(0, 5);    // "Hello"
    string sub2 = str.substr(7);       // "World!" (to end)
    string sub3 = str.substr(7, 5);    // "World"
    
    cout << "sub1: " << sub1 << endl;
    cout << "sub2: " << sub2 << endl;
    cout << "sub3: " << sub3 << endl;
    
    // Extract middle portion
    string text = "The quick brown fox";
    string middle = text.substr(4, 5);  // "quick"
    cout << "Middle: " << middle << endl;
    
    return 0;
}

Insert, Erase, Replace

#include <iostream>
#include <string>
using namespace std;

int main() {
    // INSERT
    string str = "Hello World";
    str.insert(5, ",");         // Insert at position 5
    cout << "Insert: " << str << endl;  // "Hello, World"
    
    str.insert(7, "Beautiful ");
    cout << "Insert: " << str << endl;  // "Hello, Beautiful World"
    
    // ERASE
    str = "Hello, World!";
    str.erase(5, 2);           // Erase 2 chars starting at position 5
    cout << "Erase: " << str << endl;   // "HelloWorld!"
    
    str.erase(5);              // Erase from position 5 to end
    cout << "Erase: " << str << endl;   // "Hello"
    
    // REPLACE
    str = "Hello, World!";
    str.replace(7, 5, "C++");  // Replace 5 chars at position 7
    cout << "Replace: " << str << endl; // "Hello, C++!"
    
    str = "I like cats and cats are cute";
    str.replace(str.find("cats"), 4, "dogs");
    cout << "Replace: " << str << endl; // First "cats" -> "dogs"
    
    return 0;
}

Practice Questions: Methods

Task: Extract the file extension from "document.txt".

Show Solution
string filename = "document.txt";
size_t dotPos = filename.rfind('.');  // Find last dot

if (dotPos != string::npos) {
    string ext = filename.substr(dotPos + 1);
    cout << "Extension: " << ext << endl;  // "txt"
}
06

Searching & Replacing

C++ strings provide powerful search functions to find characters, substrings, and patterns within strings.

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Hello, World! Hello, C++!";
    
    // find() - find first occurrence
    size_t pos = str.find("Hello");
    cout << "First 'Hello' at: " << pos << endl;  // 0
    
    // find() with starting position
    pos = str.find("Hello", 1);  // Search from index 1
    cout << "Second 'Hello' at: " << pos << endl;  // 14
    
    // find() single character
    pos = str.find('!');
    cout << "First '!' at: " << pos << endl;  // 12
    
    // rfind() - find last occurrence (reverse find)
    pos = str.rfind("Hello");
    cout << "Last 'Hello' at: " << pos << endl;  // 14
    
    // Check if substring exists
    if (str.find("World") != string::npos) {
        cout << "'World' found!" << endl;
    }
    
    // string::npos means "not found"
    pos = str.find("Python");
    if (pos == string::npos) {
        cout << "'Python' not found" << endl;
    }
    
    return 0;
}

More Search Functions

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Hello, World!";
    
    // find_first_of() - find first of any character in set
    size_t pos = str.find_first_of("aeiou");  // First vowel
    cout << "First vowel at: " << pos << endl;  // 1 ('e')
    
    // find_last_of() - find last of any character in set
    pos = str.find_last_of("aeiou");
    cout << "Last vowel at: " << pos << endl;  // 8 ('o' in World)
    
    // find_first_not_of() - find first char NOT in set
    string digits = "12345abc678";
    pos = digits.find_first_not_of("0123456789");
    cout << "First non-digit at: " << pos << endl;  // 5 ('a')
    
    // find_last_not_of()
    string padded = "   Hello   ";
    pos = padded.find_last_not_of(' ');
    cout << "Last non-space at: " << pos << endl;  // 7 ('o')
    
    return 0;
}

Replace All Occurrences

#include <iostream>
#include <string>
using namespace std;

// Function to replace all occurrences
string replaceAll(string str, const string& from, const string& to) {
    size_t pos = 0;
    while ((pos = str.find(from, pos)) != string::npos) {
        str.replace(pos, from.length(), to);
        pos += to.length();  // Move past replacement
    }
    return str;
}

int main() {
    string text = "I like cats. cats are cute. I have two cats.";
    
    // Replace all "cats" with "dogs"
    text = replaceAll(text, "cats", "dogs");
    cout << text << endl;
    // "I like dogs. dogs are cute. I have two dogs."
    
    return 0;
}

Practice Questions: Searching

Task: Count how many times "the" appears in "the cat and the dog and the bird".

Show Solution
string str = "the cat and the dog and the bird";
string target = "the";
int count = 0;
size_t pos = 0;

while ((pos = str.find(target, pos)) != string::npos) {
    count++;
    pos += target.length();
}
cout << "Count: " << count << endl;  // 3
07

String Input/Output

C++ provides multiple ways to read and write strings. Understanding the difference between cin, getline(), and other methods is essential for proper input handling.

#include <iostream>
#include <string>
using namespace std;

int main() {
    string name;
    
    // cin >> stops at whitespace
    cout << "Enter your first name: ";
    cin >> name;
    cout << "Hello, " << name << "!" << endl;
    // Input: "John Doe" -> name = "John" (stops at space)
    
    // Clear the input buffer
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    
    // getline() reads entire line
    string fullName;
    cout << "Enter your full name: ";
    getline(cin, fullName);
    cout << "Hello, " << fullName << "!" << endl;
    // Input: "John Doe" -> fullName = "John Doe"
    
    // getline() with custom delimiter
    string data;
    cout << "Enter comma-separated data: ";
    getline(cin, data, ',');  // Read until comma
    cout << "First part: " << data << endl;
    
    return 0;
}

Common Input Problems

#include <iostream>
#include <string>
#include <limits>
using namespace std;

int main() {
    // PROBLEM: Mixing cin >> and getline()
    int age;
    string name;
    
    cout << "Enter age: ";
    cin >> age;
    // After cin >>, newline '\n' remains in buffer!
    
    // WRONG: This will read empty string
    // getline(cin, name);  // Reads the leftover '\n'
    
    // SOLUTION: Clear the buffer first
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    
    cout << "Enter name: ";
    getline(cin, name);
    cout << "Age: " << age << ", Name: " << name << endl;
    
    // Alternative: Use getline() for everything
    string ageStr;
    cout << "Enter age again: ";
    getline(cin, ageStr);
    int age2 = stoi(ageStr);  // Convert string to int
    
    return 0;
}

String Stream (stringstream)

#include <iostream>
#include <string>
#include <sstream>  // For stringstream
using namespace std;

int main() {
    // Build string from multiple values
    stringstream ss;
    ss << "Name: " << "Alice" << ", Age: " << 25;
    string result = ss.str();
    cout << result << endl;  // "Name: Alice, Age: 25"
    
    // Parse string into values
    string data = "100 3.14 hello";
    stringstream parser(data);
    
    int num;
    double pi;
    string word;
    parser >> num >> pi >> word;
    
    cout << "num: " << num << endl;    // 100
    cout << "pi: " << pi << endl;      // 3.14
    cout << "word: " << word << endl;  // hello
    
    // Split string by delimiter
    string csv = "apple,banana,cherry";
    stringstream csvStream(csv);
    string token;
    
    cout << "Tokens: ";
    while (getline(csvStream, token, ',')) {
        cout << "[" << token << "] ";
    }
    cout << endl;  // [apple] [banana] [cherry]
    
    return 0;
}

Practice Questions: Input/Output

Task: Split "Hello World Program" into separate words using stringstream.

Show Solution
#include <sstream>
#include <vector>

string sentence = "Hello World Program";
stringstream ss(sentence);
string word;
vector words;

while (ss >> word) {
    words.push_back(word);
}

for (const string& w : words) {
    cout << w << endl;
}
// Output:
// Hello
// World
// Program
08

String Conversions

Converting between strings and numbers is a common task. C++11 introduced convenient functions like stoi(), stod(), and to_string() for easy conversions.

#include <iostream>
#include <string>
using namespace std;

int main() {
    // STRING TO NUMBER (C++11)
    
    // stoi() - string to int
    string numStr = "42";
    int num = stoi(numStr);
    cout << "stoi: " << num << endl;  // 42
    
    // stol() - string to long
    string longStr = "1234567890";
    long longNum = stol(longStr);
    
    // stoll() - string to long long
    string llStr = "9999999999999";
    long long llNum = stoll(llStr);
    
    // stof() - string to float
    string floatStr = "3.14";
    float f = stof(floatStr);
    
    // stod() - string to double
    string doubleStr = "3.14159265359";
    double d = stod(doubleStr);
    cout << "stod: " << d << endl;
    
    // With different bases
    string hexStr = "FF";
    int hexNum = stoi(hexStr, nullptr, 16);  // Base 16
    cout << "Hex FF = " << hexNum << endl;  // 255
    
    string binStr = "1010";
    int binNum = stoi(binStr, nullptr, 2);   // Base 2
    cout << "Binary 1010 = " << binNum << endl;  // 10
    
    return 0;
}

Number to String

#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>
using namespace std;

int main() {
    // to_string() - number to string (C++11)
    int num = 42;
    string s1 = to_string(num);
    cout << "to_string(42): \"" << s1 << "\"" << endl;
    
    double pi = 3.14159;
    string s2 = to_string(pi);
    cout << "to_string(pi): \"" << s2 << "\"" << endl;
    // Note: to_string gives many decimal places
    
    // For formatted output, use stringstream
    stringstream ss;
    ss << fixed << setprecision(2) << pi;
    string s3 = ss.str();
    cout << "Formatted: \"" << s3 << "\"" << endl;  // "3.14"
    
    // Build complex strings
    int age = 25;
    string name = "Alice";
    string msg = name + " is " + to_string(age) + " years old.";
    cout << msg << endl;
    
    return 0;
}

Error Handling in Conversions

#include <iostream>
#include <string>
using namespace std;

int main() {
    // Handle invalid conversions
    try {
        string invalid = "not a number";
        int num = stoi(invalid);  // Throws exception!
    } catch (const invalid_argument& e) {
        cout << "Invalid argument: " << e.what() << endl;
    } catch (const out_of_range& e) {
        cout << "Out of range: " << e.what() << endl;
    }
    
    // Partial conversion with position
    string mixed = "123abc456";
    size_t pos;
    int num = stoi(mixed, &pos);  // Converts "123"
    cout << "Converted: " << num << endl;           // 123
    cout << "Stopped at position: " << pos << endl;  // 3
    cout << "Remaining: " << mixed.substr(pos) << endl;  // "abc456"
    
    return 0;
}

C-String Conversion

#include <iostream>
#include <string>
#include <cstring>
using namespace std;

int main() {
    // std::string to C-string
    string str = "Hello, World!";
    
    // c_str() returns const char* (null-terminated)
    const char* cstr = str.c_str();
    cout << "c_str(): " << cstr << endl;
    
    // data() also returns const char* (C++11: same as c_str)
    const char* data = str.data();
    
    // Copy to char array
    char buffer[50];
    strcpy(buffer, str.c_str());
    
    // C-string to std::string
    const char* source = "C-style string";
    string converted = source;  // Implicit conversion
    string converted2(source);  // Explicit constructor
    
    cout << "Converted: " << converted << endl;
    
    return 0;
}

Practice Questions: Conversions

Task: Given "10 20 30", parse and calculate the sum.

Show Solution
#include <sstream>

string nums = "10 20 30";
stringstream ss(nums);
string token;
int sum = 0;

while (ss >> token) {
    sum += stoi(token);
}
cout << "Sum: " << sum << endl;  // 60
09

C-String vs std::string

Understanding the differences between C-style strings and std::string helps you choose the right tool and work with legacy code.

Feature C-String (char[]) std::string
Memory Fixed size, manual management Dynamic, automatic management
Size strlen() or manual count .length() or .size()
Concatenation strcat() + or +=
Comparison strcmp() ==, <, >
Copy strcpy() =
Buffer Overflow Risk Safe
Null Terminator Required Handled internally
#include <iostream>
#include <string>
#include <cstring>
using namespace std;

int main() {
    // C-STRING WAY
    char cstr1[20] = "Hello";
    char cstr2[20] = "World";
    char cstr3[40];
    
    // Concatenation (unsafe if buffer too small!)
    strcpy(cstr3, cstr1);
    strcat(cstr3, " ");
    strcat(cstr3, cstr2);
    cout << "C-string: " << cstr3 << endl;
    
    // Comparison
    if (strcmp(cstr1, cstr2) < 0) {
        cout << cstr1 << " comes before " << cstr2 << endl;
    }
    
    // Length
    cout << "Length: " << strlen(cstr1) << endl;
    
    // STD::STRING WAY (PREFERRED)
    string str1 = "Hello";
    string str2 = "World";
    
    // Concatenation (safe, automatic resize)
    string str3 = str1 + " " + str2;
    cout << "std::string: " << str3 << endl;
    
    // Comparison (natural operators)
    if (str1 < str2) {
        cout << str1 << " comes before " << str2 << endl;
    }
    
    // Length
    cout << "Length: " << str1.length() << endl;
    
    return 0;
}
Recommendation: Always prefer std::string in modern C++ for safety and convenience. Use C-strings only when interfacing with C libraries or APIs that require char*.

Key Takeaways

Use std::string

Prefer std::string over C-strings for safety

Easy Operations

Use + for concatenation, == for comparison

Search Methods

find(), rfind(), find_first_of()

Input with getline()

Use getline() for full line input

Conversions

stoi(), stod(), to_string()

Use .at() for Safety

Bounds checking prevents crashes

Knowledge Check

Quick Quiz

Test what you have learned about C++ strings

1 Which header is required for std::string?
2 What does cin >> str do with input "Hello World"?
3 What is the result of "Hello".length()?
4 What does str.find("xyz") return if "xyz" is not found?
5 Which function converts string "42" to integer?
6 What's the difference between str[5] and str.at(5)?
Answer all questions to check your score