C 2

Phase 2 — Control Flow & Functions

Phase 2 is where C starts behaving like a real programming language rather than just a collection of statements.

We’ll cover the whole phase in 10 chapters:

  1. if, else, else if + truth in C

  2. Nested conditions

  3. switch

  4. while

  5. do while

  6. for + nested loops

  7. break, continue, infinite loops + off-by-one errors

  8. Functions, parameters, arguments, return values, void

  9. Prototypes, scope, local/global variables + pass-by-value

  10. Recursion


Chapter 1 — if, else, else if & Truth in C

Question

Given below is a program that checks a person's score.

Predict the output before reading the explanation.

#include <stdio.h>

int main(void)
{
    int score = 72;

    // Check the first condition.
    if (score >= 90)
        printf("Excellent\n");

    // Check this condition if the first one was false.
    else if (score >= 60)
        printf("Pass\n");

    // Execute this if all previous conditions were false.
    else
        printf("Fail\n");

    // C treats non-zero values as true and 0 as false.
    if (5)
        printf("Five is true\n");

    if (0)
        printf("Zero is true\n");

    return 0;
}

Answer

Pass
Five is true

Step-by-step explanation

score is 72.

First:

score >= 90

becomes:

72 >= 90

which is false.

So C moves to:

score >= 60

which becomes:

72 >= 60

true.

Therefore:

printf("Pass\n");

runs.

The else is skipped because one previous condition succeeded.


The second important concept is:

if (5)

In C:

  • 0 → false

  • any non-zero value → true

Therefore 5 is true.

But:

if (0)

is false.

How to read the important code

When you see:

if (condition)

read it naturally as:

"If this condition is true, execute the following statement/block."

For:

else if (...)

read:

"Otherwise, if this new condition is true..."

Beginner trap

C does not have a special Boolean requirement for if.

This is perfectly valid:

if (123)

and this is also valid:

if (-10)

Both are true because they are non-zero.

Key takeaway

In C, 0 is false and every non-zero value is true.


Chapter 2 — Nested Conditions

Question

What will this program print?

#include <stdio.h>

int main(void)
{
    int age = 20;
    int has_id = 1;

    // First check whether the person is old enough.
    if (age >= 18)
    {
        // Only people who are at least 18 reach this block.
        if (has_id)
        {
            printf("Entry allowed\n");
        }
        else
        {
            printf("ID required\n");
        }
    }
    else
    {
        printf("Too young\n");
    }

    return 0;
}

Answer

Entry allowed

Step-by-step explanation

Start with:

age = 20

Check:

age >= 18

20 >= 18 → true.

So we enter the outer if.

Now C checks:

if (has_id)

has_id is 1.

Since non-zero means true:

1 → true

Therefore:

Entry allowed

is printed.

How to read the important code

Think of nested ifs as gates:

Gate 1
  ↓
Gate 2
  ↓
Action

The inner condition is never evaluated if the outer condition prevents execution from reaching it.

Beginner trap

Don't confuse:

if (age >= 18)

with:

if (age = 18)

The first compares.

The second assigns.

Key takeaway

A nested if is simply an if inside another decision block.


Chapter 3 — switch

Question

Predict the output.

#include <stdio.h>

int main(void)
{
    int day = 3;

    // Select one case based on the value of day.
    switch (day)
    {
        case 1:
            printf("Monday\n");
            break;

        case 2:
            printf("Tuesday\n");
            break;

        case 3:
            printf("Wednesday\n");
            break;

        case 4:
            printf("Thursday\n");
            break;

        default:
            printf("Unknown day\n");
    }

    return 0;
}

Answer

Wednesday

Step-by-step explanation

day contains:

3

C enters the switch:

switch (day)

It searches for:

case 3:

It finds it and executes:

printf("Wednesday\n");

Then:

break;

terminates the switch.

Why is break important?

Consider:

case 3:
    printf("Wednesday\n");

case 4:
    printf("Thursday\n");

Without break, execution can fall through into the next case.

So normally:

case 3:
    ...
    break;

is used when you don't want fall-through.

default

default is similar to the "none of the above" branch.

For example:

day = 10;

would produce:

Unknown day

How to read the important code

Read:

switch (day)

as:

"Choose an execution path based on the value of day."

Key takeaway

Use switch when one expression needs to be matched against multiple discrete values.


Chapter 4 — while

Question

What is the output?

#include <stdio.h>

int main(void)
{
    int count = 1;

    // Repeat while count is less than or equal to 5.
    while (count <= 5)
    {
        printf("%d ", count);

        // Change the condition's variable.
        count++;
    }

    return 0;
}

Answer

1 2 3 4 5

Step-by-step explanation

Initially:

count = 1

C checks:

count <= 5

true → print 1.

Then:

count++;

makes:

count = 2

The condition is checked again.

This continues:

1 → print
2 → print
3 → print
4 → print
5 → print
6 → stop

The important point is that the condition is checked before each iteration.

How to read the important code

Read:

while (condition)

as:

"Keep doing this while the condition remains true."

Beginner trap

A while loop can accidentally become infinite:

int count = 1;

while (count <= 5)
{
    printf("%d", count);
}

