What would you like to learn?

Try PowerShell, networks, XSS, or Step 138

Browse the full curriculum →

C · Systems · Pwn

Step 57. C Control Flow and Functions — Same Thinking, Different Notation

Step 57Estimated practice · 4 hours

Level 1 — Programming and the Computer’s Inner Workings | Difficulty ★★★☆☆ | Estimated time: 4 hours

Prerequisites: Step 56 complete. You can compile with gcc and use printf/scanf.

  • What you need: a Linux terminal, gcc.
  • Caution: every exercise today is creating, translating, and running files inside your own computer. 100% safe.

Good news first. C’s control flow (if, for, while) thinks exactly like Python. If the condition is true, it runs; it loops a set number of times; it loops while a condition holds. That flow from Step 43. The only thing that changes is the notation — braces instead of indentation, a three-part for instead of range.

Same story for functions. The idea of a component that takes input and returns a result is unchanged from Step 44. But C is a language "read from top to bottom," so it adds one courtesy: you must introduce a function before you use it. And today’s highlight — a strange phenomenon that never happened in Python: we trigger integer overflow ourselves. Today you see with your own eyes why it is the seed of vulnerabilities.


1. Learning Objectives

By the end of this chapter, you will be able to:

  • Write C’s if, for, and while by matching them to their Python counterparts
  • Read and write the three-part for and increment/decrement shorthand like i++ and n–
  • Write functions split into declaration and definition, and explain what #include does
  • Know the switch-and-break trap (forget break and execution spills downward)
  • Trigger integer overflow yourself and explain why it is dangerous

2. Background Knowledge — Today’s Tools and Concepts

Today’s Tools at a Glance

Category Details
Language/environment C language, Linux terminal, gcc -Wall (verified: Ubuntu 13.3.0)
Today’s syntax if / else if / else, for (start; condition; increment), while, switch / case / break, function declarations and definitions, #include <limits.h>
Concepts needed Brace blocks, separating declaration from definition, void, the range of int and integer overflow

2-1. From Indentation to Braces, from range to the Three-Part for

Python uses indentation to mark "how far the if’s contents go." C uses braces {}. if (condition) { ... }. Indentation is decoration for humans; the compiler only sees braces. Still, indenting for readability is a worldwide convention.

C’s for looks like this: for (int i = 0; i < 10; i++). The three parts, in order, are "starting value; condition to keep going; thing to do at the end of each lap." i++ is shorthand for "increase i by 1." It corresponds exactly to Python’s for i in range(10).

2-2. Declaration and Definition — Introducing in Advance

The C compiler reads from top to bottom. So if you call a function defined lower down from a spot above it, it warns, "I don’t know that function." The fix is to write a one-line introduction (a declaration) up top. int add(int a, int b); — a preview saying "a function of this shape appears later," while the actual content (the definition) goes below.

Here’s where the connection completes: #include <stdio.h> was pulling in the file (the header) containing printf’s declarations all along.

2-3. Integer Overflow — The Moment the Box Spills

Python’s integers grow their box automatically. Any number, however big, fits. C’s int is a fixed-size box (usually up to about 2.1 billion). What happens when you add 1 to that box’s maximum? No error, no warning — the value drops straight to the minimum (about -2.1 billion). Like a clock rolling from 12 back to 1.

This is integer overflow, the classic phenomenon that "makes the computer quietly lie." Today we trigger it ourselves.


3. Follow Along

3-1. if — Conditional Branching

Input (grade.c)

#include <stdio.h>

int main(void) {
    int score;
    printf("Enter a score: ");
    scanf("%d", &score);

    if (score >= 90) {
        printf("It's an A.n");
    } else if (score >= 80) {
        printf("It's a B.n");
    } else {
        printf("It's a C.n");
    }
    return 0;
}

Compile and run

gcc -Wall grade.c -o grade
./grade
Enter a score: 85
It's a B.

(Verified 2026-09-09. The 85 is keyboard input.)

How to read it: the structure is the same as Python’s if/elif/else — only the parentheses around the condition and the braces around the body are new. else if is Python’s elif.

