โ† All units

๐ŸŽค Unit 2 ยท Input & Output Statements

How a C program listens, thinks, decides and repeats

๐Ÿ—บ๏ธ What's in this unit?

Think of a program as a robot shopkeeper:

๐Ÿ‘‚ Input
listens to you (scanf, getchar, fgets)
๐Ÿงฎ Expressions & assignment
does maths and stores answers (total = a + b;)
๐Ÿค” Decisions
chooses what to do (if, else, switch)
๐Ÿ” Loops
repeats work (for, while, do-while)
๐Ÿ—ฃ๏ธ Output
tells you the answer (printf, puts, putchar)
๐Ÿงฐ Preprocessor & compiler
gets the program ready to run

Every program here is in this folder. To run one: gcc 05_if_and_if_else.c -o prog and then ./prog

1๏ธโƒฃ Expressions & type conversion

You buy 3 ice creams at Rs 25 each and pay Rs 100. The computer works out 3 * 25 and 100 - 75. Each of those little maths sentences is an expression.

An expression is a mix of values (operands) and signs (operators) that gives one answer.

KindExampleAnswer
Arithmetic3 * 2575
Relational (compare)75 < 1001 (true)
Logicalhungry && hasMoney1 if both are true
Assignmenttotal = 75puts 75 in total
Conditionala > b ? a : bthe bigger one

Type conversion: changing the kind of number

Implicit (automatic)
C does it by itself. Small type is lifted to big type.
5 + 1.5 โ†’ 6.5 (int became float)
Order: char โ†’ int โ†’ long โ†’ float โ†’ double
Explicit (casting)
You force it with (type).
(float)7 / 2 โ†’ 3.5
(int)36.9 โ†’ 36 (cut off, not rounded)
๐Ÿงช Try it: int division vs float division
รท

  
An expression combines operands and operators to give one value. Implicit conversion is done automatically by the compiler (lower type is promoted to higher type). Explicit conversion (type casting) is done by the programmer using (type) expression, e.g. (float)a/b.

File: 01_expressions_type_conversion.c

/*
 * Program 1: Expressions and Type Conversion
 * ------------------------------------------
 * Real-life story: You buy 3 ice creams at Rs 25 each and pay with Rs 100.
 * An EXPRESSION is a little maths sentence the computer solves,
 * like  3 * 25  or  100 - total.
 *
 * Type conversion = changing one kind of number into another.
 *   Implicit (automatic): C changes it by itself  (int + float -> float)
 *   Explicit (casting)  : YOU tell C to change it  (float) a
 */
#include <stdio.h>

int main() {
    int iceCreams = 3;
    int price = 25;
    int paid = 100;

    /* Arithmetic expression */
    int total = iceCreams * price;           /* 3 * 25 = 75 */
    int change = paid - total;               /* 100 - 75 = 25 */
    printf("Total = %d, Change = %d\n", total, change);

    /* Relational expression: answer is 1 (true) or 0 (false) */
    printf("Is total less than paid? %d\n", total < paid);

    /* Logical expression: && means AND, || means OR, ! means NOT */
    int hungry = 1, hasMoney = 1;
    printf("Can I buy food? %d\n", hungry && hasMoney);

    /* Precedence: * happens before +, just like in school maths */
    printf("2 + 3 * 4 = %d\n", 2 + 3 * 4);       /* 14, not 20 */
    printf("(2 + 3) * 4 = %d\n", (2 + 3) * 4);   /* brackets go first: 20 */

    /* Implicit conversion: int + float becomes float automatically */
    int apples = 5;
    float weight = 1.5;
    float mixed = apples + weight;
    printf("\nImplicit: 5 + 1.5 = %.1f\n", mixed);

    /* Problem: int / int throws away the decimal part */
    int marks = 7, subjects = 2;
    printf("Without cast: 7 / 2 = %d\n", marks / subjects);

    /* Explicit conversion (casting): turn marks into float first */
    printf("With cast   : 7 / 2 = %.2f\n", (float)marks / subjects);

    /* float to int cuts off the decimal part (it does NOT round) */
    float temperature = 36.9;
    printf("(int)36.9 = %d\n", (int)temperature);

    /* char is secretly a number (ASCII) */
    char letter = 'A';
    printf("'A' as a number = %d, 'A' + 1 = %c\n", letter, letter + 1);

    return 0;
}

Output

Total = 75, Change = 25
Is total less than paid? 1
Can I buy food? 1
2 + 3 * 4 = 14
(2 + 3) * 4 = 20

Implicit: 5 + 1.5 = 6.5
Without cast: 7 / 2 = 3
With cast   : 7 / 2 = 3.50
(int)36.9 = 36
'A' as a number = 65, 'A' + 1 = B

2๏ธโƒฃ printf and scanf

A school ID-card machine asks your name, age and height, then prints your card.

printf = print something on the screen. scanf = scan (read) what you type. Both are formatted I/O functions from <stdio.h>. They use format specifiers as blanks to fill.

SpecifierTypeExample value
%d or %iint42
%ffloat3.140000
%lfdouble (in scanf)3.14159
%ccharA
%sstringRavi
%uunsigned int40000
%ldlong1234567890
%x / %ohex / octalff / 377
%escientific3.14e+00
%%a percent sign%
In scanf you must put & before normal variables (&age). & means "the address of the box", so scanf knows where to put the value. Strings like name don't need &.

