C++ String Operations

C++ String Operations

C++’s for String Puzzels

A guide to working with strings in C++

Table of Contents


1. Getting Started

What is std::string?

graph LR
    A[std::string] --> B[Dynamic Array]
    A --> C[Automatic Memory]
    A --> D[Rich Operations]
    B --> E[Can grow/shrink]
    C --> F[No manual management]
    D --> G[100+ built-in methods]

std::string is a dynamic array that manages its own memory and provides many built-in methods for string operations.

Required headers:

#include <string>     // For std::string
#include <cctype>     // For isdigit, toupper, etc.
#include <algorithm>  // For sort, reverse, etc.

2. Creating Strings

MethodCodeResult
String literalstring s = "Hello";“Hello”
Constructorstring s("Hello");“Hello”
Empty stringstring s;””
Repeated charstring s(5, 'A');“AAAAA”
Copystring s2 = s1;Copy of s1
Partial copystring s(s1, 2, 3);3 chars from index 2

This table shows different ways to create strings in C++, from simple literals to more complex constructors that repeat characters or copy parts of other strings.

Example:

#include <iostream>
#include <string>

using namespace std;

int main() {
    string name = "Alice";
    string stars(3, '*');
    cout << stars << name << stars;  // ***Alice***
    return 0;
}

3. Accessing & Measuring

Access Methods Comparison

graph TD
    A[Access Character] --> B["s[i]"]
    A --> C["s.at(i)"]
    A --> D["s.front()"]
    A --> E["s.back()"]
    B --> F[Fast]
    B --> G[No bounds check]
    C --> H[Safe]
    C --> I[Throws exception]
    D --> J[First char]
    E --> K[Last char]

The diagram compares different ways to access characters in a string: s[i] is fast but unsafe, s.at(i) is safe but slower, while s.front() and s.back() access the first and last characters.

OperationCodeTimeSafe?
Index accesss[0]O(1)No
Safe accesss.at(0)O(1)Yes
First chars.front()O(1)No
Last chars.back()O(1)No
Lengths.length() or s.size()O(1)Yes
Is empty?s.empty()O(1)Yes

This table lists common string operations with their time complexity and safety: most are fast (O(1)) but some like s[0] don’t check bounds, while s.at(0) does.

Iteration Guide

#include <iostream>
#include <string>

using namespace std;

int main() {
    string s = "CODE";

    // Method 1: Classic loop
    for (int i = 0; i < s.length(); i++) 
        cout << s[i];

    // Method 2: Range-based (recommended)
    for (char c : s) 
        cout << c;

    // Method 3: Iterators
    for (auto it = s.begin(); it != s.end(); ++it)
        cout << *it;
    
    return 0;
}

4. String Manipulation

Substring Extraction Example

Original: "Programming"
          0123456789...
          
substr(0, 4)  →  "Prog"
substr(3, 4)  →  "gram"
substr(7)     →  "ming"

Code:

#include <iostream>
#include <string>

using namespace std;

int main() {
    string s = "Programming";
    cout << s.substr(0, 4);  // "Prog"
    cout << s.substr(3, 4);  // "gram"
    cout << s.substr(7);     // "ming"
    return 0;
}

Common Operations Table

OperationCodeExample
Appends += "text"“Hi” → “Hitext”
Inserts.insert(2, "XX")“Hi” → “HiXX”
Erases.erase(1, 2)“Hello” → “Hlo”
Replaces.replace(0, 2, "YY")“Hello” → “YYllo”
Clears.clear()→ “”
Reversereverse(s.begin(), s.end())“Hi” → “iH”

This table shows basic string manipulation operations: how to add text, insert at positions, remove parts, replace sections, clear the string, or reverse it.


5. Search & Compare

Find Operation Flow

graph LR
    A[s.find 'x'] --> B{Found?}
    B -->|Yes| C[Returns position]
    B -->|No| D[Returns string::npos]
    C --> E[Use position]
    D --> F[Handle not found]

This flowchart shows how the find function works: it searches for a substring and returns either the position where found or string::npos if not found.