count never changes.

Therefore the condition remains true forever.

Key takeaway

while checks the condition first, then executes the loop body.


Chapter 5 — do while

Question

What does this program print?

#include <stdio.h>

int main(void)
{
    int number = 10;

    // Execute the body first.
    do
    {
        printf("Number = %d\n", number);

        number++;
    }
    // Check the condition after execution.
    while (number < 5);

    return 0;
}

Answer

Number = 10

Step-by-step explanation

Initially:

number = 10

The do block executes without checking the condition first.

So:

printf("Number = %d\n", number);

prints:

Number = 10

Then:

number++;

makes number equal to 11.

Only now does C check:

number < 5

11 < 5 → false.

The loop ends.

while vs do while

while:
    check → execute → check → execute

do while:
    execute → check → execute → check

Therefore a do while loop executes at least once.

Key takeaway

do while executes the body first and checks the condition afterward.


Chapter 6 — for Loops & Nested Loops

Question

Predict the output.

#include <stdio.h>

int main(void)
{
    // Outer loop controls the rows.
    for (int row = 1; row <= 3; row++)
    {
        // Inner loop controls the columns.
        for (int column = 1; column <= row; column++)
        {
            printf("* ");
        }

        printf("\n");
    }

    return 0;
}

Answer

* 
* * 
* * * 

Step-by-step explanation

The outer loop starts:

row = 1

Inner loop:

column = 1

Since:

1 <= 1

one star is printed.


Next:

row = 2

The inner loop runs twice:

* *

Next:

row = 3

The inner loop runs three times:

* * *

How to read a nested loop

Think:

outer loop
    inner loop
    inner loop
    inner loop

outer loop
    inner loop
    inner loop
    inner loop

The inner loop completes its entire execution for each iteration of the outer loop.

The three parts of for

for (initialization; condition; update)

Here:

for (int row = 1; row <= 3; row++)

means:

start → row = 1

continue while → row <= 3

after each iteration → row++

Key takeaway

A for loop packages initialization, condition, and update into one compact loop structure.


Chapter 7 — break, continue, Infinite Loops & Off-by-One Errors

Question

Predict the output.

#include <stdio.h>

int main(void)
{
    for (int i = 1; i <= 10; i++)
    {
        // Skip even numbers.
        if (i % 2 == 0)
            continue;

        // Stop when i reaches 7.
        if (i == 7)
            break;

        printf("%d ", i);
    }

    return 0;
}

Answer

1 3 5

Step-by-step explanation

i = 1

Odd → continue condition false.

i == 7 false.

Print:

1

i = 2

i % 2 == 0

is true.

So:

continue;

skips the remaining body.

2 is not printed.


i = 3

Print:

3

i = 4

Skipped.


i = 5

Printed.


i = 6

Skipped.


i = 7

The first condition is false because 7 is odd.

Then:

if (i == 7)
    break;

is true.

break terminates the loop immediately.

Therefore 7 isn't printed.

continue vs break

continue:

Skip the current iteration and move toward the next one.

break:

Leave the loop completely.


Infinite loops

A deliberately infinite loop can be written as:

for (;;)
{
    /* runs forever */
}

This is sometimes useful in systems programming, servers, embedded programs, event loops, etc.

But accidental infinite loops are bugs.


Off-by-one errors

Suppose you want numbers 1 through 5:

for (int i = 1; i < 5; i++)

This gives:

1 2 3 4

because 5 < 5 is false.

Whereas:

for (int i = 1; i <= 5; i++)

gives:

1 2 3 4 5

This is an off-by-one error.

Key takeaway

break exits; continue skips the current iteration; carefully check < versus <=.


Chapter 8 — Functions, Parameters, Arguments, Return Values & void

Question

What will this program print?

#include <stdio.h>

// Function declaration.
int add(int a, int b);

int main(void)
{
    int result;

    // 10 and 20 are arguments.
    result = add(10, 20);

    printf("%d\n", result);

    return 0;
}

// Function definition.
int add(int a, int b)
{
    // Return a value to the caller.
    return a + b;
}

Answer

30

Step-by-step explanation

Execution begins in:

main()

This line:

result = add(10, 20);

calls the function.

The values:

10
20

are arguments.

Inside the function:

int add(int a, int b)

a receives 10.

b receives 20.

Therefore:

return a + b;

becomes:

return 10 + 20;

which returns:

30

That returned value is assigned to:

result

Then:

printf("%d\n", result);

prints 30.


Parameter vs argument

Consider:

int add(int a, int b)

a and b are parameters.

When calling:

add(10, 20)

10 and 20 are arguments.

Think:

parameter → variable defined by the function
argument  → actual value supplied during the call

void

A function that doesn't return a value can use:

void

For example:

void greet(void)

The first void means:

returns nothing

The second void means:

accepts no arguments

This is why:

int main(void)

means:

main returns an int and takes no arguments.

Key takeaway

Functions package reusable behavior; parameters receive values and return sends a value back to the caller.


Chapter 9 — Prototypes, Scope, Local/Global Variables & Pass-by-Value

Question

Predict the output carefully.

#include <stdio.h>

// Global variable.
int value = 100;

