ReviseAlgo Logo

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 stringO(n)strncpy / string copy constructor
strcat(dst, src)Append stringO(m+n)strncat / string +=
strcmp(a, b)Lexicographic compareO(n)string ==, <
strstr(hay, needle)Find substringO(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) when src is longer than dest overwrites adjacent memory. Use size-bounded functions or std::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::string in 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_view as the read-only bridge between C-style strings and std::string APIs without copying.