Search Methods:

FunctionSearches fromExample
find()Beginning → Ends.find("cat")
rfind()End → Beginnings.rfind("cat")
find_first_of()First occurrence of any chars.find_first_of("aeiou")
find_last_of()Last occurrence of any chars.find_last_of("aeiou")

This table lists different search functions: find() searches forward, rfind() searches backward, while find_first_of() and find_last_of() find any character from a set.

Find pattern:

#include <iostream>
#include <string>

using namespace std;

int main() {
    string s = "Hello World";
    size_t pos = s.find("World");

    if (pos != string::npos) {
        cout << "Found at: " << pos;  // Found at: 6
    } else {
        cout << "Not found";
    }
    return 0;
}

Comparison Operators

OperatorMeaningExample
==Equal"abc" == "abc" → true
!=Not equal"abc" != "xyz" → true
<Less than"abc" < "xyz" → true
>Greater than"xyz" > "abc" → true
<=Less or equal"abc" <= "abc" → true
>=Greater or equal"abc" >= "abc" → true

This table shows how to compare strings using standard operators: strings are compared lexicographically (like dictionary order).


6. Conversions

String ↔ Number Flow

graph LR
    A[String] -->|stoi, stoll, stod| B[Number]
    B -->|to_string| A
    
    style A fill:#e1f5ff
    style B fill:#fff4e1

This diagram shows bidirectional conversion between strings and numbers: use stoi/stoll/stod to convert strings to numbers, and to_string to convert numbers back to strings.

Conversion Table:

From → ToFunctionExample
string → intstoi()stoi("42") → 42
string → long longstoll()stoll("1234567890") → 1234567890LL
string → doublestod()stod("3.14") → 3.14
int → stringto_string()to_string(42) → “42”
double → stringto_string()to_string(3.14) → “3.140000”

This table lists functions to convert between strings and different number types: stoi for integers, stoll for long long, stod for doubles, and to_string for all numbers to strings.

With Error Handling:

#include <iostream>
#include <string>

using namespace std;

int main() {
    string input = "123abc";
    try {
        int num = stoi(input);  // Converts "123", ignores "abc"
        cout << "Number: " << num;
    } catch (invalid_argument& e) {
        cout << "Invalid format!";
    }
    return 0;
}

7. Character Utilities

Character Classification

graph TD
    A[Character 'c'] --> B{Check Type}
    B --> C[isdigit c]
    B --> D[isalpha c]
    B --> E[isalnum c]
    B --> F[isspace c]
    C --> G[0-9?]
    D --> H[a-z, A-Z?]
    E --> I[Letter or digit?]
    F --> J[Space, tab, newline?]

This diagram shows character classification functions: isdigit checks for digits, isalpha for letters, isalnum for letters or digits, and isspace for whitespace characters.

Quick Reference:

FunctionReturns true if…Example
isdigit(c)Character is 0-9isdigit('5') → true
isalpha(c)Character is a-z or A-Zisalpha('A') → true
isalnum(c)Character is alphanumericisalnum('7') → true
isspace(c)Character is whitespaceisspace(' ') → true
isupper(c)Character is uppercaseisupper('A') → true
islower(c)Character is lowercaseislower('a') → true
tolower(c)Converts to lowercasetolower('A') → ‘a’
toupper(c)Converts to uppercasetoupper('a') → ‘A’

This table lists character utility functions for checking types (like isdigit for numbers) and converting case (tolower/toupper).

Example:

#include <iostream>
#include <string>
#include <cctype>

using namespace std;

int main() {
    // Count digits in a string
    string s = "abc123xyz456";
    int count = 0;
    for (char c : s) {
        if (isdigit(c)) count++;
    }
    cout << count;  // 6
    return 0;
}

8. Essential Patterns

Pattern 1: Frequency Counter

#include <iostream>
#include <string>

using namespace std;