Escape sequences (special letters inside " ")

CodeMeaning
\nnew line (press Enter)
\ttab (big space)
\\a backslash
\"a double quote
\abeep sound
๐Ÿงช Try it: field width playground
Number: Format:

    The [ ] brackets show you exactly how many spaces are used.
  
printf("control string", var-list); displays output. scanf("control string", &var-list); reads input. The control string contains format specifiers (%d, %f, %c, %s), and the number of specifiers must match the number of variables. A field width like %8.2f means 8 places in total with 2 after the decimal point.

File: 02_printf_scanf.c

/*
 * Program 2: printf and scanf (Talking to the user)
 * -------------------------------------------------
 * Real-life story: A school ID card machine.
 * It ASKS your name, age and height (scanf = input)
 * and then PRINTS your ID card (printf = output).
 *
 * Format specifiers = blanks to fill:
 *   %d  int      %f  float     %c  char
 *   %s  string   %lf double    %x  hexadecimal
 *
 * Sample input:  Ravi 10 4.5 A
 */
#include <stdio.h>

int main() {
    char name[20];
    int age;
    float height;
    char section;

    printf("Enter name, age, height and section: ");
    scanf("%s %d %f %c", name, &age, &height, &section);
    /* & means "the address of the box" so scanf can put the value inside.
       Arrays (like name) don't need & */

    printf("\n");
    printf("+--------------------------+\n");
    printf("|     SCHOOL ID CARD       |\n");
    printf("+--------------------------+\n");
    printf("| Name    : %-14s |\n", name);   /* %-14s = 14 spaces wide, left side */
    printf("| Age     : %-14d |\n", age);
    printf("| Height  : %-14.1f |\n", height); /* .1 = only 1 digit after dot */
    printf("| Section : %-14c |\n", section);
    printf("+--------------------------+\n");

    /* Field width tricks */
    printf("\nField width demo:\n");
    printf("[%5d]  number in 5 spaces, right side\n", 42);
    printf("[%-5d]  number in 5 spaces, left side\n", 42);
    printf("[%05d]  fill empty spaces with zeros\n", 42);
    printf("[%8.2f]  8 wide, 2 after the dot\n", 3.14159);
    printf("[%x]  255 in hexadecimal\n", 255);
    printf("100%%  <- use %%%% to print a percent sign\n");

    return 0;
}

You type

Ravi 10 4.5 A

Output

Enter name, age, height and section: 
+--------------------------+
|     SCHOOL ID CARD       |
+--------------------------+
| Name    : Ravi           |
| Age     : 10             |
| Height  : 4.5            |
| Section : A              |
+--------------------------+

Field width demo:
[   42]  number in 5 spaces, right side
[42   ]  number in 5 spaces, left side
[00042]  fill empty spaces with zeros
[    3.14]  8 wide, 2 after the dot
[ff]  255 in hexadecimal
100%  <- use %% to print a percent sign

3๏ธโƒฃ getchar, putchar, fgets, puts

A walkie-talkie: sometimes you send just one letter, sometimes a whole sentence.
FunctionDoes whatKind
getchar()reads ONE characterUnformatted input
putchar(c)prints ONE characterUnformatted output
fgets(str, size, stdin)reads a whole line, spaces too, safelyUnformatted input
puts(str)prints a string plus a new lineUnformatted output
gets(str) โŒreads a line but can overflow. Removed from C11Don't use
scanf("%s", name) stops at the first space. Typing "Ravi Kumar" gives only "Ravi". Use fgets for full names and sentences.
After getchar() or scanf(), the Enter key is still waiting in the input. That's why the program calls an extra getchar() to "eat" it.
Formatted I/O (printf, scanf) uses format specifiers. Unformatted I/O (getchar, putchar, gets, puts, fgets) works with characters or strings directly, with no format specifiers.

File: 03_getchar_putchar_fgets_puts.c

/*
 * Program 3: getchar, putchar, fgets, puts
 * ----------------------------------------
 * Real-life story: A walkie-talkie.
 *   getchar() = listen to ONE letter
 *   putchar() = say ONE letter
 *   fgets()   = listen to a WHOLE sentence (with spaces!)
 *   puts()    = say a whole sentence and go to the next line
 *
 * Why not gets()? gets() does not know how big your box is.
 * If someone types too much, it overflows (spills) and breaks things.
 * It was REMOVED from C. Always use fgets() instead.
 *
 * Sample input:
 *   y
 *   I love C programming
 */
#include <stdio.h>

int main() {
    char answer;
    char sentence[50];

    printf("Do you like ice cream? (y/n): ");
    answer = getchar();            /* reads one character */
    getchar();                     /* eats the Enter key left behind */

    printf("You pressed: ");
    putchar(answer);               /* prints one character */
    putchar('\n');

    printf("Type a sentence: ");
    fgets(sentence, sizeof(sentence), stdin);  /* reads the whole line, safely */

    printf("You said: ");
    puts(sentence);                /* puts adds its own new line.
                                      fgets also keeps your Enter key,
                                      so you see one empty line after it */

    /* puts with a fixed message */
    puts("Over and out!");

    return 0;
}

You type

y
I love C programming

Output

Do you like ice cream? (y/n): You pressed: y
Type a sentence: You said: I love C programming

Over and out!

4๏ธโƒฃ Assignment statements

