Skip to content

Ch10: Char Manipulation / Strings

TL;DR: Low-Level C-Strings: C-strings are null-terminated character arrays (char[]) requiring manual memory management and explicit boundary awareness to avoid overflows.

โšก Quick Reference

#include <iostream>
#include <string>
#include <string_view>
#include <cctype>
#include <cstring>

int main() {
    // std::string - Standard dynamic string class supporting manipulation.
    std::string str = "Hello C++";

    // std::string_view - Lightweight read-only non-owning window (C++17).
    std::string_view view = str;

    // std::isalnum, std::isalpha, std::isdigit, std::isspace - Char property checking.
    bool is_letter = std::isalpha('A');

    // std::toupper, std::tolower - Character casing transformations.
    char upper = std::toupper('a');

    char buffer[20] = "Hello";
    // std::strlen - Calculates C-string length.
    size_t len = std::strlen(buffer);

    // std::strcmp - Compares C-strings lexicographically.
    int cmp = std::strcmp(buffer, "Hello");

    // std::strcat - Concatenates C-strings.
    std::strcat(buffer, " World");

    // std::strcpy - Copies source C-string to destination buffer.
    char dest[20];
    std::strcpy(dest, buffer);

    return 0;
}

๐Ÿง  Core Concepts

  • Low-Level C-Strings: C-strings are null-terminated character arrays (char[]) requiring manual memory management and explicit boundary awareness to avoid overflows.
  • Standard String Helper Library: The <cctype> and <cstring> libraries provide essential classification (e.g., isalpha, isdigit) and buffer operations (e.g., strlen, strcpy).
  • High-Level std::string and std::string_view: C++ wraps raw buffers in std::string (managing dynamic resizing) and std::string_view (providing lightweight, non-owning, read-only views).

โš ๏ธ Pitfalls (Quick Scan)

Mistake Fix
Directly checking std::isalnum output against 1 Evaluate result in boolean contexts or cast using static_cast<bool>
Passing a signed char with a negative value to <cctype> functions Cast char variables to unsigned char before passing them
Applying sizeof to decayed character arrays (pointers) Use std::strlen to obtain actual character count excluding null terminator
Incrementing the search pointer inside a std::strchr iteration loop Use a separate result pointer to track occurrences, and keep the source string read-only
Calling std::strcat or std::strcpy with insufficient destination buffer size Ensure destination buffers are sized properly or use std::string instead
Passing const char[] arrays as destination buffers to C-string modifiers Only pass non-const buffers to functions that modify string content
Using operator += with integers on std::string to append numbers Convert numbers using std::to_string before appending
Omitting manual null termination after calling std::strncpy Always append a null terminator (\0) manually to the end of the destination array
Printing buffer returned by std::string::copy without null terminating Zero-initialize destination buffers or insert null terminators manually
Concatenating two raw string literals with operator + Ensure at least one operand is a std::string or use adjacent literals without operators
Comparing std::string to non-null-terminated character arrays Always ensure character arrays are null-terminated before comparing
Allowing std::string_view to outlive the viewed string data Never use a std::string_view after its source string goes out of scope
Calling std::strlen on a std::string_view data pointer after prefix/suffix modifications Use sv.length() or sv.size() instead of checking raw pointer length

๐Ÿ“– Full Details

Cause โ†’ Effect โ†’ Fix with timestamp (click to expand) * **Directly checking `std::isalnum` output against `1`** -> **Checks fail on some compilers because classification functions can return any non-zero value for true (05:54)** -> **Evaluate result in boolean contexts or cast using `static_cast` (05:54)** * **Passing a signed `char` with a negative value to `` functions** -> **Causes undefined behavior or memory access errors (06:47)** -> **Cast `char` variables to `unsigned char` before passing them (06:47)** * **Applying `sizeof` to decayed character arrays (pointers)** -> **Returns pointer size (8 bytes on 64-bit) instead of string length (15:53)** -> **Use `std::strlen` to obtain actual character count excluding null terminator (15:53)** * **Incrementing the search pointer inside a `std::strchr` iteration loop** -> **Scans character-by-character inefficiently, yielding incorrect iteration counts (23:24)** -> **Use a separate result pointer to track occurrences, and keep the source string read-only (23:24)** * **Calling `std::strcat` or `std::strcpy` with insufficient destination buffer size** -> **Buffer overflows, causing program memory corruption, crashes, or security vulnerabilities (29:56)** -> **Ensure destination buffers are sized properly or use `std::string` instead (29:56)** * **Passing `const char[]` arrays as destination buffers to C-string modifiers** -> **Compile-time error because destination arguments must be mutable (29:27)** -> **Only pass non-const buffers to functions that modify string content (29:27)** * **Using operator `+=` with integers on `std::string` to append numbers** -> **Appends the character represented by the ASCII code of the integer instead of string digits (42:14)** -> **Convert numbers using `std::to_string` before appending (42:14)** * **Omitting manual null termination after calling `std::strncpy`** -> **Outputs display garbage characters or crashes due to missing null terminator if source exceeds count limit (28:13)** -> **Always append a null terminator (`\0`) manually to the end of the destination array (28:13)** * **Printing buffer returned by `std::string::copy` without null terminating** -> **Outputs display garbage characters due to missing null terminator (48:50)** -> **Zero-initialize destination buffers or insert null terminators manually (48:50)** * **Concatenating two raw string literals with operator `+`** -> **Compile-time error because C++ cannot add two pointers (40:26)** -> **Ensure at least one operand is a `std::string` or use adjacent literals without operators (40:26)** * **Comparing `std::string` to non-null-terminated character arrays** -> **Causes the comparison to read out of bounds until a null byte is found in memory (50:41)** -> **Always ensure character arrays are null-terminated before comparing (50:41)** * **Allowing `std::string_view` to outlive the viewed string data** -> **Dangling reference that accesses invalid memory and causes undefined behavior (58:13)** -> **Never use a `std::string_view` after its source string goes out of scope (58:13)** * **Calling `std::strlen` on a `std::string_view` data pointer after prefix/suffix modifications** -> **Causes buffer over-reads because view boundaries are ignored (58:38)** -> **Use `sv.length()` or `sv.size()` instead of checking raw pointer length (58:38)**

๐Ÿ“Ž Repo Files

  • 15.2CharacterManipulation/main.cpp
  • 15.3CStringManipulation/main.cpp
  • 15.4CStringConcatenationAndCopy/main.cpp
  • 15.6DeclaringAndUsingStdString/main.cpp
  • 15.7ConcatenatingStdStrings/main.cpp
  • 15.8AccessingCharactersInStdString/main.cpp
  • 15.9StdStringSizeAndCapacity/main.cpp
  • 15.10ModifyingStdStrings/main.cpp
  • 15.11ComparingStdStrings/main.cpp
  • 15.12StdStringCompare/main.cpp
  • 15.13StdStringReplacingCopyingResizingSwapping/main.cpp
  • 15.14SearchingStdString/main.cpp
  • 15.15TransformingStdStringFromToNumbers/main.cpp
  • 15.16EscapeSequences/main.cpp
  • 15.17RawStringLiterals/main.cpp
  • 15.18CopiedStrings/main.cpp
  • 15.19StringView/main.cpp