int main() {
    // Count each letter's frequency
    string s = "hello";
    int freq[26] = {0};

    for (char c : s) {
        freq[c - 'a']++;
    }

    // freq['h'-'a'] = 1, freq['e'-'a'] = 1, etc.
    for (int i = 0; i < 26; i++) {
        if (freq[i] > 0) {
            cout << char('a' + i) << ": " << freq[i] << endl;
        }
    }
    return 0;
}

Mapping:

Character:  a   b   c   d   e   ...
Index:      0   1   2   3   4   ...
Formula:    c - 'a'

LeetCode Problems Using Frequency Counter

ProblemWhat it asks (simplified)Customization
383. Ransom NoteCheck if ransom note can be built from magazine lettersCount magazine frequencies, then decrement for ransom note. Check if all counts remain ≥ 0.
387. First Unique CharacterFind first non-repeating character in stringCount all frequencies, then scan string to find first char with count == 1.
242. Valid AnagramCheck if two strings are anagramsCount frequencies for both strings, check if all counts match (covered in Pattern 3).
438. Find All AnagramsFind all starting indices of anagrams in stringUse sliding window with frequency count. Maintain window size = p.length(), slide and compare frequency maps.

Pattern 2: Two-Pointer Technique

graph LR
    A["Start: left=0, right=n-1"] --> B["Compare s[left] vs s[right]"]
    B --> C{Equal?}
    C -->|Yes| D[Move both pointers inward]
    C -->|No| E[Not palindrome]
    D --> F{"left < right?"}
    F -->|Yes| B
    F -->|No| G[Is palindrome]

This flowchart shows the two-pointer technique for palindrome checking: start pointers at ends, compare characters, and move inward until they meet or find a mismatch.

Palindrome Check:

#include <iostream>
#include <string>

using namespace std;

bool isPalindrome(string s) {
    int left = 0, right = s.length() - 1;
    
    while (left < right) {
        if (s[left] != s[right]) return false;
        left++;
        right--;
    }
    return true;
}

int main() {
    string test = "racecar";
    if (isPalindrome(test)) {
        cout << test << " is a palindrome" << endl;
    } else {
        cout << test << " is not a palindrome" << endl;
    }
    return 0;
}

Example:

"racecar"
 ↑     ↑   Compare, both move inward
  ↑   ↑    Compare, both move inward
   ↑ ↑     Compare, both move inward
    ↑      Left >= Right, DONE

LeetCode Problems Using Two-Pointer Technique

ProblemWhat it asks (simplified)Customization
125. Valid PalindromeCheck if string reads same forwards and backwardsSkip non-alphanumeric chars, compare lowercase versions from both ends (covered in practice problems).
344. Reverse StringReverse characters in array in-placeSwap characters from both ends until pointers meet (covered in practice problems).
167. Two Sum IIFind two numbers that sum to target in sorted arrayStart pointers at ends, move based on sum comparison (target > sum: move left pointer right, target < sum: move right pointer left).
11. Container With Most WaterFind two lines that form container with maximum waterCalculate area at each step, move the shorter line inward to potentially find larger area.
26. Remove DuplicatesRemove duplicates from sorted array in-placeUse slow pointer to track unique position, fast pointer to scan array.

Pattern 3: Anagram Detection

flowchart TD
    A[Two Strings] --> B[Method 1: Sort Both]
    A --> C[Method 2: Count Frequencies]
    
    B --> D["sort both strings"]
    B --> E["compare s1 == s2"]
    D --> E
    E --> F["O(n log n) time"]
    
    C --> G["Create freq array"]
    C --> H["Count chars in s1"]
    C --> I["Decrement for s2"]
    H --> J["Check all counts = 0"]
    I --> J
    J --> K["O(n) time - FASTER!"]

This flowchart shows two approaches to check if two strings are anagrams: sorting both strings and comparing (slower) vs. counting character frequencies and checking for balance (faster).

Method 1: Sorting

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

bool isAnagram(string s1, string s2) {
    sort(s1.begin(), s1.end());
    sort(s2.begin(), s2.end());
    return s1 == s2;
}