Your video-game score keeps changing: +5 for a coin, -3 for a monster, ร—2 for a power-up.

In C, = does not mean "is equal to". It means "put the right side into the box on the left". To compare two things, use ==.

Short wayLong wayscore was 10, now it is
score += 5score = score + 515
score -= 3score = score - 37
score *= 2score = score * 220
score /= 4score = score / 42
score %= 4score = score % 42
๐ŸŽฎ Try it: score machine
Score = 10

  
x++ vs ++x: y = x++ gives y the old value, then adds 1 ("use, then add"). y = ++x adds 1 first, then gives it to y ("add, then use").
An assignment statement stores a value in a variable: variable = expression;. Kinds: simple (=), compound (+= -= *= /= %=), multiple (a = b = c = 0;, evaluated right to left), and increment/decrement (++ --, prefix and postfix).

File: 04_assignment_statements.c

/*
 * Program 4: Assignment Statements
 * --------------------------------
 * Real-life story: Your game score.
 * = means "PUT this value in the box" (it does NOT mean "equals" like maths).
 *
 *   score = 10;      put 10 in score
 *   score += 5;      same as score = score + 5
 *   score -= 3;      same as score = score - 3
 *   score *= 2;      same as score = score * 2
 *   score /= 4;      same as score = score / 4
 *   score %= 4;      same as score = score % 4
 */
#include <stdio.h>

int main() {
    int score;

    score = 10;                 /* simple assignment */
    printf("Start            : %d\n", score);

    score += 5;                 /* found a coin */
    printf("score += 5       : %d\n", score);

    score -= 3;                 /* hit by a monster */
    printf("score -= 3       : %d\n", score);

    score *= 2;                 /* double-points power-up */
    printf("score *= 2       : %d\n", score);

    score /= 4;                 /* shared with 4 teammates */
    printf("score /= 4       : %d\n", score);

    score %= 4;                 /* remainder after groups of 4 */
    printf("score %%= 4       : %d\n", score);

    /* Multiple assignment: right to left, all get the same value */
    int a, b, c;
    a = b = c = 7;
    printf("\na = b = c = 7 -> a=%d b=%d c=%d\n", a, b, c);

    /* Increment and decrement */
    int lives = 3;
    lives++;                    /* got an extra life: 4 */
    printf("lives++          : %d\n", lives);
    lives--;                    /* lost a life: 3 */
    printf("lives--          : %d\n", lives);

    /* Pre vs Post increment */
    int x = 5;
    int y = x++;    /* y gets OLD x (5), then x becomes 6 */
    printf("\ny = x++ -> y=%d, x=%d\n", y, x);
    x = 5;
    y = ++x;        /* x becomes 6 FIRST, then y gets 6 */
    printf("y = ++x -> y=%d, x=%d\n", y, x);

    return 0;
}

Output

Start            : 10
score += 5       : 15
score -= 3       : 12
score *= 2       : 24
score /= 4       : 6
score %= 4       : 2

a = b = c = 7 -> a=7 b=7 c=7
lives++          : 4
lives--          : 3

y = x++ -> y=5, x=6
y = ++x -> y=6, x=6

5๏ธโƒฃ Decision making: if and if-else

At the roller-coaster gate: IF you are at least 120 cm tall, you ride. ELSE, you go to the merry-go-round.
Simple if
if (age >= 18) {
    printf("Vote!");
}
One choice: do it or skip it.
if-else
if (height >= 120) {
    printf("Ride");
} else {
    printf("Merry-go-round");
}
Two choices: always picks exactly one.

Comparison signs (relational operators)

SignMeansSignMeans
==equal to!=not equal to
>greater than<less than
>=greater or equal<=less or equal
๐ŸŽข Try it: roller-coaster gate
Height (cm):

  
A common mistake is writing if (x = 5). That puts 5 into x and is always true. To compare, write if (x == 5).
if: runs a block only when the condition is true. if-else: runs one block if true, another if false. In C, any non-zero value counts as true and 0 is false. The ternary operator cond ? a : b is a short if-else.

File: 05_if_and_if_else.c

/*
 * Program 5: if and if-else
 * -------------------------
 * Real-life story: The roller-coaster gate.
 * "IF you are at least 120 cm tall, you may ride. ELSE, try the merry-go-round."
 *
 *   if (condition) {        -> runs only when condition is true
 *       ...
 *   } else {                -> runs when condition is false
 *       ...
 *   }
 */
#include <stdio.h>

int main() {
    int height = 115;
    int age = 19;
    int number = 7;

    /* Simple if: only one choice */
    if (age >= 18) {
        printf("Age %d: You can vote!\n", age);
    }

    /* if-else: two choices */
    if (height >= 120) {
        printf("Height %d cm: Enjoy the roller-coaster!\n", height);
    } else {
        printf("Height %d cm: Too short, try the merry-go-round.\n", height);
    }

    /* Even or odd: % 2 gives 0 for even numbers */
    if (number % 2 == 0) {
        printf("%d is EVEN\n", number);
    } else {
        printf("%d is ODD\n", number);
    }

    /* Ternary operator: a tiny if-else on one line
       condition ? valueIfTrue : valueIfFalse */
    int a = 12, b = 9;
    int bigger = (a > b) ? a : b;
    printf("Bigger of %d and %d is %d\n", a, b, bigger);

    return 0;
}

