CS210 · Block 2 · Lesson 10

C Strings

Null-terminated character arrays · string.h · Format specifier control
At a glance: A C string is just an array of characters with a zero byte at the end. That one design choice shapes everything you do with strings: how you measure them, copy them, compare them, and how easy it is to wreck them. Today you build a real mental model of what a string looks like in memory, learn the five most important functions in <string.h>, and pick up the printf format controls that let you produce clean output.
Contents
  1. Lesson Objectives
  2. Assigned Readings
  3. Pre-Class Work
  4. Lesson Materials and Overview
  5. In-Class Work
  6. After Class
1. Lesson Objectives

By the end of this lesson, cadets will be able to:

  1. Manipulate C strings as null-terminated character arrays. (Outcome 2)
  2. Apply standard library string functions from <string.h> to common string tasks. (Outcome 2)
  3. Format printed output using precision, width, and padding specifiers. (Outcomes 2, 7)
2. Assigned Readings

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
Heads-up on Beej Chapter 7: Beej leads with 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.
3. Pre-Class Work
Do this first
Plan on 30 to 40 minutes for the reading and warmup. Most of the work happens during the in-class walkthroughs; come with the vocabulary ready.

Pre-Class Checklist

1
Read Beej-C Chapter 7
It is short. Pay particular attention to:
  • The NUL terminator ('\0') and why it matters
  • The difference between a string literal and a char[] initialized from one
  • Why = does not copy a string
  • strlen and strcpy
2
Skim the <string.h> reference
In the Beej-Lib reference, look up the signatures of these five functions. You do not need to memorize them, but the in-class walkthrough will use all five:
  • strlen
  • strcpy, strncpy
  • strcmp
  • strcat, strncat
Reading function signatures fluently is itself a skill. It will pay off every lesson from here on.
3
Warmup: count the bytes, then predict
Part A. For each of the following, write down how many bytes the array uses. Bring your answers to class.
char a[] = "hi";
char b[] = "";
char c[10] = "abc";
char d[] = {'h', 'i'};
Hint: every C string ends with a NUL byte. Three of the four above contain one.
Part B. Predict what each of the two printf calls below prints. Write your predictions down, then check yourself in the in-class playground.
printf("|%5d|\n", 42);
printf("|%-5d|\n", 42);
Click for the answer
|   42|
|42   |
The pipes make the width visible. %5d pads on the left; %-5d pads on the right.
Why predict-then-check? Reading code and predicting output is the cheapest debugging tool you have. We'll use this habit throughout the course.
4. Lesson Materials and Overview

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.

Jump to
Slides What is a string NUL terminator Declaring strings string.h functions Format control

Slides

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.

Open Lesson 10 slides →

What is a string, really?

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.

The NUL terminator

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:

[0]
[1]
[2]
'h'
'i'
'\0'
Three bytes: two visible characters and one NUL terminator.

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.

Declaring strings: char[] form

In this course, we declare strings as character arrays. There are three common ways:

// 1. Let the compiler size it for you
char name[] = "Bolton";  // 7 bytes: 6 chars + NUL

// 2. Specify a size with room to grow
char username[32];   // 32 bytes; contents uninitialized
strncat(username, "jbolton", 31); // safe append

// 3. Specify a size with an initializer
char badge[8] = "N1234"// 8 bytes, "N1234\0..." (rest is zero)

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.

A note about Beej's pointer form
Beej Chapter 7 also shows 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.

The five functions you need from <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:

char display[32] = "";  // 32 bytes, all zero
strncat(display, "jbolton", 31);  // display = "jbolton"
strncat(display, " (", 31 - strlen(display)); // display = "jbolton ("
strncat(display, "RUN)", 31 - strlen(display));
printf("%s\n", display);
// prints: jbolton (RUN)

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.

printf format control: width, precision, and padding

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:

%[flags][width][.precision]conversion
flags — optional. - left-aligns; 0 pads numbers with zeros instead of spaces; + forces a sign.
width — optional. Minimum number of characters to print. Pads with spaces if the value is shorter.
precision — optional. For floats: digits after the decimal. For strings: maximum characters to print.
conversion — required. 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.

5. In-Class Work

Three things to do in class. Use the checklist to track your progress.

  • Work through the string anatomy walkthrough below. Twelve guided tasks that visualize char arrays, the NUL terminator, and the five string.h functions byte by byte. About 25 minutes.
  • Work through the printf format playground. Ten guided tasks practicing width, precision, padding, and alignment. About 20 minutes.
  • Complete Lab 10: Fitness Tracker Daily Summary. Auto-graded through GitHub Classroom. Full instructions in the lab repo.

String Anatomy Walkthrough

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.

Before you begin

Enter your name. It will appear on the completion screen so you can include it in your screenshot for the Lesson 10 reflection.

CS210 Lesson 10 · String Anatomy Walkthrough

A guided tour through C strings: arrays of characters, the NUL terminator, and the five string.h functions. Type each C statement on the input line. The terminal echoes what happened; the right pane shows each character of each array.
Task 0 of 12
Section 1: Anatomy of a string
Current task
Loading...
String memory
No strings declared yet.
Type a declaration on the left.
strmem>
How this works: This is a teaching tool that simulates what happens to char arrays in memory. The task card tells you what to type next; only the expected command will advance the walkthrough so the memory state stays predictable. Mistype twice and the hint button will pulse. After the walkthrough completes, free mode unlocks automatically so you can experiment.

printf Format Playground

Ten tasks across four sections. Type printf calls and watch the output appear with a column ruler so you can count positions exactly.

Before you begin

Enter your name. It will appear on the completion screen so you can include it in your screenshot for the Lesson 10 reflection.

CS210 Lesson 10 · printf Format Playground

A guided tour through printf format control: width, precision, padding, and alignment. Each task shows you the exact output you must produce. Type a printf call that matches.
Task 0 of 10
Section 1: Width and alignment
Current task
Loading...
Stdout
Nothing printed yet.
Type a printf call on the left.
pfmt>
How this works: The right pane shows what printf would print, with a column ruler so you can count positions exactly. Padding spaces are rendered as faint dots so you can see them. Match the target output exactly, including the line of dots. Mistype twice and the hint button will pulse. After the walkthrough completes, free mode unlocks so you can experiment with any format.
6. After Class
  • Finish Lab 10 if you did not complete it in class. Submit through GitHub Classroom before Lesson 11.
  • Complete the Lesson 10 reflection in Blackboard (widget codes + short essay).
  • Read the supplementary notes for Lesson 11 (Recursion I, instructor-written).
  • Replay either walkthrough in free mode. Try strings with embedded NULs, oversized strcpy targets, and strange format specifiers.
  • Heads up: Quiz 3 in the next class meeting covers Lesson 9 (arrays) only, per the rule that quizzes never assess day-of content. Today's content (strings, string.h, printf format control) carries forward to the GR2 midterm at Lesson 17.
Need help? Schedule EI with your instructor. Bring specific code or specific screenshots, and the exact error message or output you do not understand. Specific questions get unstuck quickly.