C strings: char arrays and the null terminator
Understand how C represents text as null-terminated char arrays — declaration, the null terminator, string literals, and basic iteration.
- Explain that a C string is a char array terminated by a null byte
- Declare a string as a char array and as a pointer to a string literal
- Iterate over a string character by character
- Use strlen to find a string's length
Text in C is stored as an array of char values with a special sentinel byte at the end: the null terminator ('\0', value 0). This design is elegant in its simplicity and a source of many of C's most famous bugs. Understanding it thoroughly is essential for writing safe C.
The null terminator
Every C string ends with the byte '\0' (null, ASCII value 0). This is how functions like printf, strlen, and strcpy know where the string ends — they walk forward through memory until they hit the zero byte.
"Hello" in memory:
H e l l o \0
72 101 108 108 111 0A char array of length 6 stores the 5-character string "Hello" plus the null terminator.
Declaring strings
As a char array with initialisation:
char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};More commonly, string literal syntax handles the null terminator automatically:
char greeting[6] = "Hello"; /* compiler adds '\0' automatically */
char greeting2[] = "Hello"; /* compiler infers size = 6 */As a pointer to a string literal:
const char *message = "Hello, World!";This is different from the array form. The string "Hello, World!" is stored in read-only memory. The pointer message points to it. You should mark it const because modifying a string literal is undefined behaviour.
Array strings and pointer strings are different. char greeting[] = "Hello" creates a writable copy of the string on the stack. const char *message = "Hello" points to read-only data. You can modify greeting[0] = 'J' to change it to "Jello", but modifying through the pointer version is undefined behaviour and typically causes a crash.
Iterating over a string
Since strings end with '\0', you iterate until you hit it:
#include <stdio.h>
int main(void) {
char str[] = "Hello";
/* Method 1: index-based */
for (int i = 0; str[i] != '\0'; i++) {
printf("str[%d] = '%c' (ASCII %d)\n", i, str[i], str[i]);
}
/* Method 2: pointer-based (preview of pointers) */
for (char *p = str; *p != '\0'; p++) {
printf("%c", *p);
}
printf("\n");
return 0;
}Output:
str[0] = 'H' (ASCII 72)
str[1] = 'e' (ASCII 101)
str[2] = 'l' (ASCII 108)
str[3] = 'l' (ASCII 108)
str[4] = 'o' (ASCII 111)
HelloString length with strlen
strlen from <string.h> returns the number of characters before the null terminator:
#include <stdio.h>
#include <string.h>
int main(void) {
char str[] = "Hello";
size_t len = strlen(str);
printf("Length: %zu\n", len); /* 5, not 6 */
return 0;
}strlen does not count the null terminator. The array needs len + 1 bytes to store the string including the terminator.
Printing strings
char name[] = "Alice";
printf("Hello, %s!\n", name); /* %s for strings */
puts(name); /* puts adds a newline automatically */%s tells printf to print characters until it hits '\0'. puts is simpler for just printing a string with a newline.
Building strings manually
#include <stdio.h>
int main(void) {
char upper[20] = "hello";
for (int i = 0; upper[i] != '\0'; i++) {
if (upper[i] >= 'a' && upper[i] <= 'z') {
upper[i] -= 32; /* lowercase is 32 more than uppercase in ASCII */
}
}
printf("%s\n", upper); /* HELLO */
return 0;
}Or using <ctype.h>:
#include <ctype.h>
for (int i = 0; upper[i]; i++) {
upper[i] = toupper((unsigned char)upper[i]);
}Cast to unsigned char before calling ctype.h functions. Functions like toupper and isdigit take an int whose value must be representable as unsigned char or be EOF. Passing a plain char (which may be signed) can pass negative values on platforms where char is signed, causing undefined behaviour.
Where to go next
Next: string functions from <string.h> — strcpy, strcat, strcmp, strncpy, and others that let you copy, concatenate, and compare strings without writing the loops yourself.
Multidimensional arrays
Represent tables and matrices in C using two-dimensional arrays — declaration, indexing, nested loops, and how they are laid out in memory.
String functions from <string.h>
Use the standard C string library — strcpy, strcat, strcmp, strncpy, strstr, and others — to copy, compare, and search strings safely.