Skip to main content

Strings

Strings in C++

In C++, a string is a data structure that represents a sequence of characters used to store and manipulate text. The C++ Standard Library provides the std::string class, which offers a convenient and powerful way to handle strings. It automatically manages memory and provides a wide range of functions for operations like concatenation, comparison, and searching. This article provides a comprehensive look at strings in C++, covering their evolution from basic character arrays to the powerful and flexible std::string class used in modern C++ programming.

Types Of Strings In C++

  1. C-Style Strings: These are character arrays used to represent strings. This method comes from C programming and requires manual handling of the string's termination using a null character (\0).
  2. C++ String Class: By using the std::string class, available through the <string> header, you gain access to many powerful string-handling functions that make working with strings easier and safer.

C-Style Character Strings

C-style Character strings have their origins in the C programming language and are fully supported in C++. A C-style string is essentially a sequence of characters stored in a one-dimensional array, terminated with a special null character ('\0'). The null character is crucial because it tells the program where the string ends during operations like printing or manipulation.

When you create a C-style string, the array must have enough space to store all the characters plus the terminating null character. For example, if you have a word with 7 letters, the array size should be at least 8 to accommodate the '\0'.

Declaring and Initializing C-Style Strings

You can create a C-style string in two ways:

Method 1: Manual Initialization

char platform[9] = {'L', 'e', 'a', 'r', 'n', 'Y', 'a', 'r', 'd', '\0'};

Here, each character is inserted individually, and the null terminator is explicitly added at the end. The array size is 10 because "LearnYard" has 9 characters plus 1 for '\0'.

Method 2: Using String Literals

char platform[] = "LearnYard";

When you use double quotes, the compiler automatically appends the '\0' character at the end. So there’s no need to manually include it.

Memory Layout of a C-Style String

When stored in memory, the string "LearnYard" would be arranged as:

| 'L' | 'e' | 'a' | 'r' | 'n' | 'Y' | 'a' | 'r' | 'd' | '\0' |

Each character occupies one memory cell, and the null terminator marks the end of the string.

Example Program

Here’s a simple C++ program to demonstrate a C-style string using the word "LearnYard":

cpp

#include <iostream>
using namespace std;

int main() {
    char platform[] = "LearnYard";

    cout << "Welcome to: ";
    cout << platform << endl;

    return 0;
}

Output

Welcome to: LearnYard

C Style String Functions

C++ provides a variety of functions specifically designed to work with null-terminated strings (C-style strings). These functions are declared in the <cstring> header file (or <string.h> in C).

These built-in functions allow you to perform common operations such as copying, concatenating, comparing, and searching within strings.

Commonly Used C-Style String Functions

Sr. No.FunctionDescription
1strcpy(s1, s2)Copies the content of string s2 into string s1.
2strcat(s1, s2)Appends string s2 at the end of string s1.
3strlen(s1)Returns the length (number of characters) in string s1, excluding the null terminator.
4strcmp(s1, s2)Compares two strings; returns 0 if they are equal, a negative value if s1 is less than s2, and a positive value if s1 is greater than s2.
5strchr(s1, ch)Searches for the first occurrence of character ch in string s1 and returns a pointer to it.
6strstr(s1, s2)Finds the first occurrence of the string s2 within string s1 and returns a pointer to it.

Example Program

The following C++ program demonstrates the use of a few of these string functions:

cpp

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

int main() {
    char platform1[15] = "Learn";
    char platform2[15] = "Yard";
    char result[15];
    int length;

    // Copying platform1 into result
    strcpy(result, platform1);
    cout << "After strcpy(result, platform1): " << result << endl;

    // Concatenating platform1 and platform2
    strcat(platform1, platform2);
    cout << "After strcat(platform1, platform2): " << platform1 << endl;

    // Finding length of concatenated string
    length = strlen(platform1);
    cout << "Length of platform1 after concatenation: " << length << endl;

    return 0;
}

Output