Output

Age 19: You can vote!
Height 115 cm: Too short, try the merry-go-round.
7 is ODD
Bigger of 12 and 9 is 12

6๏ธโƒฃ else-if ladder: grade calculator

The teacher checks marks from the top. The first rule that matches gives your grade, and she stops checking.
๐Ÿชœ Try it: climb down the ladder
Marks:
An else-if ladder tests conditions one by one from the top. As soon as one is true, its block runs and the rest are skipped. The final else runs when none are true. Use it when there are many ranges (grades, slabs, age groups).

File: 06_else_if_ladder_grade.c

/*
 * Program 6: else-if ladder (Grade calculator)
 * --------------------------------------------
 * Real-life story: The teacher gives grades.
 * The computer climbs down a ladder and stops at the FIRST step that is true.
 *
 *   90 and above -> O (Outstanding)
 *   80 to 89     -> A+
 *   70 to 79     -> A
 *   60 to 69     -> B
 *   50 to 59     -> C
 *   below 50     -> F (Fail)
 */
#include <stdio.h>

int main() {
    int marks[] = {95, 84, 72, 65, 51, 30};   /* six students */
    int i;

    for (i = 0; i < 6; i++) {
        int m = marks[i];
        char *grade;                          /* holds the grade word */

        if (m >= 90) {
            grade = "O  (Outstanding)";
        } else if (m >= 80) {
            grade = "A+ (Excellent)";
        } else if (m >= 70) {
            grade = "A  (Very good)";
        } else if (m >= 60) {
            grade = "B  (Good)";
        } else if (m >= 50) {
            grade = "C  (Pass)";
        } else {
            grade = "F  (Try again!)";
        }

        printf("Student %d: %3d marks -> Grade %s\n", i + 1, m, grade);
    }

    return 0;
}

Output

Student 1:  95 marks -> Grade O  (Outstanding)
Student 2:  84 marks -> Grade A+ (Excellent)
Student 3:  72 marks -> Grade A  (Very good)
Student 4:  65 marks -> Grade B  (Good)
Student 5:  51 marks -> Grade C  (Pass)
Student 6:  30 marks -> Grade F  (Try again!)

7๏ธโƒฃ Nested if: the ATM

An ATM checks three things in order: is the card in? Is the PIN right? Is there enough money? It only asks the next question if the last answer was yes.

Nested if = an if inside another if. Like boxes inside boxes ๐Ÿ“ฆ.

๐Ÿง Try it

PIN typed: (correct PIN is 1234)
Withdraw: Rs (balance is Rs 5000)

  
A nested if places one if (or if-else) inside another. The inner condition is checked only when the outer condition is true. It's used when decisions depend on earlier decisions, e.g. finding the largest of three numbers.

File: 07_nested_if_atm_pin.c

/*
 * Program 7: Nested if (an if inside an if)
 * -----------------------------------------
 * Real-life story: Taking money from an ATM.
 *   Step 1: Is the card inserted?
 *       Step 2: Is the PIN correct?
 *           Step 3: Is there enough balance?
 * You only check the next step if the previous one was OK.
 */
#include <stdio.h>

int main() {
    int cardInserted = 1;      /* 1 = yes */
    int correctPin = 1234;
    int enteredPin = 1234;
    int balance = 5000;
    int withdraw = 2000;

    if (cardInserted == 1) {
        printf("Card found.\n");

        if (enteredPin == correctPin) {
            printf("PIN correct.\n");

            if (withdraw <= balance) {
                balance = balance - withdraw;
                printf("Please collect Rs %d.\n", withdraw);
                printf("Balance left: Rs %d\n", balance);
            } else {
                printf("Not enough balance!\n");
            }

        } else {
            printf("Wrong PIN!\n");
        }

    } else {
        printf("Please insert your card.\n");
    }

    return 0;
}

Output

Card found.
PIN correct.
Please collect Rs 2000.
Balance left: Rs 3000

8๏ธโƒฃ Real example: electricity bill

Electricity gets costlier the more you use, just like a bigger box of sweets costs more per sweet in a fancy shop.
UnitsRate
0 โ€“ 100Free
101 โ€“ 200Rs 2 per unit
201 โ€“ 500Rs 4 per unit
Above 500Rs 6 per unit
๐Ÿ’ก Try it: your house bill
Units used:

  

File: 08_electricity_bill.c

/*
 * Program 8: Electricity Bill (else-if ladder with slabs)
 * -------------------------------------------------------
 * Real-life story: The more electricity you use, the costlier each unit gets.
 *
 *   First 100 units   -> Rs 0 (free)
 *   101 to 200 units  -> Rs 2 per unit
 *   201 to 500 units  -> Rs 4 per unit
 *   Above 500 units   -> Rs 6 per unit
 */
#include <stdio.h>

int main() {
    int homes[] = {80, 150, 350, 620};
    int i;

    for (i = 0; i < 4; i++) {
        int units = homes[i];
        int bill;

        if (units <= 100) {
            bill = 0;
        } else if (units <= 200) {
            bill = (units - 100) * 2;
        } else if (units <= 500) {
            bill = 100 * 2 + (units - 200) * 4;
        } else {
            bill = 100 * 2 + 300 * 4 + (units - 500) * 6;
        }

        printf("House %d used %3d units -> Bill = Rs %d\n", i + 1, units, bill);
    }

    return 0;
}

