C++ Strings Interview Questions
C++ Strings and Built-in String Functions
What are the two types of strings in C++ and what are their differences?
C++ supports two types of strings:
- C-style strings (character arrays): Null-terminated character arrays, inherited from C language.
- String class objects (std::string): C++ Standard Library string class from the <string> header.
| Aspect | C-style Strings | std::string |
|---|---|---|
| Header | <cstring> or none | <string> |
| Memory | Fixed size, manual management | Dynamic, automatic management |
| Null terminator | Required | Not required (handled internally) |
| Assignment | strcpy() function needed | Direct assignment with = operator |
| Concatenation | strcat() function | + operator or append() |
| Length | strlen() function | length() or size() methods |
| Safety | Prone to buffer overflow | Bounds checking available |
How do you declare and initialize strings in C++ using both methods?
C-style string declaration and initialization:
- Character array with null terminator: char str[] = "Hello";
- Explicit character array: char str[6] = {'H','e','l','l','o','\0'};
- Pointer to string literal: char *str = "Hello";
- Uninitialized array: char str[20];
- Default constructor: std::string str;
- From C-string: std::string str = "Hello";
- From another string: std::string str2 = str1;
- With repetition: std::string str(5, 'A'); (creates "AAAAA")
- Substring: std::string str = "Hello World".substr(6, 5);
What are the most commonly used C-string functions from <cstring> header?
| Function | Purpose | Description |
|---|---|---|
| strlen() | String length | Returns length of string (excluding null terminator) |
| strcpy() | String copy | Copies source string to destination |
| strncpy() | Bounded copy | Copies up to n characters |
| strcat() | String concatenation | Appends source to destination |
| strncat() | Bounded concatenation | Appends up to n characters |
| strcmp() | String compare | Compares two strings lexicographically |
| strncmp() | Bounded compare | Compares up to n characters |
| strchr() | Character search | Finds first occurrence of character |
| strrchr() | Reverse search | Finds last occurrence of character |
| strstr() | Substring search | Finds first occurrence of substring |
| strtok() | String tokenization | Splits string into tokens |
What are the key member functions of the std::string class?
| Category | Functions | Description |
|---|---|---|
| Capacity | size(), length(), capacity(), empty(), clear(), reserve(), shrink_to_fit() | Query and manage string size and capacity |
| Element Access | operator[], at(), front(), back() | Access individual characters (at() does bounds checking) |
| Modifiers | append(), push_back(), insert(), erase(), replace(), swap(), pop_back() | Modify string content |
| Operations | c_str(), data(), copy(), find(), rfind(), find_first_of(), find_last_of(), substr(), compare() | String operations and searching |
| Numeric Conversions | stoi(), stol(), stoll(), stof(), stod(), to_string() | Convert between strings and numbers (C++11) |
How do string comparison functions work in C++?
C-style string comparison (strcmp):
- Returns 0 if strings are equal
- Returns negative value if first string is less than second
- Returns positive value if first string is greater than second
- Comparison is lexicographical (dictionary order)
- Case-sensitive comparison
- compare() method: Similar return values as strcmp()
- Relational operators: ==, !=, <, <=, >, >= can be used directly
- Case-sensitive by default
- For case-insensitive comparison, need to convert to same case first or use custom comparison
What is the difference between strcpy() and strncpy() functions?
| Aspect | strcpy() | strncpy() |
|---|---|---|
| Safety | Unsafe - no bounds checking | Safer - specifies maximum characters to copy |
| Null terminator | Always copies null terminator | May not add null terminator if source length ≥ n |
| Padding | No padding | Pads destination with nulls if source shorter than n |
| Use case | When source size is known and fits destination | When copying from untrusted sources or fixed buffers |
| Performance | Faster | Slightly slower due to length checking |
How do you convert between C-style strings and std::string?
Converting C-string to std::string:
- Implicit conversion: std::string str = cstr;
- Constructor: std::string str(cstr);
- Assignment: str = cstr;
- With length: std::string str(cstr, length);
- c_str() method: Returns const char* (read-only)
- data() method: Returns char* (C++17 onwards, non-const for non-const strings)
- copy() method: Copies to character array
- c_str() pointer becomes invalid if string is modified
- For modifications, copy to a separate buffer
- Always ensure destination buffer is large enough
What are the string search functions available in C++?
C-style string search functions:
- strchr(): Find first occurrence of character
- strrchr(): Find last occurrence of character
- strstr(): Find substring
- strpbrk(): Find any character from set
- strcspn(): Find length of initial segment not containing characters
- strspn(): Find length of initial segment containing only characters
- find(): Find first occurrence of string/character
- rfind(): Find last occurrence of string/character
- find_first_of(): Find first occurrence of any character in set
- find_last_of(): Find last occurrence of any character in set
- find_first_not_of(): Find first character not in set
- find_last_not_of(): Find last character not in set
- All return string::npos if not found
How does string concatenation work in C++ with both string types?
C-style string concatenation:
- strcat(dest, src): Appends src to dest
- strncat(dest, src, n): Appends up to n characters from src to dest
- Must ensure dest has enough space for both strings plus null terminator
- No automatic memory management
- Returns pointer to dest
- + operator: string3 = string1 + string2;
- += operator: string1 += string2;
- append() method: Various overloads for different data types
- push_back(): Appends single character
- Automatic memory management - string resizes as needed
- Can concatenate strings, C-strings, characters, and ranges
What are the string tokenization methods in C++?
C-style string tokenization:
- strtok(): Modifies original string by replacing delimiters with null characters
- First call: strtok(string, delimiters)
- Subsequent calls: strtok(NULL, delimiters)
- Not thread-safe (uses static buffer)
- strtok_r(): Thread-safe version (POSIX)
- Returns pointer to token or NULL when done
- No built-in tokenizer in std::string
- Common approaches:
- find() and substr() combination
- stringstream with getline() and delimiter
- Regular expressions (C++11)
- Custom tokenization function
What are the numeric conversion functions available for strings in C++?
C++11 introduced numeric conversion functions in std::string:
Features:
| Function | Purpose | Example Conversion |
|---|---|---|
| stoi() | String to int | "123" → 123 |
| stol() | String to long | "123456" → 123456L |
| stoll() | String to long long | "123456789" → 123456789LL |
| stoul() | String to unsigned long | "123" → 123UL |
| stoull() | String to unsigned long long | "123" → 123ULL |
| stof() | String to float | "3.14" → 3.14f |
| stod() | String to double | "3.14159" → 3.14159 |
| stold() | String to long double | "3.14159" → 3.14159L |
| to_string() | Numeric to string | 123 → "123" |
- Automatic detection of base (decimal, octal, hex)
- Leading whitespace is ignored
- Throws std::invalid_argument if no conversion
- Throws std::out_of_range if value out of range
- Optional parameters for size_t* and int base
What is the difference between size() and capacity() in std::string?
| Function | Returns | Description |
|---|---|---|
| size() | size_t | Number of characters currently in the string |
| length() | size_t | Same as size() (for string compatibility) |
| capacity() | size_t | Total characters that can be stored without reallocation |
| max_size() | size_t | Maximum possible string size |
| empty() | bool | True if string has 0 characters |
- capacity() >= size() always
- When size() reaches capacity(), adding more characters triggers reallocation
- reserve() can pre-allocate memory to avoid frequent reallocations
- shrink_to_fit() reduces capacity to fit current size
- Reallocation invalidates iterators, pointers, and references to characters
What are iterator functions available for std::string?
std::string iterator functions:
Usage scenarios:
| Function | Returns | Description |
|---|---|---|
| begin() | iterator | Iterator to first character |
| end() | iterator | Iterator past last character |
| rbegin() | reverse_iterator | Reverse iterator to last character |
| rend() | reverse_iterator | Reverse iterator before first character |
| cbegin() | const_iterator | Const iterator to first character |
| cend() | const_iterator | Const iterator past last character |
| crbegin() | const_reverse_iterator | Const reverse iterator to last character |
| crend() | const_reverse_iterator | Const reverse iterator before first character |
- Range-based for loops (C++11)
- STL algorithms (sort, find, transform, etc.)
- Iterating forward or backward through string
- Const iterators for read-only access
- Reverse iteration for processing from end to beginning
How do you perform case conversion on strings in C++?
Built-in methods:
Common approaches:
- No direct case conversion in std::string or C-string functions
- Use character functions from <cctype> header
| Function | Purpose |
|---|---|
| toupper() | Convert character to uppercase |
| tolower() | Convert character to lowercase |
| isupper() | Check if character is uppercase |
| islower() | Check if character is lowercase |
| isalpha() | Check if character is alphabetic |
- Loop through string and apply toupper()/tolower() to each character
- Use std::transform with toupper/tolower
- For locale-specific conversions, use std::locale
- Third-party libraries like Boost.StringAlgorithms
What is the substr() function in std::string and how is it used?
std::string::substr() function:
- Returns a substring of the original string
- Syntax: substr(pos, count)
- pos: Starting position (default: 0)
- count: Number of characters (default: npos - until end)
- Returns new string containing the substring
- Does not modify original string
- Throws std::out_of_range if pos > size()
- Extracting parts of strings (first N characters, last N characters, middle section)
- String splitting/tokenization
- Removing prefixes or suffixes
- Creating string views without copying (C++17 string_view is better for this)
- Creates a new string (memory allocation)
- For read-only operations, consider std::string_view (C++17)
- For C-strings, use strncpy() with manual null termination
What are the safety considerations when working with C-style strings?
Common security issues with C-strings:
- Buffer overflow: Writing beyond allocated memory
- Off-by-one errors: Forgetting null terminator
- Uninitialized buffers: Containing garbage data
- String truncation: Losing data without indication
- Always validate input lengths before copying
- Use bounded functions (strncpy, strncat, snprintf)
- Always null-terminate strings manually when using bounded functions
- Initialize character arrays
- Check return values of string functions
- Use sizeof() for stack-allocated arrays
- Prefer std::string for new code
- strlcpy() and strlcat() (BSD, not standard C/C++)
- snprintf() for formatted output
- Windows: StringCchCopy, StringCchCat
- Compiler security features: /GS flag, stack cookies
How do you read and write strings in C++ with I/O operations?
Reading strings:
- cin >> string: Reads word (stops at whitespace)
- getline(cin, string): Reads entire line (including spaces)
- getline(cin, string, delimiter): Reads until delimiter
- cin.getline(): For C-strings with buffer size limit
- fgets(): File reading for C-strings
- cout << string: Output string
- printf("%s", str.c_str()): Formatted output for std::string
- puts(): Output C-string with newline
- fputs(): File output for C-strings
- ifstream/ofstream with >> and << operators
- getline() with file streams
- fread()/fwrite() for binary data
What are the performance considerations when using std::string?
Performance characteristics of std::string:
- Small String Optimization (SSO): Many implementations store small strings (typically ≤ 15 chars) directly in object, avoiding heap allocation
- Copy-on-write (COW): Some implementations use this optimization (less common now due to thread safety)
- Growth strategy: Typically exponential (double capacity) to amortize reallocation cost
- Use reserve() when final size is known to avoid reallocations
- Avoid repeated concatenation with + in loops (use += or stringstream)
- Prefer passing by const reference for function parameters
- Use move semantics (C++11) for returning strings
- Consider string_view (C++17) for read-only parameters
- Avoid unnecessary copies with substr()
- std::string has overhead: pointer, size, capacity (typically 24-32 bytes)
- Fragmentation from frequent allocations/deallocations
- Custom allocators can improve performance for specific use cases
What is std::string_view (C++17) and when should it be used?
std::string_view features:
Use cases for string_view:
- Lightweight non-owning read-only view of a string
- Header: <string_view>
- Contains pointer to data and size
- No memory allocation (typically 16 bytes)
- Can view any contiguous character sequence
| Aspect | std::string | std::string_view |
|---|---|---|
| Ownership | Owns the data | Non-owning view |
| Memory | Allocates/deallocates | No allocation |
| Modification | Mutable | Read-only |
| Size | Larger (24-32 bytes) | Smaller (16 bytes) |
| Lifetime | Manages lifetime | Depends on source |
- Function parameters for read-only string access
- Avoiding copies when passing substrings
- Parsing and tokenization
- String literals in performance-critical code
- Interface between different string types
- Lifetime: Source data must outlive string_view
- Not null-terminated by requirement (but often is)
- No conversion to C-string automatically
What are the best practices for string handling in modern C++?
Modern C++ string best practices:
- Prefer std::string over C-strings for new code
- Use std::string_view (C++17+) for read-only function parameters
- Pass by const reference when not modifying strings
- Use reserve() when final size is known to avoid reallocations
- Prefer string literals with "s" suffix in C++14: using namespace std::string_literals;
- Use auto with string operations to avoid type issues
- Leverage range-based for loops for iteration
- Use modern conversion functions (stoi, to_string) instead of C functions
- Be cautious with c_str() - pointer invalidated on modification
- Consider emplace_back() instead of push_back() for characters
- Use string streams for complex string building
- Regular expressions (C++11+) for complex pattern matching
- Avoid strlen() in loops - cache the result
- Validate user input before processing
- Use appropriate string functions for the task (find vs find_first_of, etc.)
Summary of Key Points:
- std::string is preferred over C-strings for safety and convenience
- Always consider buffer sizes and null termination with C-strings
- Use appropriate functions for the task (bounded vs unbounded, find vs search)
- Understand memory management implications of string operations
- Leverage modern C++ features (string_view, numeric conversions, literals)
- Consider performance implications (SSO, reallocation, copying)
- Validate inputs and check function returns for security
- Choose the right string type based on ownership and lifetime requirements