Skip to content

C++ Strings

C++ offers two primary ways to work with sequences of characters (strings):

  • std::string: The standard C++ string class (<string> header). This is the preferred, modern, safer, and more convenient way to handle strings in C++.
  • C-style character strings: Null-terminated character arrays inherited from the C language (char* or char[]). While necessary for interacting with C APIs or older code, direct manipulation is error-prone and generally discouraged in modern C++.

The std::string class, defined in the <string> header, provides a robust and feature-rich way to manage strings. It handles memory management automatically, preventing many common errors associated with C-style strings.

  • Initialization: Can be initialized from string literals, other std::string objects, or parts of strings.
  • Assignment: Use the = operator.
  • Concatenation: Use the + or += operators.
  • Comparison: Use standard comparison operators (==, !=, <, >, <=, >=).
  • Length/Size: Use .length() or .size() methods (they are equivalent).
  • Accessing Characters: Use [] operator (no bounds checking) or .at() method (throws std::out_of_range if index is invalid).
  • Appending: Use .append() or +=.
  • Finding Substrings: Use .find(), .rfind(), .find_first_of(), .find_last_of(), etc.
  • Substrings: Use .substr() to extract a portion of the string.
  • Modification: Use methods like .insert(), .erase(), .replace().
  • Conversion to C-style: Use .c_str() to get a const char* pointer (null-terminated) for compatibility with C functions.

Example using std::string:

#include <iostream>
#include <string>
#include <stdexcept> // For std::out_of_range
int main() {
// Initialization
std::string greeting = "Hello";
std::string name("World"); // Constructor initialization
std::string message; // Empty string
// Concatenation and Assignment
message = greeting + ", " + name + "!"; // Use +
greeting += ", again!"; // Use +=
std::cout << "Greeting: " << greeting << std::endl;
std::cout << "Message: " << message << std::endl;
// Length
std::cout << "Message length: " << message.length() << std::endl;
// Accessing Characters
std::cout << "First character: " << message[0] << std::endl; // 'H'
try {
std::cout << "Character at index 6: " << message.at(6) << std::endl; // 'W'
// std::cout << message.at(100); // This would throw std::out_of_range
} catch (const std::out_of_range& oor) {
std::cerr << "Out of Range error: " << oor.what() << std::endl;
}
// Finding substrings
size_t commaPos = message.find(',');
if (commaPos != std::string::npos) { // npos indicates 'not found'
std::cout << "Comma found at index: " << commaPos << std::endl;
}
// Substring
std::string sub = message.substr(7, 5); // Extract 5 chars starting at index 7
std::cout << "Substring (name): " << sub << std::endl; // "World"
// Conversion to C-style string (for C APIs)
printf("Message as C-string: %s\n", message.c_str());
return 0;
}

Expected Output:

Greeting: Hello, again!
Message: Hello, World!
Message length: 13
First character: H
Character at index 6: W
Comma found at index: 5
Substring (name): World
Message as C-string: Hello, World!

C-style strings are essentially arrays of characters terminated by a special null character (\0). They are managed using pointers (char*) and require manual memory management if allocated dynamically.

Declaration and Initialization:

// Initialized from a string literal (size automatically includes null terminator)
char greeting[] = "Hello"; // Size is 6 ('H','e','l','l','o','\0')
// Explicitly sized array (must be large enough for string + null terminator)
char farewell[10] = "Bye"; // {'B','y','e','\0', ?, ?, ?, ?, ?, ?}
// Pointer initialization (points to the literal in read-only memory - modifying is undefined behavior!)
const char* readOnlyStr = "Constant String";

Memory Representation of greeting[]:

Index: 0 1 2 3 4 5
Value: 'H' 'e' 'l' 'l' 'o' '\0'

Common C String Functions (<cstring> header):

Section titled “Common C String Functions (<cstring> header):”

The <cstring> header (or <string.h> in C) provides functions for manipulating C-style strings. Warning: Many of these functions are unsafe as they don’t perform bounds checking and can lead to buffer overflows if the destination buffer is too small.

SNFunctionPurpose & Safety Notes
1strcpy(dest, src)Copies string src to dest. Unsafe! Can overflow dest.
2strncpy(dest, src, n)Copies at most n characters. Safer, but might not null-terminate if n is reached.
3strcat(dest, src)Appends string src to dest. Unsafe! Can overflow dest.
4strncat(dest, src, n)Appends at most n characters from src. Safer, always null-terminates.
5strlen(str)Returns the length of str (excluding the null terminator).
6strcmp(s1, s2)Compares s1 and s2. Returns 0 if equal, <0 if s1<s2, >0 if s1>s2.
7strncmp(s1, s2, n)Compares at most n characters.
8strchr(str, ch)Returns a pointer to the first occurrence of character ch in str, or nullptr if not found.
9strstr(haystack, needle)Returns a pointer to the first occurrence of string needle in haystack, or nullptr if not found.

Example using C-style strings (demonstration purposes):

#include <iostream>
#include <cstring> // Use <cstring> in C++
int main() {
char str1[20] = "Hello"; // Ensure buffer is large enough!
char str2[] = "World";
char str3[20];
int len;
// Copy str1 into str3 (use safer strncpy or strcpy_s if available)
// strcpy(str3, str1); // Unsafe version
strncpy(str3, str1, sizeof(str3) - 1); // Safer copy
str3[sizeof(str3) - 1] = '\0'; // Ensure null termination
std::cout << "strncpy(str3, str1, ...): " << str3 << std::endl;
// Concatenate str2 onto str1 (use safer strncat or strcat_s)
// strcat(str1, str2); // Unsafe version
strncat(str1, " ", sizeof(str1) - strlen(str1) - 1);
strncat(str1, str2, sizeof(str1) - strlen(str1) - 1); // Safer concat
std::cout << "strncat(str1, ...): " << str1 << std::endl;
// Total length of str1 after concatenation
len = strlen(str1);
std::cout << "strlen(str1): " << len << std::endl;
// Comparison
if (strcmp(str2, "World") == 0) {
std::cout << "str2 is equal to \"World\"" << std::endl;
}
return 0;
}

Expected Output:

strncpy(str3, str1, ...): Hello
strncat(str1, ...): Hello World
strlen(str1): 11
str2 is equal to "World"

Conclusion: While understanding C-style strings is important for C++ developers (especially when dealing with C libraries or low-level code), always prefer std::string for general string manipulation in modern C++. It’s safer, easier to use, and less error-prone.

For situations where you need read-only access to string data without incurring the overhead of creating a new std::string (e.g., function parameters), consider using std::string_view (from the <string_view> header). It provides a non-owning view into an existing character sequence (which could be a std::string, a C-style string, or a string literal).