<string.h>, and pick up the printf format controls that let you produce clean output.
By the end of this lesson, cadets will be able to:
<string.h> to common string tasks. (Outcome 2)Complete before class. These set the vocabulary we will use.
| Source | Sections | Why |
|---|---|---|
| Beej-C | Chapter 7 (Strings) | What a string actually is in C, NUL termination, copying gotchas |
| Beej-Lib | <string.h> reference (skim) |
Function signatures for strlen, strcpy, strcmp, strcat, and their strn* siblings |
| King, C Programming: A Modern Approach | Chapter 13 (Strings) | Optional deeper dive with more examples |
char *s = "Hello"; and calls strings "pointers." We have not formally taught pointers yet (that lands in Lesson 12). For now: read the array form char s[] = "Hello"; as the working form. The char * syntax will make full sense in two lessons. You can absolutely follow the chapter; just do not get stuck on the pointer language.
'\0') and why it matterschar[] initialized from one= does not copy a stringstrlen and strcpy<string.h> referencestrlenstrcpy, strncpystrcmpstrcat, strncat%5d pads on the left; %-5d pads on the right.C does strings differently than every modern language you have used. Python hides the bytes from you; C makes them the point. This reference material walks through what a string actually is in memory, the five functions you will use constantly, and the printf controls that make output presentable.
The Lesson 10 deck walks through the anatomy of a C string, the five core <string.h> functions, the safer strn* family, and printf format control. Slides are the spine of lecture; the walkthroughs are where you practice.
In Python, a string was a built-in type with a known length and a rich set of methods. len(s) was constant time; s + t made a new string; s == t compared values.
C has none of that. A C string is a sequence of char values in contiguous memory, with a single zero byte marking the end. There is no length stored anywhere. There is no + operator for strings. There is no built-in equality test.
Everything you want to do with a string is implemented as a function that walks the memory one byte at a time until it sees a zero. Once you accept that, the rest of the lesson is just learning the names of those functions.
Every C string ends with a zero byte. Written in C, this byte is '\0', a single character with the integer value 0. We pronounce it "NUL" (one L). It is not the digit '0', which has ASCII value 48.
When you write a string literal in double quotes, the compiler adds the NUL for you. The string "hi" looks like this in memory:
That terminator is what makes strlen possible. It walks forward from the start, counting bytes, and stops when it sees a zero. strlen("hi") returns 2, not 3, because the NUL is the marker, not part of the visible content.
Why this matters in practice: if you ever lose the NUL (by overwriting it with another byte, by copying a string into a buffer too small to hold it, or by manually filling characters without writing the terminator), every subsequent strlen, printf("%s", ...), or comparison will read past the end of your data into whatever happens to be next in memory. That is the canonical C string bug.
char[] formIn this course, we declare strings as character arrays. There are three common ways:
Rule of thumb on sizing: when you declare a fixed-size buffer that will hold a string, ask "what is the longest content I might put here?" and add one for the NUL. For a username of up to 31 characters, declare char username[32]. Thirty-one visible bytes plus one for the NUL.
char *s = "Hello";. That form points at read-only memory. Trying to modify it (s[0] = 'h';) usually crashes the program. We are deliberately leaving the pointer-form discussion until Lesson 12. For now, use the array form for anything you intend to modify.<string.h>Include #include <string.h> at the top of any file that calls these. Each one walks memory looking for a NUL.
| Function | What it does |
|---|---|
| strlen(s) | Returns the number of characters in s before the NUL. Does not include the NUL itself. |
| strcpy(dest, src) | Copies bytes of src into dest, including the NUL. You must ensure dest is large enough. |
| strcmp(a, b) | Compares two strings lexicographically. Returns 0 if equal, negative if a < b, positive if a > b. Zero means equal. Do not flip the logic. |
| strcat(dest, src) | Appends src onto the end of dest. Overwrites dest's NUL with the first character of src, then continues. Again, ensure dest has room. |
| strncpy(dest, src, n) strncat(dest, src, n) |
Bounded versions that copy or append at most n bytes. Safer when you do not trust the source's length. Caveat: strncpy does not guarantee a NUL if n equals the source length, so you may have to write one yourself. |
Worked example. Build a display string from parts using the safer bounded form:
DFCS C Programming Standard, §8.1. This lesson introduces the first defensive-programming rule from the course style guide. §8.1 directs you to avoid library functions that don't check buffer bounds (e.g., gets(), strcpy()) and to hardcode the format string in every printf-family call. Today's lab uses strncat (the bounded form) rather than strcat specifically because of this rule. The full standard lives in the course Resources section.
Up to now you have used basic specifiers like %d and %f. Today we add control over how the value gets formatted: minimum width, decimal precision, and padding behavior. The full specifier looks like this:
- left-aligns; 0 pads numbers with zeros instead of spaces; + forces a sign.d, f, s, c, etc.
Examples that illustrate each piece:
| Format string and value | Output (dots = spaces) | What changed |
|---|---|---|
| printf("%d", 42); | 42 | Baseline. |
| printf("%5d", 42); | ...42 | Width 5, right-aligned by default. |
| printf("%-5d", 42); | 42... | Left-aligned with - flag. |
| printf("%05d", 42); | 00042 | Zero-padded with 0 flag. |
| printf("%f", 3.14159); | 3.141590 | Default 6 decimal places. |
| printf("%.2f", 3.14159); | 3.14 | Precision 2: rounded to 2 decimals. |
| printf("%8.2f", 3.14159); | ....3.14 | Width 8, precision 2. |
| printf("%10s", "VIPER"); | .....VIPER | Right-aligned in a 10-wide field. |
| printf("%-10s", "VIPER"); | VIPER..... | Left-aligned with -. |
| printf("%.3s", "VIPER"); | VIP | Precision on a string truncates. |
Useful for: aligning columns of data, padding numeric IDs with leading zeros, controlling decimal places in reports, fitting strings into fixed-width fields. The printf walkthrough in Section 5 lets you experiment with each piece live.
Three things to do in class. Use the checklist to track your progress.
Twelve tasks across four sections. Type each C statement at the prompt. The terminal shows what the runtime did; the right pane shows each character of each array, with the NUL terminator highlighted.
Enter your name. It will appear on the completion screen so you can include it in your screenshot for the Lesson 10 reflection.
Ten tasks across four sections. Type printf calls and watch the output appear with a column ruler so you can count positions exactly.
Enter your name. It will appear on the completion screen so you can include it in your screenshot for the Lesson 10 reflection.