Predict: what if you enter 90? What about 79? Predict each, then run to check. The habit of testing boundary values — the very one you learned in Step 54.

3-2. for — The Sum from 1 to 100

Input (sum100.c)

#include <stdio.h>

int main(void) {
    int total = 0;
    for (int i = 1; i <= 100; i++) {
        total = total + i;
    }
    printf("Sum: %dn", total);
    return 0;
}

Compile and run

gcc -Wall sum100.c -o sum100
./sum100
Sum: 5050

(Verified 2026-09-09.)

How to read it: for (int i = 1; i <= 100; i++) means "start i at 1; while i is 100 or less; increase i by 1 each lap." The three parts handle start, condition, and increment respectively. It’s the exact same idea as Python’s range(1, 101) written in different notation — not new grammar, just translation practice.

3-3. Making Functions — Declaration and Definition

Input (funcs.c)

#include <stdio.h>

int add(int a, int b);
int square(int n);
void cheer(char name[]);

int main(void) {
    printf("3 + 5 = %dn", add(3, 5));
    printf("7 squared = %dn", square(7));
    cheer("Lee");
    return 0;
}

int add(int a, int b) {
    return a + b;
}

int square(int n) {
    return n * n;
}

void cheer(char name[]) {
    printf("%s, you're doing great!n", name);
}

Compile and run

gcc -Wall funcs.c -o funcs
./funcs
3 + 5 = 8
7 squared = 49
Lee, you're doing great!

(Verified 2026-09-09.)

How to read it: the three lines up top are declarations (introductions), the ones below are definitions (content), and main calls them in between. The int before a function name means "a function that returns an integer," and void marks a function that "returns nothing." Delete the declarations and compile, and a warning appears — the verified message is in Wall 2.

3-4. Overflow — Spilling the Box

Input (overflow.c)

#include <stdio.h>
#include <limits.h>

int main(void) {
    int big = INT_MAX;
    printf("int maximum: %dn", big);
    printf("Add 1 to it: %dn", big + 1);
    return 0;
}

Compile and run

gcc -Wall overflow.c -o overflow
./overflow
int maximum: 2147483647
Add 1 to it: -2147483648

(Verified 2026-09-09.)

How to read it: INT_MAX, written in limits.h, is the int box’s maximum: 2,147,483,647 (about 2.1 billion). Add 1 and, with no error or warning, it became -2,147,483,648. The clock hand completed one full turn. The computer raised no objection at all. It quietly lied.

Predict: what happens if you subtract 1 from the minimum (INT_MIN)? Predict with the clock-hand analogy, then modify the code to check. (Verified: after int minimum: -2147483648, the next line shows Subtract 1 from it: 2147483647 — one full turn in the opposite direction.)

Why: why this quiet lie is dangerous gets organized in section 7. Today’s output is the most expensive screen in this chapter.

3-5. while — While the Condition Holds

Input (countdown.c)

#include <stdio.h>

int main(void) {
    int n = 5;
    while (n > 0) {
        printf("%d...n", n);
        n--;
    }
    printf("Blast off!n");
    return 0;
}

Compile and run

gcc -Wall countdown.c -o countdown
./countdown
5...
4...
3...
2...
1...
Blast off!

(Verified 2026-09-09.)

How to read it: n-- means "decrease n by 1." It loops while the condition (n > 0) is true and exits when it becomes false. Delete n-- and the condition stays true forever — an infinite loop. To stop it, Ctrl+C. Same principle as Python.

3-6. switch — When There Are Many Forks

If if is a door that splits in two, when there are many forks there is also a dedicated statement: switch.

Input (menu.c)

#include <stdio.h>

int main(void) {
    int menu;
    printf("Choose a menu (1-3): ");
    scanf("%d", &menu);

    switch (menu) {
        case 1:
            printf("Viewing the file list.n");
            break;
        case 2:
            printf("Opening settings.n");
            break;
        case 3:
            printf("Exiting.n");
            break;
        default:
            printf("No such menu.n");
    }
    return 0;
}

Compile and run

gcc -Wall menu.c -o menu
./menu
Choose a menu (1-3): 2
Opening settings.