After strcpy(result, platform1): Learn
After strcat(platform1, platform2): LearnYard
Length of platform1 after concatenation: 9

Limitations and Challenges of C-Style Strings

Although C-style strings are simple and lightweight, they come with several challenges that make them difficult to work with, especially in larger programs:

  • No Bounds Checking:
    Functions like strcpy() and strcat() do not check whether the destination array has enough space. This can easily lead to buffer overflow errors, which can cause programs to crash or even create security vulnerabilities.
  • Manual Memory Management:
    Developers are responsible for allocating enough memory for strings and ensuring there is room for the null terminator ('\0'). Forgetting this can cause unpredictable behavior.
  • Performance Issues:
    Some operations, like finding the length of a string with strlen(), require scanning the entire string until the null character is found. This takes O(n) time, where n is the length of the string.
  • Difficult String Modifications:
    Changing or expanding a C-style string often needs careful handling of array sizes and manual index management, which can make programs harder to write and debug.

The String Class in C++

In C++, working with text becomes much easier and safer with the help of the string class.The std::string class, defined in the <string> header, provides a modern and flexible way to handle sequences of characters. It solves many problems that occur with traditional C-style strings, such as memory management and buffer overflows.

Unlike character arrays, std::string comes with many built-in functions that make string operations simple and error-free.

Example of Using the String Class

Let’s look at a basic example:

cpp

#include <iostream>
#include <string> // Include the string library

using namespace std;

int main() {
    string str1 = "Hello";
    string str2 = "World";
    string str3;
    int len;

    // Copying str1 into str3
    str3 = str1;
    cout << "str3: " << str3 << endl;

    // Concatenating str1 and str2
    str3 = str1 + str2;
    cout << "str1 + str2: " << str3 << endl;

    // Finding the length of str3
    len = str3.size();
    cout << "Length of str3: " << len << endl;

    return 0;
}

Output:

str3: Hello
str1 + str2: HelloWorld
Length of str3: 10

These limitations and the error-prone nature of C-style string manipulation

How to Create Strings in C++

There are two common ways to create strings in C++:

1. Using Character Arrays (C-style strings)

You can still create a string using a character array. Here’s how:

Syntax:

char variable_name[length];
  • length is the number of characters you want to store (including space for the null character).

Example:

cpp

#include <iostream>
using namespace std;