Output

House 1 used  80 units -> Bill = Rs 0
House 2 used 150 units -> Bill = Rs 100
House 3 used 350 units -> Bill = Rs 800
House 4 used 620 units -> Bill = Rs 2120

9๏ธโƒฃ switch statement: ATM menu

An ATM has buttons 1, 2, 3, 4. When you press 2, it jumps straight to "Withdraw" without checking 1 first.
switch (choice) {
    case 1:  ...;  break;    // if choice is 1
    case 2:  ...;  break;    // if choice is 2
    default: ...;            // if nothing matched
}
switchelse-if ladder
Checksonly equal to (==)any condition (<, >, && ...)
Works withint and char onlyany type, including float and ranges
Best formenus, fixed choicesranges like marks or units
Speedjumps directlychecks one by one
๐Ÿง Try it: press a button
Balance: Rs 2000

  
switch is a multi-way branch. The expression's value is compared with each case constant. On a match, execution starts there and continues until break. default runs if no case matches. Case labels must be unique integer or char constants; float and strings are not allowed.

File: 09_switch_atm_menu.c

/*
 * Program 9: switch statement (ATM menu)
 * --------------------------------------
 * Real-life story: An ATM shows buttons 1, 2, 3, 4.
 * switch jumps straight to the "case" that matches the button.
 * break = "I'm done, leave the switch".
 * default = "none of the buttons matched".
 *
 * Sample input: 1 2 500 3 1000 7 4
 */
#include <stdio.h>

int main() {
    int balance = 2000;
    int choice, amount;

    do {
        printf("\n--- ATM MENU ---\n");
        printf("1. Check balance\n2. Withdraw\n3. Deposit\n4. Exit\n");
        printf("Choose: ");
        scanf("%d", &choice);

        switch (choice) {
            case 1:
                printf("Your balance is Rs %d\n", balance);
                break;
            case 2:
                printf("Amount to withdraw: ");
                scanf("%d", &amount);
                if (amount <= balance) {
                    balance -= amount;
                    printf("Collect Rs %d. New balance Rs %d\n", amount, balance);
                } else {
                    printf("Not enough money!\n");
                }
                break;
            case 3:
                printf("Amount to deposit: ");
                scanf("%d", &amount);
                balance += amount;
                printf("Deposited. New balance Rs %d\n", balance);
                break;
            case 4:
                printf("Thank you! Bye.\n");
                break;
            default:
                printf("Wrong button! Try again.\n");
        }
    } while (choice != 4);

    return 0;
}

You type

1  2 500  3 1000  7  4

Output

--- ATM MENU ---
1. Check balance
2. Withdraw
3. Deposit
4. Exit
Choose: Your balance is Rs 2000

--- ATM MENU ---
1. Check balance
2. Withdraw
3. Deposit
4. Exit
Choose: Amount to withdraw: Collect Rs 500. New balance Rs 1500

--- ATM MENU ---
1. Check balance
2. Withdraw
3. Deposit
4. Exit
Choose: Amount to deposit: Deposited. New balance Rs 2500

--- ATM MENU ---
1. Check balance
2. Withdraw
3. Deposit
4. Exit
Choose: Wrong button! Try again.

--- ATM MENU ---
1. Check balance
2. Withdraw
3. Deposit
4. Exit
Choose: Thank you! Bye.

๐Ÿ”Ÿ switch fall-through: traffic light

Red means stop, yellow means get ready, green means go. And all five vowels share one answer, "it's a vowel", by stacking cases together.
๐Ÿšฆ Try it: traffic light switch
Press a button
If you forget break, C keeps running the next case too. That's called fall-through. Look at "Forgot break" in the output below.

File: 10_switch_fallthrough.c

/*
 * Program 10: switch fall-through (Traffic light + vowels)
 * --------------------------------------------------------
 * Real-life story 1: Traffic light colours.
 * Real-life story 2: Checking vowels. Many cases share one answer.
 *
 * If you FORGET break, C keeps running into the next case.
 * This is called FALL-THROUGH. Sometimes it's a bug,
 * sometimes we use it on purpose to group cases together.
 */
#include <stdio.h>

int main() {
    char lights[] = {'R', 'Y', 'G', 'B'};
    int i;

    printf("Traffic light:\n");
    for (i = 0; i < 4; i++) {
        switch (lights[i]) {             /* switch works with int and char */
            case 'R': printf("  RED    -> STOP\n");      break;
            case 'Y': printf("  YELLOW -> GET READY\n"); break;
            case 'G': printf("  GREEN  -> GO\n");        break;
            default:  printf("  %c? That's not a traffic light colour!\n", lights[i]);
        }
    }

    /* Fall-through on purpose: a, e, i, o, u all reach the same printf */
    char word[] = "piano";
    printf("\nLetters of \"%s\":\n", word);
    for (i = 0; word[i] != '\0'; i++) {
        switch (word[i]) {
            case 'a':
            case 'e':
            case 'i':
            case 'o':
            case 'u':
                printf("  %c is a vowel\n", word[i]);
                break;
            default:
                printf("  %c is a consonant\n", word[i]);
        }
    }

    /* Fall-through by mistake: no break after case 1 */
    int level = 1;
    printf("\nForgot break (level 1):\n");
    switch (level) {
        case 1: printf("  Level 1 reward\n");      /* no break here! */
                /* fall through */
        case 2: printf("  Level 2 reward (oops, fell through)\n");
                break;
        case 3: printf("  Level 3 reward\n");
    }

    return 0;
}