int main() {
    string str1 = "listen";
    string str2 = "silent";
    if (isAnagram(str1, str2)) {
        cout << "Anagrams" << endl;
    } else {
        cout << "Not anagrams" << endl;
    }
    return 0;
}

Method 2: Frequency Array (faster)

#include <iostream>
#include <string>

using namespace std;

bool isAnagram(string s1, string s2) {
    if (s1.length() != s2.length()) return false;
    
    int freq[26] = {0};
    for (char c : s1) freq[c - 'a']++;
    for (char c : s2) freq[c - 'a']--;
    
    for (int x : freq) 
        if (x != 0) return false;
    
    return true;
}

int main() {
    string str1 = "listen";
    string str2 = "silent";
    if (isAnagram(str1, str2)) {
        cout << "Anagrams" << endl;
    } else {
        cout << "Not anagrams" << endl;
    }
    return 0;
}

LeetCode Problems Using Anagram Detection

ProblemDifficultyCustomization
242. Valid AnagramEasyUse frequency counting: count chars in s, decrement for t, check if all counts are zero.
49. Group AnagramsMediumSort each string to create keys, or use frequency count as key in map, group strings with same key.
438. Find All AnagramsMediumUse sliding window with frequency count. Maintain window size = p.length(), compare frequency maps at each position.
266. Palindrome PermutationEasyCount frequencies, ensure at most one character has odd count (for palindrome possibility).

9. Practice Problems

Problem 1: Reverse String

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

void reverseString(string& s) {
    int left = 0, right = s.length() - 1;
    while (left < right) {
        swap(s[left++], s[right--]);
    }
}

int main() {
    string s = "hello";
    reverseString(s);
    cout << s << endl;  // "olleh"
    
    // Or using algorithm:
    string s2 = "world";
    reverse(s2.begin(), s2.end());
    cout << s2 << endl;  // "dlrow"
    
    return 0;
}

This demonstrates a common string manipulation task used in text processing, cryptography, and data transformation. The two-pointer technique efficiently reverses strings in-place without extra space.


Problem 2: First Unique Character

#include <iostream>
#include <string>

using namespace std;

int firstUniqChar(string s) {
    int freq[26] = {0};
    
    for (char c : s) 
        freq[c - 'a']++;
    
    for (int i = 0; i < s.length(); i++) 
        if (freq[s[i] - 'a'] == 1) return i;
    
    return -1;
}

int main() {
    string s = "leetcode";
    int index = firstUniqChar(s);
    if (index != -1) {
        cout << "First unique character at index: " << index << endl;
    } else {
        cout << "No unique character found" << endl;
    }
    return 0;
}

This pattern is crucial for finding unique elements in strings, commonly used in data validation, compression algorithms, and text analysis. It uses frequency counting to identify the first non-repeating character.


Problem 3: Valid Palindrome (Ignore Non-Alphanumeric)

#include <iostream>
#include <string>
#include <cctype>

using namespace std;

bool isPalindrome(string s) {
    int left = 0, right = s.length() - 1;
    
    while (left < right) {
        while (left < right && !isalnum(s[left])) left++;
        while (left < right && !isalnum(s[right])) right--;
        
        if (tolower(s[left]) != tolower(s[right])) 
            return false;
        
        left++; right--;
    }
    return true;
}

int main() {
    string test = "A man, a plan, a canal: Panama";
    if (isPalindrome(test)) {
        cout << "Valid palindrome" << endl;
    } else {
        cout << "Not a palindrome" << endl;
    }
    return 0;
}

Palindrome checking is essential for string validation in algorithms, word games, and DNA sequence analysis. This implementation ignores case and non-alphanumeric characters for robust text comparison.


Problem 4: Reverse Words

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

string reverseWords(string s) {
    reverse(s.begin(), s.end());  // Reverse entire string
    
    int n = s.length(), start = 0;
    for (int end = 0; end <= n; end++) {
        if (end == n || s[end] == ' ') {
            reverse(s.begin() + start, s.begin() + end);
            start = end + 1;
        }
    }
    return s;
}

