Strings
C has no string type. A string is simply an array of char that ends with a zero byte, written '\0' and called the null terminator. Every string function relies on that terminator to know where the text stops — so making sure it's there, and that arrays are big enough to hold it, is the heart of string handling in C.
Strings are char arrays
#include <stdio.h> int main(void) { char greeting[] = "Hello"; printf("%s has %zu bytes\n", greeting, sizeof greeting); for (size_t i = 0; i < sizeof greeting; i++) { if (greeting[i] != '\0') { printf("[%zu] %3d '%c'\n", i, greeting[i], greeting[i]); } else { printf("[%zu] %3d (the terminator)\n", i, greeting[i]); } } return 0; }
Hello has 6 bytes [0] 72 'H' [1] 101 'e' [2] 108 'l' [3] 108 'l' [4] 111 'o' [5] 0 (the terminator)
"Hello" has five letters but takes six bytes: the compiler adds the '\0' automatically. %s prints characters until it reaches that zero.
Declaring strings
#include <stdio.h> int main(void) { char name[20] = "Ada"; // 20 bytes: "Ada", '\0', then zeros char word[] = "kettle"; // exactly 7 bytes const char *motto = "Keep calm"; // pointer to a string literal char letters[4] = { 'a', 'b', 'c', '\0' }; name[0] = 'E'; // arrays can be modified printf("%s | %s | %s | %s\n", name, word, motto, letters); return 0; }
Eda | kettle | Keep calm | abc
A string literal like "Keep calm" is stored in read-only memory for the whole program. Point to it with a const char *; trying to modify it is undefined behaviour (and often a crash). If you need to change the text, copy it into a char array.
Length vs. size
strlen (from <string.h>) counts the characters before the terminator. sizeof gives the array's capacity in bytes:
#include <stdio.h> #include <string.h> int main(void) { char city[32] = "Lisbon"; printf("strlen: %zu, sizeof: %zu\n", strlen(city), sizeof city); return 0; }
strlen: 6, sizeof: 32
strlen has to walk the whole string to find the zero, so call it once and store the result rather than calling it in every loop condition.
Walking through a string
Loop until you reach the terminator:
#include <stdio.h> int main(void) { const char *text = "the quick brown fox"; int spaces = 0; for (int i = 0; text[i] != '\0'; i++) { if (text[i] == ' ') spaces++; } printf("%d words\n", spaces + 1); return 0; }
4 words
You can't assign or compare with = and ==
Strings are arrays, so the usual operators don't do what you'd expect. Assigning an array is an error; comparing with == compares addresses, not text:
#include <stdio.h> int main(void) { char status[10]; status = "ready"; printf("%s\n", status); return 0; }
main.c:5:12: error: array type 'char[10]' is not assignable
And == on two arrays compares where they are in memory — two different arrays are never equal, whatever they contain. The compiler can even tell you so:
#include <stdio.h> int main(void) { char status[10] = "ready"; char input[10] = "ready"; printf("%s\n", status == input ? "same" : "different"); return 0; }
main.c:6:27: warning: array comparison always evaluates to false [-Wtautological-compare]
The right tools are strcpy to copy text into an array and strcmp to compare it:
#include <stdio.h> #include <string.h> int main(void) { char status[10]; strcpy(status, "ready"); char input[10] = "ready"; printf("strcmp says %s\n", strcmp(status, input) == 0 ? "same" : "different"); return 0; }
strcmp says same
Use strcpy (or safer alternatives) to copy and strcmp to compare — the next lesson covers them.
The terminator must fit
An array for a string needs one more byte than the number of characters. Forget it, and functions run past the end looking for a zero — a buffer overflow. When you build strings yourself, add the terminator explicitly:
#include <stdio.h> int main(void) { char initials[4]; const char *names[] = { "Grace", "Brewster", "Hopper" }; for (int i = 0; i < 3; i++) { initials[i] = names[i][0]; } initials[3] = '\0'; // without this, printf would read beyond the array printf("%s\n", initials); return 0; }
GBH
Reading strings
As lesson 15 showed, read text with fgets, which respects the array size, and strip the newline:
#include <stdio.h> #include <string.h> int main(void) { char colour[16]; printf("Favourite colour? "); if (fgets(colour, sizeof colour, stdin)) { colour[strcspn(colour, "\n")] = '\0'; printf("\n%s is a fine choice (%zu letters).\n", colour, strlen(colour)); } return 0; }
teal
Favourite colour? teal is a fine choice (4 letters).
Never use gets — it can't limit the input length and was removed from C in C11 — and always give scanf("%s") a width, such as %15s.
Text encoding
A char is one byte. Plain English letters fit in one byte each, but most other characters, such as é or emoji, take several bytes in the common UTF-8 encoding. strlen counts bytes, not visible characters:
#include <stdio.h> #include <string.h> int main(void) { printf("%zu %zu\n", strlen("cafe"), strlen("café")); return 0; }
4 5
For full Unicode text processing, C programs use libraries such as ICU; for most everyday programs, treating UTF-8 as bytes works fine as long as you don't cut a string in the middle of a character.
Try it yourself
Reverse a string in place by swapping characters from both ends towards the middle.
desserts