Arrays and Strings
C-Style Strings
Null-terminated character arrays and cstring functions
Interview: Understanding legacy codebases and embedded systems; knowing why std::string exists
C-Style Strings
C-style strings are null-terminated character arrays: a sequence of char values ending with the special null terminator character '' (ASCII value 0). The string "Hello" requires 6 bytes: {'H','e','l','l','o',''}. The null terminator is what makes the string functions in <cstring> work — they iterate until they find ''.
String Literals and Storage
String literals ("hello") are stored in read-only memory (the text segment). Assigning a pointer to a string literal gives you a const char* pointing to read-only memory — modifying it is undefined behavior. To get a mutable copy, declare char arr[] = "hello" — this copies the literal onto the stack.
Buffer Overflow — The Classic C Vulnerability
The most dangerous aspect of C-style strings: functions like strcpy and strcat don't know the destination buffer's size. Writing beyond the buffer overwrites adjacent memory — the root cause of countless security vulnerabilities (stack smashing, heap corruption). Always use the size-bounded variants: strncpy, strncat, or preferably std::string.
Common cstring Functions
| Function | Purpose | Complexity | Safe Alternative |
|---|---|---|---|
| strlen(s) | Length (excluding null) | O(n) | string::size() |
| strcpy(dst, src) | Copy string | O(n) | strncpy / string copy constructor |
| strcat(dst, src) | Append string | O(m+n) | strncat / string += |
| strcmp(a, b) | Lexicographic compare | O(n) | string ==, < |
| strstr(hay, needle) | Find substring | O(mn) | string::find() |
Interview Corner
Q: Why is strlen O(n) while std::string::size() is O(1)?
A: strlen walks the char array from the beginning until it finds '' — it must traverse the entire string every call. std::string stores its length as a member variable alongside the data — size() just reads that value in O(1). This is one of the core performance advantages of std::string: strings that contain embedded null characters are also supported, since length tracking is separate.
Q: What is the difference between const char and char[]?
A: const char* p = "hello" is a pointer to a string literal in read-only memory — the pointer can be reassigned, but the data cannot be modified. char arr[] = "hello" copies the literal into a stack-allocated, mutable array — the array can be modified but its size is fixed. Understanding this distinction is often tested in interviews about C++ memory model.
Common Pitfalls
- Buffer overflow: Using
strcpy(dest, src)whensrcis longer thandestoverwrites adjacent memory. Use size-bounded functions orstd::string. - Modifying string literals:
char* p = "hello"; p[0] = 'H';is undefined behavior — string literals are in read-only memory on most platforms. - Off-by-one in buffer sizing: Forgetting to allocate +1 byte for the null terminator:
char buf[5] = "hello"— "hello" needs 6 bytes. The compiler will warn or truncate.
Best Practices
- Use
std::stringin new C++ code. Only use C-style strings when interfacing with C APIs or in embedded environments with strict memory constraints. - When C-style strings are necessary, always use bounded functions:
strncpy,snprintf,strncat. - Use
std::string_viewas the read-only bridge between C-style strings andstd::stringAPIs without copying.