Output

Traffic light:
  RED    -> STOP
  YELLOW -> GET READY
  GREEN  -> GO
  B? That's not a traffic light colour!

Letters of "piano":
  p is a consonant
  i is a vowel
  a is a vowel
  n is a consonant
  o is a vowel

Forgot break (level 1):
  Level 1 reward
  Level 2 reward (oops, fell through)

1๏ธโƒฃ1๏ธโƒฃ Looping statements

The traffic light goes around 3 times (for), you wait until the bus comes (while), and you ring the doorbell at least once before waiting (do-while).
forwhiledo-while
Use whenyou know the countyou don't know the countit must run at least once
Condition checkedbefore (entry-controlled)before (entry-controlled)after (exit-controlled)
Minimum runs001
Semicolon at end?nonoyes: while(x);
๐Ÿ” Try it: same job, three loops
Start: Stop at:

    Try Start = 10 and Stop = 5. for and while run 0 times, but do-while still runs once!
  
A loop repeats a block while a condition is true. Every loop has 3 parts: initialization, condition and update. for and while are entry-controlled (they check first). do-while is exit-controlled (it runs the body first, so at least once).

File: 11_looping_statements.c

/*
 * Program 11: Looping statements (for, while, do-while)
 * -----------------------------------------------------
 * Real-life story: A traffic light changes again and again.
 *   for      -> when you KNOW how many times (3 rounds of the light)
 *   while    -> when you DON'T know how many times (wait until the bus comes)
 *   do-while -> do it at least ONCE, then check (ring the doorbell, then wait)
 */
#include <stdio.h>

int main() {
    int round;

    /* FOR loop: 3 rounds of the traffic light */
    printf("FOR loop - traffic light, 3 rounds:\n");
    for (round = 1; round <= 3; round++) {
        printf("  Round %d: RED -> YELLOW -> GREEN\n", round);
    }

    /* WHILE loop: wait for the bus; it arrives at minute 4 */
    int minute = 0;
    int busArrives = 4;
    printf("\nWHILE loop - waiting for the bus:\n");
    while (minute < busArrives) {
        minute++;
        printf("  Minute %d: still waiting...\n", minute);
    }
    printf("  Bus is here!\n");

    /* WHILE loop that runs ZERO times: condition false at the start */
    int sweets = 0;
    while (sweets > 0) {
        printf("  This never prints\n");
    }
    printf("\nWHILE with 0 sweets ran 0 times.\n");

    /* DO-WHILE runs ONCE even though the condition is false */
    int rings = 0;
    printf("\nDO-WHILE - ring the doorbell:\n");
    do {
        rings++;
        printf("  Ding dong! (ring %d)\n", rings);
    } while (rings < 0);     /* false, but the body already ran once */

    /* Sum of 1 to 10 */
    int sum = 0, n;
    for (n = 1; n <= 10; n++) {
        sum += n;
    }
    printf("\nSum of 1 to 10 = %d\n", sum);

    return 0;
}

Output

FOR loop - traffic light, 3 rounds:
  Round 1: RED -> YELLOW -> GREEN
  Round 2: RED -> YELLOW -> GREEN
  Round 3: RED -> YELLOW -> GREEN

WHILE loop - waiting for the bus:
  Minute 1: still waiting...
  Minute 2: still waiting...
  Minute 3: still waiting...
  Minute 4: still waiting...
  Bus is here!

WHILE with 0 sweets ran 0 times.

DO-WHILE - ring the doorbell:
  Ding dong! (ring 1)

Sum of 1 to 10 = 55

1๏ธโƒฃ2๏ธโƒฃ break, continue, goto

Eating a box of 10 sweets. Sweet #4 is sour, so you skip it (continue). At sweet #8 your tummy is full, so you stop (break).
๐Ÿฌ Try it
Skip sweet # Stop at sweet #
StatementWhat it does
breakleaves the loop (or switch) right away
continueskips the rest of this round and goes to the next round
goto label;jumps to label: anywhere in the function. Avoid it, because it makes "spaghetti code"
returnleaves the whole function
break terminates the nearest enclosing loop or switch. continue skips the remaining statements of the current iteration and moves to the next one. goto transfers control unconditionally to a labelled statement.

File: 12_break_continue_goto.c

/*
 * Program 12: break, continue, goto (jump statements)
 * ---------------------------------------------------
 * Real-life story: Eating sweets from a box of 10.
 *   continue -> "skip this one" (sweet number 4 is sour, skip it)
 *   break    -> "stop now" (tummy full at sweet number 8)
 *   goto     -> "jump to a label" (rarely used, makes code messy)
 */
#include <stdio.h>