int main() {
    string s = "the sky is blue";
    string result = reverseWords(s);
    cout << result << endl;  // "blue is sky the"
    return 0;
}

Process:

Original:  "the sky is blue"
Step 1:    "eulb si yks eht"  (reverse all)
Step 2:    "blue is sky the"  (reverse each word)

Word reversal is a key technique in natural language processing, text formatting, and data preprocessing. The approach first reverses the entire string, then reverses each word individually.


Problem 5: Compress String (Run-Length Encoding)

#include <iostream>
#include <string>

using namespace std;

string compress(string s) {
    string result;
    int count = 1;
    
    for (int i = 1; i <= s.length(); i++) {
        if (i < s.length() && s[i] == s[i-1]) {
            count++;
        } else {
            result += s[i-1];
            result += to_string(count);
            count = 1;
        }
    }
    return result;
}

int main() {
    string s = "aaabbcccc";
    string compressed = compress(s);
    cout << compressed << endl;  // "a3b2c4"
    return 0;
}

Run-length encoding is a fundamental compression technique used in data storage, image processing, and network protocols. This implementation counts consecutive characters to create a compressed representation.


Problem 6: Remove Spaces

#include <iostream>
#include <string>

using namespace std;

string removeSpaces(string s) {
    string result;
    for (char c : s) {
        if (c != ' ') result += c;
    }
    return result;
}

// Or replace spaces:
string replaceSpaces(string s) {
    string result;
    for (char c : s) {
        result += (c == ' ') ? "%20" : string(1, c);
    }
    return result;
}

int main() {
    string s = "hello world";
    cout << removeSpaces(s) << endl;    // "helloworld"
    cout << replaceSpaces(s) << endl;   // "hello%20world"
    return 0;
}

Space removal is a basic text cleaning operation used in data parsing, search functionality, and user input validation. The example shows both complete removal and URL-style replacement.


Problem 7: Extracting URL Parts

Parse a URL to extract the protocol, domain, and path components.

#include <iostream>
#include <string>

using namespace std;

void parseURL(string url) {
    // Find protocol (before "://")
    size_t protocolEnd = url.find("://");
    if (protocolEnd == string::npos) {
        cout << "Invalid URL format" << endl;
        return;
    }
    
    string protocol = url.substr(0, protocolEnd);
    
    // Find domain (after "://" until first "/" or end)
    size_t domainStart = protocolEnd + 3;
    size_t pathStart = url.find("/", domainStart);
    
    string domain;
    string path;
    
    if (pathStart != string::npos) {
        domain = url.substr(domainStart, pathStart - domainStart);
        path = url.substr(pathStart);
    } else {
        domain = url.substr(domainStart);
        path = "/";
    }
    
    cout << "Protocol: " << protocol << endl;
    cout << "Domain: " << domain << endl;
    cout << "Path: " << path << endl;
}

int main() {
    string url = "https://www.example.com/path/to/resource";
    parseURL(url);
    // Output:
    // Protocol: https
    // Domain: www.example.com
    // Path: /path/to/resource
    
    return 0;
}

URL parsing is critical for web development, network programming, and data extraction. This technique breaks down URLs into components like protocol, domain, and path for further processing.


Problem 8: Transforming Dates in Strings

Convert date formats like “MM/DD/YYYY” to “YYYY-MM-DD” or vice versa.

#include <iostream>
#include <string>
#include <sstream>

using namespace std;

// Convert MM/DD/YYYY to YYYY-MM-DD
string convertDateFormat(string date) {
    // Find positions of slashes
    size_t firstSlash = date.find("/");
    size_t secondSlash = date.find("/", firstSlash + 1);
    
    if (firstSlash == string::npos || secondSlash == string::npos) {
        return "Invalid date format";
    }
    
    // Extract month, day, year
    string month = date.substr(0, firstSlash);
    string day = date.substr(firstSlash + 1, secondSlash - firstSlash - 1);
    string year = date.substr(secondSlash + 1);
    
    // Ensure 2-digit month and day
    if (month.length() == 1) month = "0" + month;
    if (day.length() == 1) day = "0" + day;
    
    // Return in YYYY-MM-DD format
    return year + "-" + month + "-" + day;
}

