C Mastery / Strings and the Standard Character Functions
Part 1 — The Core Language

Strings and the Standard Character Functions

This chapter explains how C represents strings (null-terminated character arrays), how string literals work, and how to use the core <string.h> functions safely. A deeper reference for each function appears in c.stdlib.4.

Why This Matters

C has no string type. A string is a convention: a contiguous sequence of characters terminated by a null byte ('\0'). Getting the null terminator, buffer sizing, and the strncpy/strncat semantics right is a matter of memory safety, not just style.

Prerequisites

Core Concept

Strings are null-terminated arrays

char s[6] = {'h', 'e', 'l', 'l', 'o', '\0'};
char t[] = "hello";    /* same: 6 bytes, including the terminator */

A string literal "hello" is an array of char with static storage, of length 6 (5 characters plus the null terminator). It decays to char * in expressions, and its contents are not modifiable (modifying a string literal is UB).

String vs. character array

Not every char array is a string. It is a string only if it contains a null terminator within its bounds. Functions in <string.h> that operate on strings rely on that terminator.

Syntax

char *s = "hello";       /* s points to a string literal (do not modify) */
char a[] = "hello";      /* modifiable copy: 6 bytes */

The Core Functions

FunctionPurposeNotes
strlen(s)length excluding nullmust be null-terminated
strcpy(d, s)copy s into dd must be large enough; no bounds check
strncpy(d, s, n)copy up to n charsdoes NOT null-terminate if src >= n
strcat(d, s)append s to dd must be large enough
strncat(d, s, n)append up to n charsalways null-terminates (writes n+1)
strcmp(a, b)compare lexicallyreturns <0, 0, >0
strncmp(a, b, n)compare first n chars
strchr(s, c)first occurrence of c
strrchr(s, c)last occurrence of c
strstr(h, n)first occurrence of n in h
strspn/strcspn/strpbrkspan/complement/breaksee c.stdlib.4
strtoktokenize (stateful!)modifies the string, not reentrant
memcpy/memmove/memset/memcmp/memchrraw memory opssizes in bytes, not chars

The full signatures, failure modes, and portability notes are in c.stdlib.4.

Examples

Correct string copy

#include <string.h>
#include <stdio.h>

int main(void)
{
    char src[] = "hello";
    char dst[32];
    strcpy(dst, src);   /* safe because dst is large enough */
    printf("%s\n", dst);
    return 0;
}

Expected output: hello.

The strncpy trap

#include <string.h>
#include <stdio.h>

int main(void)
{
    char src[] = "hello world";
    char dst[5];
    strncpy(dst, src, sizeof dst);   /* copies "hello", NO null terminator */
    /* dst is not a valid string! */
    printf("%.5s\n", dst);           /* bounded print, avoids overread */
    return 0;
}

strncpy copies exactly n characters (padding with zeros if the source is shorter) and does not null-terminate when the source is at least n characters. This is a frequent source of bugs. strncat is safer in that it always null-terminates.

Manual null-termination after strncpy

char dst[6];
strncpy(dst, src, sizeof dst - 1);
dst[sizeof dst - 1] = '\0';

How It Works

String functions scan for the null terminator (strlen, strcpy, strcat, strcmp) or operate on explicit byte counts (mem*, strn* variants). The null terminator is just a byte with value 0; there is nothing special about it except the convention that string functions stop there.

Variations

String literals and const

String literals have type char[N] in C (not const char[N]), but modifying them is UB. You should treat them as read-only, and declare pointers to them as const char * when possible.

Wide and UTF-8 strings

Wide strings use wchar_t and are covered in c.stdlib.10. UTF-8 is a byte encoding for Unicode that is compatible with null-terminated char strings (as long as no embedded zero bytes are misinterpreted), covered in c.stdlib.10.

Common Mistakes

because it needs 6 bytes).

Undefined Behavior

VERIFIED

VERIFIED

Portability

frequently surprising.

universal on modern systems.

Under the Hood

String literals are typically placed in a read-only section (.rodata). The null terminator is just a zero byte. String functions compile to loops that scan for zero or copy until zero; modern compilers may optimize strlen/ strcpy to vectorized or built-in versions.

Practical Usage

raw strcpy/strcat when sizes are not provably safe.

and handle termination explicitly.

Exercises

1. Write a program that demonstrates the difference between char *s = "hello" and char a[] = "hello" (attempt to modify and observe). 2. Show the strncpy non-termination behavior and fix it. 3. Implement your own strlen, strcpy, and strcmp with a loop. 4. Write a safe string-copy function that always null-terminates and never overflows.

Deep Challenge

Implement strtok from scratch (including its static-state behavior) and then explain why it is not reentrant. Provide a reentrant alternative (like strtok_r on POSIX) and discuss the trade-offs.

References

Verification

verified.`

Progress

Concept checkboxes

Mastery levels

ConceptCurrent level (0–8)Target level
c.str.literal06
c.str.funcs06