int main() {
    int sweet;

    printf("Eating sweets:\n");
    for (sweet = 1; sweet <= 10; sweet++) {
        if (sweet == 4) {
            printf("  Sweet %d is sour, skip it (continue)\n", sweet);
            continue;          /* jump to the next round of the loop */
        }
        if (sweet == 8) {
            printf("  Sweet %d: tummy full, stop! (break)\n", sweet);
            break;             /* leave the loop completely */
        }
        printf("  Ate sweet %d\n", sweet);
    }

    /* Find the first number divisible by 7 between 50 and 100 */
    int n;
    for (n = 50; n <= 100; n++) {
        if (n % 7 == 0) {
            printf("\nFirst multiple of 7 after 50 is %d\n", n);
            break;
        }
    }

    /* goto: jump to a label. Shown only so you know it exists. */
    int count = 1;
start:
    printf("goto round %d\n", count);
    count++;
    if (count <= 3) {
        goto start;           /* jump back up to the label "start:" */
    }

    return 0;
}

Output

Eating sweets:
  Ate sweet 1
  Ate sweet 2
  Ate sweet 3
  Sweet 4 is sour, skip it (continue)
  Ate sweet 5
  Ate sweet 6
  Ate sweet 7
  Sweet 8: tummy full, stop! (break)

First multiple of 7 after 50 is 56
goto round 1
goto round 2
goto round 3

1๏ธโƒฃ3๏ธโƒฃ Preprocessor directives