// Convert YYYY-MM-DD to MM/DD/YYYY
string convertDateFormatReverse(string date) {
    // Find positions of dashes
    size_t firstDash = date.find("-");
    size_t secondDash = date.find("-", firstDash + 1);
    
    if (firstDash == string::npos || secondDash == string::npos) {
        return "Invalid date format";
    }
    
    // Extract year, month, day
    string year = date.substr(0, firstDash);
    string month = date.substr(firstDash + 1, secondDash - firstDash - 1);
    string day = date.substr(secondDash + 1);
    
    // Remove leading zeros
    if (month[0] == '0') month = month.substr(1);
    if (day[0] == '0') day = day.substr(1);
    
    // Return in MM/DD/YYYY format
    return month + "/" + day + "/" + year;
}

int main() {
    string date1 = "12/25/2023";
    cout << convertDateFormat(date1) << endl;  // "2023-12-25"
    
    string date2 = "2023-07-04";
    cout << convertDateFormatReverse(date2) << endl;  // "7/4/2023"
    
    return 0;
}

Date format conversion is essential for data processing, internationalization, and database operations. The example demonstrates bidirectional conversion between common date formats.


Problem 9: Roman to Decimal

Convert Roman numerals to decimal integers (I=1, V=5, X=10, L=50, C=100, D=500, M=1000).

#include <iostream>
#include <string>
#include <unordered_map>

using namespace std;

int romanToInt(string s) {
    unordered_map<char, int> romanValues = {
        {'I', 1}, {'V', 5}, {'X', 10},
        {'L', 50}, {'C', 100}, {'D', 500}, {'M', 1000}
    };
    
    int total = 0;
    int prevValue = 0;
    
    // Iterate from right to left
    for (int i = s.length() - 1; i >= 0; i--) {
        int currentValue = romanValues[s[i]];
        
        // If current value is less than previous (right neighbor),
        // subtract it, otherwise add it
        if (currentValue < prevValue) {
            total -= currentValue;
        } else {
            total += currentValue;
        }
        
        prevValue = currentValue;
    }
    
    return total;
}

int main() {
    string roman1 = "III";      // 3
    string roman2 = "IV";       // 4
    string roman3 = "IX";       // 9
    string roman4 = "LVIII";    // 58
    string roman5 = "MCMXCIV";  // 1994
    
    cout << roman1 << " = " << romanToInt(roman1) << endl;
    cout << roman2 << " = " << romanToInt(roman2) << endl;
    cout << roman3 << " = " << romanToInt(roman3) << endl;
    cout << roman4 << " = " << romanToInt(roman4) << endl;
    cout << roman5 << " = " << romanToInt(roman5) << endl;
    
    return 0;
}

The Roman numeral conversion is used in historical data processing, educational software, and legacy system integration. The algorithm handles subtractive notation correctly.


Problem 10: Splitting String into Tokens

Split a string into tokens using multiple possible delimiters (spaces, commas, periods, etc.).

#include <iostream>
#include <string>
#include <vector>

using namespace std;

vector<string> splitTokens(const string& s, const string& delimiters) {
    vector<string> tokens;
    size_t start = 0;
    size_t end = 0;
    
    while ((end = s.find_first_of(delimiters, start)) != string::npos) {
        // Add token if there's content between delimiters
        if (end > start) {
            tokens.push_back(s.substr(start, end - start));
        }
        start = end + 1;  // Skip the delimiter
    }
    
    // Add the last token if there's remaining content
    if (start < s.length()) {
        tokens.push_back(s.substr(start));
    }
    
    return tokens;
}

// Alternative approach using stringstream (simpler for single delimiters)
#include <sstream>

vector<string> splitBySpace(const string& s) {
    vector<string> tokens;
    stringstream ss(s);
    string token;
    
    while (ss >> token) {
        tokens.push_back(token);
    }
    
    return tokens;
}