(Verified 2026-09-09.)

How to read it: case means "if it’s this value, go here," and default means "if it’s none of the cases." The important part here is break. Remove the break and, after running that case, execution spills through the following cases in a row. Verified: delete case 2’s break and enter 2, and Opening settings. was followed by Exiting. One of C’s classic traps.


4. Missions & Exercises

Mission — Number Guessing Game

Today’s work of art: build a number guessing game in C.

  1. Fix an answer between 1 and 50 in the code (e.g., 37).
  2. Write a compare function that tells the user "higher/lower" when they enter a number.
  3. Loop with while until they guess it, counting the attempts.
  4. When they guess right, print a congratulatory message like "Correct in 7 tries!" with a celebrate function.
  5. Complete it with at least two functions, with declarations and definitions separated.
  6. Bonus: for out-of-range input like 0 or 100, show a hint like "Please enter a number between 1 and 50."

Exercises

Problem 1. State the difference between if (score = 90) and if (score == 90), and explain how the program behaves if you write the former.

Problem 2. If you defined a function below main in C, what must you write up top and why? And how does #include <stdio.h> connect to this?

Problem 3. State what each of the three parts of for (int i = 1; i <= 100; i++) means, and write the Python code that does exactly the same thing as this one line.

Problem 4. Explain why integer overflow happens with no error or warning, and give one example of how it can be abused as "a lie that passes the check."


Answers & completion criteria · expand/collapse

5. Model Answers & Completion Criteria

Mission Model Answer

#include <stdio.h>

int compare(int answer, int guess);
void celebrate(int tries);

int main(void) {
    int answer = 37;
    int guess;
    int tries = 0;

    printf("Number guessing (1-50)n");
    while (1) {
        printf("Enter a number: ");
        scanf("%d", &guess);
        tries++;
        if (guess < 1 || guess > 50) {
            printf("Please enter a number between 1 and 50n");
            continue;
        }
        if (compare(answer, guess) == 0) {
            break;
        }
    }
    celebrate(tries);
    return 0;
}

int compare(int answer, int guess) {
    if (guess > answer) {
        printf("Lowern");
        return 1;
    } else if (guess < answer) {
        printf("Highern");
        return 1;
    }
    return 0;
}

void celebrate(int tries) {
    printf("Correct in %d tries!n", tries);
}

Run (verified 2026-09-09, input in the order 25 → 42 → 37)

Number guessing (1-50)
Enter a number: 25
Higher
Enter a number: 42
Lower
Enter a number: 37
Correct in 3 tries!

How to verify: ① while (1) is a loop that runs forever, structured to escape with break when the answer is right. ② Check that out-of-range input (0, 51) shows the guidance message. ③ Compile with -Wall and there must be no warnings. You can confirm the need for declarations yourself: write functions only below main, omit the declarations, and a warning appears (Wall 2).

Exercise Answers

Problem 1 answer. = is "put in" (assignment), == is "is it equal" (comparison). if (score = 90) puts 90 into score and then uses that value (90) as the condition. Since C treats any non-zero value as true, the condition is always true. In testing, this code printed "It’s an A." even when score was 70, and -Wall warned: warning: suggest parentheses around assignment used as truth value.

Problem 2 answer. You write a one-line declaration up top (e.g., int add(int a, int b);). Because the C compiler reads from top to bottom, if you don’t introduce a function defined below in advance, it warns about an "unknown function." #include <stdio.h> pulls in a header file containing the declarations of standard functions like printf — it does for you the same job as the declarations we wrote by hand.

Problem 3 answer. The three parts are, in order: starting value (i starts at 1), condition to keep going (while i is 100 or less), and thing to do at the end of each lap (increase i by 1). The Python equivalent is for i in range(1, 101):.

Problem 4 answer. Because C does not check whether a calculation result exceeds the box — the price of a design that "trusts the programmer." A spilled value quietly continues after one full turn toward the minimum. An abuse example: in code that checks "is balance + deposit within the limit," an attacker who enters a huge amount can wrap the sum around one full turn, and the check passes in an unintended way. At the root of incidents like game-item duplication and amount bypasses lies this phenomenon.

