C from the ground up

Strings as char arrays

C has no string type: text is a char array ending in a zero. Meet strlen, strcmp and strcpy, the functions that know where the text ends.

Part 7 of 12

Intermediate16 min readBack to Courses

Text is an array of chars

There is no string type in C. Text is stored as a char array, and by convention the last character is a zero, written \0. That zero is the mark the string functions look for to know where the text stops.

So "Hi" actually needs three slots: the H, the i, and the hidden zero. When you declare char name[20] = "Ada"; you reserve twenty slots, fill four of them, and the rest are spare.

The string library

The header string.h brings the tools that respect that ending zero. strlen counts the characters before the zero. strcmp compares two strings and returns zero when they are equal. strcpy copies one into another.

Notice that strcmp returning zero means equal, which reads backwards at first. It returns a negative or positive number when they differ, so the usual test is strcmp(a, b) == 0.

Room to copy

strcpy does not know how much room the destination has; it copies until the zero and trusts you. If the target array is too small, it writes past the end. Always size the destination to hold the longest text you will copy, plus one for the zero.

You can also walk a string with a loop and read it one char at a time, stopping at the zero. That is exactly what the library functions do underneath, so it is worth trying once.

The zero is the contract

Every string function walks forward until it meets the zero byte. strlen counts the steps, strcpy copies until it arrives, and printf with %s prints until it arrives. The zero is not decoration — it is the only thing that says where the text ends.

That walk costs time proportional to the length, so calling strlen in the condition of a loop rescans the whole string on every pass. Measure once into a variable and use the number.

Literals, arrays and what you may write

char name[20] = "Ada"; copies the characters into your array, and you may change them. char *name = "Ada"; points at a string literal, which may live in read-only memory; writing through that pointer is undefined behaviour and often crashes at once.

sizeof(name) is the room in the array, not the length of the text. For char name[20] = "Ada", it is 20 while strlen(name) is 3. Keep the two ideas apart and buffer sizes stop surprising you.

Joining text without running over the end

strcpy trusts the destination, but snprintf takes its size. snprintf(dest, sizeof dest, "%s %s", first, last) writes at most that many bytes including the ending zero, and reports how many characters the full result would have needed. A return value at or above the size means the text was cut, which is your signal to give the buffer more room.

That makes it the safer default when the pieces come from anywhere you do not control. It still needs the array itself in view: passed to a function, dest is a pointer, so sizeof measures the pointer and the bound is wrong. Pass the size alongside, exactly as you pass the count for an array.

Finding a piece, and checking for NULL

strchr(text, 'x') returns a pointer to the first x, or NULL when there is none. strstr(text, "needle") does the same for a whole substring. Both hand back a position inside the original string rather than a copy, so you can read from it or subtract the start address to get an index.

The NULL case is the one to handle before you subtract or print. A program that assumes the character is present will follow a null pointer the first time the input changes. Test the result, then use it; that single check is the difference between a search and a crash.

Three string mistakes account for most crashes: comparing two strings with ==, which compares addresses rather than characters; sizing a buffer without the extra slot for the zero; and writing into a string literal through a char *. Use strcmp for the first, count the zero for the second, and copy literals into an array for the third.

Try these next

  • Count the vowels in a word with a loop that stops at the ending zero.
  • Print a word backwards by starting at strlen(word) - 1 and counting down to zero.
  • Copy a four-character word into char buf[4] and explain why the result is not a string.

Measure and compare

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

int main(void) {
    char word[20] = "hello";

    printf("Length %d\n", (int)strlen(word));
    if (strcmp(word, "hello") == 0) {
        printf("It matches\n");
    }
    return 0;
}

Copy, measure, compare

Run it, then change the name and the comparison string and watch which line prints. Keep every char array big enough to hold the text and its zero.

Output
Click "Run" to execute your code

Reverse a word in place

Run it, then change the word to a palindrome and check that the reversed text reads the same. Then try a one-letter word and trace the loop bounds.

Output
Click "Run" to execute your code

Forgetting the ending zero, or leaving no room for it, is the cause of most string bugs. When you size a char array, count the visible characters and then add one for the zero.

Check what you learned

One question at a time. A wrong answer explains itself — take another go.

Part 1 of 5

What marks the end of a C string?