03 Input-Output Streams & Strings

Overview: Data Abstraction Streams

C++ replaces C’s formatting placeholders (like %d, %s in printf) with type-safe streams. Strings are elevated from raw character arrays to full object abstractions.


1. Input/Output Streams: Mechanics & Buffering

C++ standard input/output is built on stream classes: <iostream>.

  • std::cout: Standard output stream (buffered, routes to standard output).
  • std::cin: Standard input stream (buffered, routes from standard input).
  • std::cerr: Standard error stream (unbuffered, routes to standard error for instant output).

Operator Overloading at Work:

The operators << (insertion) and >> (extraction) are overloaded bitwise shift operators:

std::cout << "Value: " << myInt;
// Resolves to: std::operator<<(std::operator<<(std::cout, "Value: "), myInt);

Each insertion returns a reference to the stream object (std::ostream&), allowing you to chain output calls.

Performance Tip: std::endl vs. '\n'

  • std::endl inserts a newline character and triggers std::flush on the output buffer, forcing a system write call.
  • Using std::endl inside loops can slow down execution due to repetitive flushing. Use '\n' instead, letting the system handle buffer flushes.

2. C++ Strings (std::string)

Unlike C-style character arrays, std::string is an instance of std::basic_string<char> that manages its own memory.

Memory Allocation & Small String Optimization (SSO)

  • Dynamic Allocation: By default, strings allocate buffer memory on the heap to allow resizing.
  • Small String Optimization (SSO): To avoid the overhead of heap allocations for short strings, modern compilers allocate a small buffer (typically 15 to 22 bytes) inside the string object itself on the stack.
Large String Object (Stack): [ Pointer to Heap ] ---> [ String characters on Heap ]
Small String Object (Stack): [ Embedded Buffer: "Hello\0" ] (No Heap allocation)

Mutability:

Unlike Java or Python strings, C++ strings are mutable. You can modify characters in place and append to them without creating a new object.


3. C-Style Strings vs. std::string

  • C-Style string: A raw character array terminated by a null character \0. Requires functions from <cstring> (e.g. strlen, strcmp).
  • Conversion: You can convert a std::string to a C-style string pointer using the .c_str() member function, which is useful when working with C-style legacy APIs.

💻 Conceptual Code Demonstration

#include <iostream>
#include <string>
#include <cstring> // For legacy C-string functions
 
int main() {
    // 1. Stream input/output
    std::cout << "Stream output: " << 42 << std::endl; // Forces flush
    std::cout << "Stream output with newline: " << 100 << '\n'; // Faster
    
    // 2. String mutability and methods
    std::string text = "Hello";
    text += " C++";            // Modifies string in place (concatenation)
    text.append(" World");     // Heap expansion if SSO limit exceeded
    
    std::cout << text << " | Length: " << text.length() << '\n';
    
    // 3. Interacting with C-style strings
    char legacyBuffer[20] = "Raw Array";
    std::printf("C-string length: %zu\n", std::strlen(legacyBuffer));
    
    // Converting std::string to const char*
    const char* cStr = text.c_str(); // Returns a null-terminated pointer
    std::printf("Legacy Print: %s\n", cStr);
    
    return 0;
}