// Function prototype.
void change(int number);

int main(void)
{
    int value = 10;

    printf("Before: %d\n", value);

    // Pass value to the function.
    change(value);

    printf("After: %d\n", value);

    return 0;
}

void change(int number)
{
    // This changes only the function's local copy.
    number = 999;

    printf("Inside: %d\n", number);
}

Answer

Before: 10
Inside: 999
After: 10

Step-by-step explanation

There are two different variables named value.

Global:

int value = 100;

Local to main:

int value = 10;

Inside main, the local variable is the one being used.

So:

printf("Before: %d\n", value);

prints:

10

Then:

change(value);

passes 10 to the function.

The parameter:

int number

receives a copy of 10.

Inside the function:

number = 999;

changes that copy.

So:

Inside: 999

is printed.

But the original value in main remains:

10

Therefore:

After: 10

Pass-by-value

C fundamentally passes function arguments by value.

That means:

main's value
      ↓
     copy
      ↓
function parameter

Changing the parameter doesn't change the original variable.

Pointers will later give us a way for a function to modify the caller's object.


Scope

Scope means, roughly:

Where can this variable name be accessed?

This:

int main(void)
{
    int x = 10;
}

creates a local variable whose scope is inside that block.

A global variable can have broader scope, but globals should not be treated as a substitute for good program design.


Function prototype

This:

void change(int number);

is a function declaration/prototype.

It tells the compiler:

"There is a function called change; it takes an int and returns void."

The actual implementation comes later:

void change(int number)
{
    ...
}

Why prototypes matter

C compiles source code in a structured way. The compiler needs to know enough about a function when it encounters a call.

Key takeaway

C passes arguments by value; without pointers, changing a parameter doesn't directly change the caller's variable.


Chapter 10 — Recursion

Question

Predict the output.

#include <stdio.h>

// Calculate n! recursively.
int factorial(int n)
{
    // Base case: stop recursion.
    if (n <= 1)
        return 1;

    // Recursive case: function calls itself.
    return n * factorial(n - 1);
}

int main(void)
{
    printf("%d\n", factorial(4));

    return 0;
}

Answer

24

Step-by-step explanation

Start:

factorial(4)

becomes:

4 * factorial(3)

Then:

4 * 3 * factorial(2)

Then:

4 * 3 * 2 * factorial(1)

Now the base case:

if (n <= 1)
    return 1;

returns 1.

So the calculations unwind:

factorial(1) = 1

factorial(2) = 2 × 1 = 2

factorial(3) = 3 × 2 = 6

factorial(4) = 4 × 6 = 24

Therefore:

24

Two essential parts of recursion

Every useful recursive function needs a way to eventually stop.

1. Base case

if (n <= 1)
    return 1;

2. Recursive case

return n * factorial(n - 1);

The recursive call moves toward the base case.


What happens in memory?

This is especially important because later we'll connect recursion to stack frames.

Conceptually:

factorial(4)
    ↓
factorial(3)
    ↓
factorial(2)
    ↓
factorial(1)

Each active function call needs its own call information.

Later, when we study memory, pointers and stack frames, you'll understand exactly what is happening underneath.

Beginner trap

This would be dangerous:

int factorial(int n)
{
    return n * factorial(n - 1);
}

There is no base case.

The function keeps calling itself until the program eventually runs out of stack space.

Key takeaway

Recursion means a function calls itself, and a base case is required to stop the chain.


Phase 2 — What You Should Now Understand

You have now covered the complete Phase 2 roadmap:

ConceptCore idea
ifMake a decision
elseAlternative path
else ifTest another condition
C truth0 false, non-zero true
Nested ifDecision inside decision
switchMatch one expression against cases
whileCheck → execute
do whileExecute → check
forInitialization → condition → update
Nested loopsLoop inside another loop
breakExit loop
continueSkip current iteration
Infinite loopCondition never becomes false
Off-by-oneBoundary/counting mistake
FunctionReusable block of code
ParameterVariable receiving an argument
ArgumentValue supplied to a function
returnSend a value back
voidNo value / no parameters
PrototypeTells compiler about a function
ScopeWhere a name is accessible
Local variableVariable belonging to a block/function
Global variableVariable declared outside functions
Pass-by-valueFunction receives a copy
RecursionFunction calls itself

The most important connection

Phase 2 should leave you with this mental model:

             C PROGRAM
                 │
        ┌────────┴────────┐
        ↓                 ↓
     DECISIONS          REPETITION
        │                 │
   if / switch       while / for
        │                 │
        └────────┬────────┘
                 ↓
             FUNCTIONS
                 │
        ┌────────┴────────┐
        ↓                 ↓
   parameters          return
        │                 │
        └────────┬────────┘
                 ↓
          REUSABLE LOGIC
                 │
                 ↓
             recursion

One crucial bridge to Phase 3/4

You have also reached an important point:

change(value);

cannot directly modify value because C passed a copy.

Soon, when we reach pointers, the picture changes:

value
  │
  └── address ──→ pointer ──→ same memory

That is where C becomes substantially different from Java—and where Phase 4 becomes one of the most important parts of your entire C journey.

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.