int main() {
    string text = "Hello, world! How are you? I'm fine.";
    string delimiters = " ,.!?";  // Space, comma, period, exclamation, question mark
    
    vector<string> tokens = splitTokens(text, delimiters);
    
    cout << "Original: " << text << endl;
    cout << "Tokens:" << endl;
    for (const string& token : tokens) {
        cout << "\"" << token << "\"" << endl;
    }
    
    // Output:
    // "Hello"
    // "world"
    // "How"
    // "are"
    // "you"
    // "I'm"
    // "fine"
    
    // Example with space-only splitting
    string sentence = "The quick brown fox jumps over the lazy dog";
    vector<string> words = splitBySpace(sentence);
    
    cout << "\nWords:" << endl;
    for (const string& word : words) {
        cout << word << " ";
    }
    cout << endl;
    
    return 0;
}

This covers a fundamental string processing technique that’s essential for parsing text data, CSV files, command-line arguments, and many other real-world applications. The example shows splitting a sentence with punctuation into clean word tokens.


10. Common Mistakes

Mistake 1: Off-by-One Errors

// Wrong
for (int i = 0; i <= s.length(); i++)  // Goes beyond!

// Correct
for (int i = 0; i < s.length(); i++)

Mistake 2: Modifying While Iterating

// Wrong
for (int i = 0; i < s.length(); i++) {
    if (s[i] == 'x') {
        s.erase(i, 1);  // Changes length!
    }
}

// Correct
string result;
for (char c : s) {
    if (c != 'x') result += c;
}
s = result;

Mistake 3: Input Buffer Issues

#include <iostream>
#include <string>

using namespace std;

int main() {
    int n;
    string line;

    // ❌ WRONG
    cout << "Enter a number: ";
    cin >> n;
    cout << "Enter a line: ";
    getline(cin, line);  // Gets empty line because cin leaves newline!
    cout << "Line: '" << line << "'" << endl;

    // ✅ CORRECT
    cout << "Enter another number: ";
    cin >> n;
    cin.ignore();        // Clear the newline character
    cout << "Enter another line: ";
    getline(cin, line);  // Now works!
    cout << "Line: '" << line << "'" << endl;

    return 0;
}

When to use what:

NeedUseExample
One wordcin >> sInput: “Hello World” → s = “Hello”
Full linegetline(cin, s)Input: “Hello World” → s = “Hello World”
Multiple words separatelyMultiple cin >>cin >> a >> b

This table shows different input methods: cin » for single words, getline for entire lines, and multiple cin » for separate words.


Reference

Time Complexity Guide

OperationComplexity
Access s[i]O(1)
length() / size()O(1)
find()O(n·m)
substr()O(m)
+ / appendO(n)
compare()O(n)
Sort stringO(n log n)

This table shows the time complexity of common string operations: most basic operations are fast (O(1)), while searching and sorting take longer.

Most Used Operations

// Measuring
s.length(), s.size(), s.empty()

// Accessing
s[i], s.at(i), s.front(), s.back()

// Modifying
s += "text", s.append("text"), s.insert(pos, "text")
s.erase(pos, len), s.clear()

// Searching
s.find("text"), s.rfind("text"), s.find(pos) != string::npos

// Substring
s.substr(pos, len)

// Conversion
stoi(s), stoll(s), stod(s), to_string(num)

// Character checks
isdigit(c), isalpha(c), isalnum(c), 
tolower(c), toupper(c)

// Algorithms (need <algorithm>)
reverse(s.begin(), s.end())
sort(s.begin(), s.end())

Final Tips

Do:

  • Use range-based for loops for readability
  • Check string::npos when using find
  • Use frequency arrays for character counting
  • Practice two-pointer technique
  • Handle edge cases (empty strings, single char)

Don’t:

  • Use <= in loop conditions with .length()
  • Modify strings while iterating
  • Forget cin.ignore() after cin >>
  • Ignore bounds checking for critical code