int main() {
    char s[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
    cout << s << endl;
    return 0;
}

Output:

hello
Note: You need to manually add the null character \0 at the end.

2. Using the std::string Class

This is the modern and recommended way of working with strings in C++.

Syntax:

string variable_name = [optional_value];

You can assign a value at the time of declaring the string or later.

Example:

cpp

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

int main() {
    string s = "a merry tale";
    cout << s << endl;
    return 0;
}

Output:

cpp

a merry tale

Traversing (Iterating) Over a String

You can go through each character in a string in two main ways:

1. Using Loops with Indexing

You can use a for loop to access each character by its position (index).

Example:

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

int main() {
    string s = "Hey, I am at LearnYard.";

    for (int i = 0; i < s.length(); i++) {
        cout << s[i] << " ";
    }
    cout << endl;

    return 0;
}

Output:

H e y ,   I   a m   a t   L e a r n Y a r d . 

2. Using Range-Based For Loop

This method automatically goes through each character without worrying about indexes.

Example:

cpp

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

int main() {
    string s = "Hey, I am at LearnYard.";

    for (char c : s) {
        cout << c << " ";
    }
    cout << endl;

    return 0;
}

Output:

H e y ,   I   a m   a t   L e a r n Y a r d . 

Accessing and Modifying String Characters

You can not only access but also modify the characters of a string.

Example:

cpp

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

int main() {
    string s = "Hey, I am at LearnYard.";

    cout << "Original string: " << s << endl;

    // Change every character to 'A'
    for (int i = 0; i < s.length(); i++) {
        s[i] = 'A';
    }
    cout << "After changing to 'A': " << s << endl;

    // Change every character to 'B' using a reference
    for (char &c : s) {
        c = 'B';
    }
    cout << "After changing to 'B': " << s << endl;

    return 0;
}

Output:

Original string: Hey, I am at LearnYard.
After changing to 'A': AAAAAAAAAAAAAAAAAAAAAAA
After changing to 'B': BBBBBBBBBBBBBBBBBBBBBBB

String Functions in C++

In C++, a string is an object of the <string> class. The string class provides many useful functions to perform operations easily.

Here are some important functions of the string class:

FunctionDescription
length()Returns the total number of characters in the string.
size()Same as length(), gives the size of the string.
resize()Changes the size (length) of the string.
swap()Swaps the content of two strings.
find()Searches for a substring and returns its first position if found.
push_back()Adds a character at the end of the string.
pop_back()Removes the last character of the string.
clear()Erases all characters of the string, making it empty.
replace()Replaces part of the string with another substring.
substr()Returns a part (substring) of the string.
compare()Compares two strings and returns an integer based on comparison.
erase()Deletes a portion of the string.

Length of a String

The length of a string means the number of characters present, including spaces.

Syntax:

int len = string_name.length();

Example:
cpp

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

int main() {
string name = "LearnYard Academy";
cout << name.length();
return 0;
}

Output:

18

String Concatenation (Joining Two Strings)

You can combine two strings together in two ways:

Using Addition Operator (+)

Example:

cpp

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

int main() {
string a = "Learn";
string b = "Yard";
cout << a + b;
return 0;
}

Output:

LearnYard

Using append() Function

Syntax:

string1.append(string2);

Example:

cpp

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

int main() {
string first = "LearnYard";
string second = " Platform";
first.append(second);
cout << first;
return 0;
}

Output:

LearnYard Platform

Difference Between Integer Addition and String Addition

When two integers are added, they are numerically summed. But when two strings are added, they get combined.

Example (Integer Addition):

cpp

#include <iostream>
using namespace std;

int main() {
int x = 30;
int y = 20;
cout << x + y;
return 0;
}

Output:

50

Example (String Addition):

cpp

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

int main() {
string x = "30";
string y = "20";
cout << x + y;
return 0;
}

Output:

3020

Taking String Input

There are three common ways to input strings:

1. Using cin

This method reads a single word (stops at space).

Example:

cpp

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

int main() {
string institute;
cin >> institute;
cout << institute;
return 0;
}

Input:

LearnYard

Output:

LearnYard

2. Using getline()

This method reads a complete line including spaces.

Syntax:

getline(cin, string_name);

Example:

cpp

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

int main() {
string institute;
getline(cin, institute);
cout << institute;
return 0;
}

Input:

LearnYard Academy of Coding

Output:

LearnYard Academy of Coding

3. Using stringstream

If you want to split a sentence into words, you can use stringstream.

Example:

cpp

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

int main() {
string sentence = "LearnYard makes coding easy";
stringstream ss(sentence);
string word;
while (ss >> word) {
cout << word << " ";
}
return 0;
}

Output:

LearnYard makes coding easy

C++11 and Beyond Features

cpp

// String to number
int i = std::stoi("42");                 // String to int
long l = std::stol("42");                // String to long
float f = std::stof("3.14");             // String to float
double d = std::stod("3.14");            // String to double

// Number to string
std::string str1 = std::to_string(42);   // Int to string
std::string str2 = std::to_string(3.14); // Double to string

// Raw string literals
std::string raw = R"(Line 1\nLine 2)";   // Contains actual \n, not newline

// Move semantics
std::string source = "Hello, World!";
std::string dest = std::move(source);    // Move content from source to dest

String Class Implementation Details

The std::string class is typically implemented as a template specialization of basic_string<char>, which handles character sequences with dynamic memory allocation. While implementations may vary across different standard library vendors, most follow similar principles:

cpp

template<class CharT, class Traits = std::char_traits<CharT>, 
         class Allocator = std::allocator<CharT>>
class basic_string {
    // Implementation details...
};

typedef basic_string<char> string;

Modern implementations often employ optimizations like Small String Optimization (SSO) to avoid heap allocations for short strings by storing them directly in the string object.

Size of String Data Types

Memory Footprint of C-Style Strings

Understanding the size of strings is crucial, especially when optimizing performance.

Size of C-Style Strings

  • Each character occupies 1 byte (ASCII encoding).
  • The total size = number of characters + 1 (for \0).

Example

cpp

char arr[] = "Hello"; // size =  6 bytes (5 chars + '\0')

Size of std::string Objects

  • std::string has overhead: besides the character array, it stores metadata like size and capacity.
  • Actual memory usage varies depending on the implementation (libstdc++, libc++).
Generally, a std::string object is bigger than just the characters it holds, but it gives you powerful and safe operations.

You can find the size and capacity:

cpp

string s = "Learnyard";
cout << "Size: " << s.size() << endl;
cout << "Capacity: " << s.capacity() << endl;
  • Size = number of valid characters.
  • Capacity = allocated memory (might be larger to allow faster growth).

Memory Allocation Strategies

When a string exceeds its capacity and needs to grow, most implementations:

  1. Allocate a new, larger buffer (often 1.5x or 2x the current size)
  2. Copy the existing content to the new buffer
  3. Deallocate the old buffer
  4. Update internal pointers and capacity information

This growth strategy amortizes the cost of reallocation across multiple operations, achieving an average constant time complexity for appending characters.

Memory Storage and Layout

Memory Representation of C-Style Strings

C-style strings are stored as contiguous arrays of characters in memory, with a null character marking the end:

Memory Address: 0x1000  0x1001  0x1002  0x1003  0x1004  0x1005
Content:           H       e       l       l       o      '\0'

The array may be allocated in different memory regions depending on how it's declared:

  • Stack: For arrays declared with automatic storage duration
  • Static Data Segment: For string literals and global/static arrays
  • Heap: For dynamically allocated strings using malloc() or new[]

Memory Representation of std::string

The internal representation of std::string is more complex and varies across implementations. A typical layout might include:

  1. Object Header: Contains metadata about the string
  2. Pointer to Data: Points to the character buffer (which may be inline or on the heap)
  3. Length Field: Stores the current length of the string
  4. Capacity Field: Stores the total allocated capacity
  5. SSO Buffer: Space for small strings to be stored directly in the object

For a short string using SSO:

[String Object]
├── Metadata (length, flags)
└── Characters stored inline ("Hello")

For a longer string requiring heap allocation:

[String Object]               [Heap Memory]
├── Metadata (length, flags)  │
├── Pointer to heap ————————→ ├── Character data ("A longer string...")
└── Capacity                  └── Extra capacity for growth

Memory Management and Performance Implications

The memory layout and management strategies of strings have significant performance implications:

  1. Locality of Reference: SSO improves cache locality by keeping short strings directly in the string object.
  2. Allocation Overhead: Heap allocations are relatively expensive operations that can dominate the performance profile of string-heavy applications.
  3. Move Semantics: Modern C++ move semantics allow efficient transfer of string ownership without copying content, significantly improving performance for string passing and return values.
  4. Memory Fragmentation: Frequent string allocations and deallocations can lead to heap fragmentation, affecting overall application performance.

Example of performance-conscious string handling:

cpp

// Inefficient: Creates multiple temporary strings
std::string result = "Hello, " + first_name + " " + last_name + "!";

// More efficient: Preallocates sufficient space
std::string efficient_result;
efficient_result.reserve(first_name.length() + last_name.length() + 10);
efficient_result = "Hello, ";
efficient_result += first_name;
efficient_result += " ";
efficient_result += last_name;
efficient_result += "!";

Common String Processing Utilities

Here are some frequently used string utility functions that demonstrate common string processing techniques:

cpp

#include <string>
#include <vector>
#include <algorithm>
#include <cctype>
#include <sstream>

// Trim whitespace from beginning of string
std::string ltrim(const std::string &s) {
    std::string result = s;
    result.erase(result.begin(), 
                 std::find_if(result.begin(), result.end(), 
                             [](unsigned char ch) {
                                 return !std::isspace(ch);
                             }));
    return result;
}

// Trim whitespace from end of string
std::string rtrim(const std::string &s) {
    std::string result = s;
    result.erase(std::find_if(result.rbegin(), result.rend(),
                             [](unsigned char ch) {
                                 return !std::isspace(ch);
                             }).base(),
                result.end());
    return result;
}

// Trim both ends
std::string trim(const std::string &s) {
    return rtrim(ltrim(s));
}

// Split string by delimiter
std::vector<std::string> split(const std::string &s, char delimiter) {
    std::vector<std::string> tokens;
    std::string token;
    std::istringstream tokenStream(s);
    
    while (std::getline(tokenStream, token, delimiter)) {
        tokens.push_back(token);
    }
    
    return tokens;
}

// Convert to upper case
std::string to_upper(const std::string &s) {
    std::string result = s;
    std::transform(result.begin(), result.end(), result.begin(),
                  [](unsigned char c){ return std::toupper(c); });
    return result;
}

// Replace all occurrences of a substring
std::string replace_all(const std::string &str, const std::string &from, const std::string &to) {
    std::string result = str;
    size_t start_pos = 0;
    
    while((start_pos = result.find(from, start_pos)) != std::string::npos) {
        result.replace(start_pos, from.length(), to);
        start_pos += to.length();  // In case 'to' contains 'from'
    }
    
    return result;
}

Advanced String Features in Modern C++

String View (C++17)

C++17 introduced std::string_view as a non-owning reference to a string. It provides a view into a sequence of characters, without copying the data:

cpp

std::string_view sv = "Hello, World!";  // No copy, just a view

String views are particularly useful for functions that only need to read string data without modifying it:

cpp

void process_string(std::string_view sv) {
    // Process the string without copying it
}

// Can be called with different string types without conversion
std::string s = "Hello";
const char* cs = "World";
process_string(s);     // No copy
process_string(cs);    // No copy
process_string("!");   // No copy

Unicode Support

Modern C++ provides several ways to handle Unicode strings:

  1. UTF-8 with std::string: Using std::string with UTF-8 encoded content
  2. UTF-16/32 with std::wstring: Using wide character strings
  3. C++20 char8_t: Dedicated type for UTF-8 encoded strings
  4. External Libraries: Libraries like ICU or Boost.Locale for comprehensive Unicode support

Example of UTF-8 handling:

cpp

// UTF-8 encoded string
std::string utf8_string = "Привет, мир!";  // Russian "Hello, world!"

// C++20 UTF-8 literal
std::u8string cpp20_utf8 = u8"こんにちは世界";  // Japanese "Hello, world!"

String Formatting (C++20)

C++20 introduced a standardized formatting library that simplifies string formatting tasks:

cpp

#include <format>  // C++20

std::string formatted = std::format("Hello, {}! The answer is {}.", "World", 42);
// Result: "Hello, World! The answer is 42."

// Format with positional arguments
std::string formatted2 = std::format("The order is {1}, {0}, {2}", "B", "A", "C");
// Result: "The order is A, B, C"

// Format with format specifiers
std::string formatted3 = std::format("Value: {:10.2f}", 3.14159);
// Result: "Value:       3.14"

Conclusion

Strings form the foundation of so many things we do in C++ programming.
From simple greetings to complex text processing, a strong grip over both C-style and std::string types is essential.

C-style strings teach you about memory, arrays, and basic data handling.

std::string brings the power of abstraction, safety, and ease-of-use — empowering you to write cleaner and more robust programs.

Learn both. Use the right tool for the right job!