Completion Criteria Checklist

  • [ ] I can explain C’s if/for/while by matching them to Python
  • [ ] I know what the three-part for and i++, n– mean
  • [ ] I can write functions with declarations and definitions separated
  • [ ] I know what happens if you omit break in a switch
  • [ ] I can trigger integer overflow myself and explain it
  • [ ] I completed the number guessing game with at least two functions

6. Common Pitfalls & Fixes

Wall 1. Confusing = and ==

Symptom: you wrote if (score = 90) and the condition behaves as if always true. Compile with -Wall and it tells you this (verified 2026-09-09):

assign.c:5:9: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
    5 |     if (score = 90) {
      |         ^~~~~

Cause: = is assignment, == is comparison. The assignment’s resulting value, 90, is treated as true.
Fix: use == in comparison spots. And always keep -Wall on — the compiler asks you, "Did you really mean that?"

Wall 2. Forgetting the Function Declaration

Symptom: you wrote a function only below main and compiled (verified 2026-09-09):

nodecl.c:4:20: warning: implicit declaration of function 'add' [-Wimplicit-function-declaration]
    4 |     printf("%dn", add(3, 5));
      |                    ^~~

Cause: C reads from top to bottom, and you didn’t introduce the lower function in advance.
Fix: write a one-line declaration at the top of the file. Or place the whole function above main. The convention is to put declarations up top.

Wall 3. Trapped in an Infinite Loop

Symptom: the program never ends and keeps spitting out the same thing.
Cause: the loop condition stays true forever. Most of the time you forgot the increment (n++, n--).
Fix: stop it with Ctrl+C, then trace by hand "when does the condition become false." The first question in loop design is not "what do I repeat" but "how does it end."

Wall 4. Expecting Overflow to Be an Error

Symptom: big-number math comes out wrong, but there’s no error, so you can’t find the cause.
Cause: overflow is not an error but a quiet full turn. In the 3-4 verification, even -Wall said nothing.
Fix: remember int’s range (about ±2.1 billion), and when handling big numbers consider long long (a bigger box). "No error doesn’t mean correct" is common sense in the C world.

Wall 5. Omitting break in a switch

Symptom: you picked one menu item, but the next item’s action also runs in a row. Verified: delete case 2’s break, enter 2, and Exiting. printed right after Opening settings.
Cause: without break, execution "falls through" to the next case.
Fix: write break at the end of each case. There is an advanced technique that intentionally falls through, but at the beginner stage, engrave "break is the default."


7. Summary

Today’s Concepts

Concept One-line explanation
Brace blocks The spot where Python had indentation — { } marks the range
Declaration vs definition A one-line introduction up top vs the actual content below
void Marks a function with nothing to return
break The plug that ends a switch case right there
Integer overflow The phenomenon where a spilled value quietly wraps around one full turn

Today’s Syntax

Syntax What it does
if / else if / else Conditional branching (corresponds to Python’s if/elif/else)
for (int i = 0; i < 10; i++) Three-part loop: start; condition; increment
while (condition) Loop while the condition is true
switch / case / default Branching when there are many forks (break required)
int add(int a, int b); Function declaration — "a function like this appears later"
#include <limits.h> Pull in the header with limit values like INT_MAX

A Sense More Important Than Syntax

In two days, you’ve come to write control flow and functions in C. The secret is that you already knew programming — conditions, loops, and functions are not a language but a way of thinking, and you already trained that way of thinking in Python. That the way of thinking stays the same even when the language changes is today’s biggest harvest.

And remember the overflow screen. The moment you add 1 to the maximum and it becomes negative with no objection — a textbook of the techniques that make computers quietly lie. There’s a reason most famous vulnerabilities trace their hometown back to C. C is a language that trusts the programmer, so the spot where that trust breaks is exactly the spot where incidents happen. Little by little, your eyes for seeing memory are opening.


Once every box is checked, Step 57 is complete.

ONE STEP FURTHER

Finished this lesson?

Check the completion criteria, then mark your progress.

Something wrong with this page or a link? Let us know.
Next