Before the cook starts, a helper brings ingredients (#include), labels jars (#define) and removes recipes not needed today (#ifdef). That helper is the preprocessor. It works before compiling.
DirectiveKid meaningExample
#includebring in another file#include <stdio.h>
#definemake a label (a macro)#define PI 3.14
#define with ( )a mini-function macro#define SQUARE(x) ((x)*(x))
#undefremove a label#undef PI
#ifdef / #ifndefinclude code only if a label is (or isn't) defined#ifdef DEBUG
#if #elif #else #endifif-else, but at preprocessing time#if VERSION > 2
#pragmaspecial instructions for the compiler#pragma once
<stdio.h> with angle brackets searches the system folders. "myfile.h" with quotes searches your own folder first.
๐Ÿ”Ž Try it: why macros need brackets
#define BAD(x) x*x vs #define GOOD(x) ((x)*(x))
x =

  
Preprocessor directives are lines starting with #, processed before compilation. Types: file inclusion (#include), macro substitution (#define, #undef), conditional compilation (#if, #ifdef, #ifndef, #else, #elif, #endif) and other (#pragma, #error). They do not end with a semicolon.

File: 13_preprocessor_directives.c

/*
 * Program 13: Preprocessor directives
 * -----------------------------------
 * Real-life story: Before a cook starts cooking, a helper gets everything ready:
 * brings the ingredients (#include), sticks labels on jars (#define),
 * and removes recipes we don't need today (#ifdef).
 * That helper is the PREPROCESSOR. It works BEFORE the compiler.
 * Every directive starts with #.
 */
#include <stdio.h>             /* bring in printf, scanf ... */

#define PI 3.14159             /* a constant label: PI means 3.14159 */
#define SCHOOL "Sunshine School"
#define SQUARE(x) ((x) * (x))  /* a macro with an argument */
#define MAX(a, b) ((a) > (b) ? (a) : (b))

#define DEBUG                  /* turn ON debug messages */

int main() {
    float radius = 2.0;

    printf("School: %s\n", SCHOOL);
    printf("Area of circle (r=2) = %.2f\n", PI * radius * radius);
    printf("SQUARE(5) = %d\n", SQUARE(5));
    printf("SQUARE(2+3) = %d (brackets in the macro keep it right)\n", SQUARE(2 + 3));
    printf("MAX(10, 25) = %d\n", MAX(10, 25));

    /* Conditional compilation */
#ifdef DEBUG
    printf("[DEBUG] This line is included because DEBUG is defined\n");
#endif

#ifndef TEST_MODE
    printf("TEST_MODE is NOT defined, so this line is included\n");
#endif

#undef DEBUG                   /* remove the DEBUG label */

#ifdef DEBUG
    printf("This will NOT print\n");
#else
    printf("DEBUG was removed with #undef\n");
#endif

    /* Built-in macros */
    printf("This is line %d of file %s\n", __LINE__, __FILE__);

    return 0;
}

Output

School: Sunshine School
Area of circle (r=2) = 12.57
SQUARE(5) = 25
SQUARE(2+3) = 25 (brackets in the macro keep it right)
MAX(10, 25) = 25
[DEBUG] This line is included because DEBUG is defined
TEST_MODE is NOT defined, so this line is included
DEBUG was removed with #undef
This is line 46 of file 13_preprocessor_directives.c

1๏ธโƒฃ4๏ธโƒฃ The compilation process

Your recipe is written in English (C code). The oven (CPU) only understands 0s and 1s. So the recipe goes through 4 helpers, one after another, until it becomes a cake you can eat (a program you can run).
hello.cyour code
โ†’
1. Preprocessorpastes #include,
replaces #define,
removes comments
โ†’
hello.iexpanded code
โ†’
2. Compilerchecks errors,
makes assembly
โ†’
hello.sassembly
โ†’
3. Assemblermakes machine code
โ†’
hello.oobject file (0s and 1s)
โ†’
4. Linkerjoins in printf's code from the library
โ†’
hello / a.out / .exe
ready to run!
โ†’
5. Loaderputs it in memory and runs it
CommandStops afterMakes
gcc -E hello.c -o hello.iPreprocessinghello.i (575 lines, because stdio.h was pasted in)
gcc -S hello.c -o hello.sCompilinghello.s (37 lines of assembly)
gcc -c hello.c -o hello.oAssemblinghello.o (832 bytes of machine code)
gcc hello.o -o helloLinkinghello (33432 bytes, ready to run)

Here is what each stage actually looked like when we ran it:

End of hello.i: GREETING got replaced and the comments are gone

int main() {
    printf("%s\n", "Hello, I went through all 4 steps!");
    return 0;
}

Start of hello.s: assembly language

	.build_version macos, 26, 0	sdk_version 27, 0
	.section	__TEXT,__text,regular,pure_instructions
	.globl	_main                           ; -- Begin function main
	.p2align	2
_main:                                  ; @main
	.cfi_startproc
; %bb.0:
	sub	sp, sp, #32
	stp	x29, x30, [sp, #16]             ; 16-byte Folded Spill
	add	x29, sp, #16
	.cfi_def_cfa w29, 16
	.cfi_offset w30, -8
	.cfi_offset w29, -16
	mov	w8, #0                          ; =0x0

Start of hello.o: machine code shown in hex

00000000: cffa edfe 0c00 0001 0000 0000 0100 0000  ................
00000010: 0400 0000 b801 0000 0020 0000 0000 0000  ......... ......
00000020: 1900 0000 3801 0000 0000 0000 0000 0000  ....8...........
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
Errors caught at different steps: a missing ; is a compile error. A spelling mistake like prntf becomes a linker error ("undefined reference"). Dividing by zero happens while running, so it's a runtime error.
Compilation steps: Preprocessing (.c โ†’ .i) โ†’ Compilation (.i โ†’ .s) โ†’ Assembly (.s โ†’ .o) โ†’ Linking (.o + libraries โ†’ executable) โ†’ Loading (loader copies it into memory for execution). Draw the flow diagram in a 16-mark answer.

File: 14_compilation_process.c

/*
 * Program 14: The compilation process
 * -----------------------------------
 * Real-life story: Turning a recipe written in English into a cake.
 *
 *   hello.c  --(1. Preprocessor)-->  hello.i   (#include and #define are pasted in)
 *   hello.i  --(2. Compiler)------>  hello.s   (assembly language)
 *   hello.s  --(3. Assembler)----->  hello.o   (machine code, 0s and 1s)
 *   hello.o  --(4. Linker)-------->  hello     (joins with printf's code, ready to run)
 *
 * Try these commands one by one:
 *   gcc -E 14_compilation_process.c -o hello.i    (stop after preprocessing)
 *   gcc -S 14_compilation_process.c -o hello.s    (stop after compiling)
 *   gcc -c 14_compilation_process.c -o hello.o    (stop after assembling)
 *   gcc hello.o -o hello                          (link)
 *   ./hello                                       (run!)
 */
#include <stdio.h>

#define GREETING "Hello, I went through all 4 steps!"

int main() {
    printf("%s\n", GREETING);
    return 0;
}

Output

Hello, I went through all 4 steps!

๐Ÿ“ 2-mark questions & answers

1. Differentiate formatted and unformatted I/O functions.Formatted functions (printf, scanf) use format specifiers to read or write any data type in a chosen format. Unformatted functions (getchar, putchar, gets, puts) work only with characters or strings and use no format specifiers.
2. What is the difference between = and ==?= is the assignment operator: it stores a value (a = 5). == is the relational operator: it compares two values and gives 1 or 0 (a == 5).
3. Differentiate while and do-while.while is entry-controlled: it checks the condition first and may run 0 times. do-while is exit-controlled: it runs the body first, then checks, so it runs at least once, and it ends with a semicolon.
4. Differentiate break and continue.break exits the loop or switch completely. continue skips the rest of the current iteration and goes to the next iteration of the loop.
5. What is type casting? Give an example.Converting a value from one data type to another explicitly, using (type). Example: float avg = (float)sum / n;
6. Why is break used in switch?Without break, control falls through and runs the following cases too. break stops execution after the matching case.
7. What is a macro? Give an example.A macro is a name defined with #define that the preprocessor replaces before compilation. Example: #define SQUARE(x) ((x)*(x))
8. What is a preprocessor?A program that processes the source code before compilation. It handles directives beginning with # such as file inclusion, macro substitution and conditional compilation.
9. Can switch use float or string as case labels?No. Case labels must be integer or character constants.
10. What are the stages of compilation?Preprocessing, compilation, assembly, linking (then the loader loads the program for execution).
11. What is the role of the linker?The linker combines object files with library code (like the code for printf) to produce one executable file, and it resolves function references.
12. What is an infinite loop? Give an example.A loop whose condition never becomes false. Example: while(1) { } or for(;;) { }

๐Ÿ† Mini quiz

๐ŸŽฏ Practice homework

  1. Read the temperature in Celsius with scanf and print it in Fahrenheit (F = C * 9 / 5 + 32). Use %.1f.
  2. Read 3 numbers and print the largest using a nested if.
  3. Read a year and say if it is a leap year: divisible by 4 and not by 100, or divisible by 400.
  4. Make a switch calculator: read two numbers and an operator character (+ - * /).
  5. Read a number 1โ€“7 and print the day name using switch.
  6. Print all numbers from 1 to 50 except multiples of 5 (use continue).
  7. Keep reading numbers until the user types 0, then print their sum (use do-while).
  8. Write a macro CUBE(x) and a macro IS_EVEN(n). Test them.
  9. Run gcc -E on one of your programs and count how many lines the .i file has.