LABORATORY 05

Statements (1) - Algorithms and Decision Structures

Duration: 2 hours Language: C / C++ Previous: Laboratory 4 PDF handout RO versiunea română

A program is the translation of an algorithm. Before writing code, the problem must be described as an ordered sequence of steps. This lab covers representing algorithms and the first category of statements that change the order of execution: decision statements.

1Lab objectives

  • Describing an algorithm through a flowchart and through pseudocode
  • Telling expression statements apart from compound ones
  • Correctly using the if and if-else statements
  • Resolving the else ambiguity by using braces
  • Applying the switch statement and understanding the role of break

2Algorithms and ways to represent them

An algorithm is a finite sequence of actions that, applied to input data, lead to the desired result. Describing it is an intermediate stage between the mathematical formulation and the program written in a concrete language.

MethodAdvantagesDisadvantages
Natural languageneeds no special trainingambiguous for complex problems
Flowchartvisually clear, easy to followbecomes hard to draw for large algorithms
Pseudocodeconcise, close to the final codenot standardized
Decision tablesideal for many combined alternativesunsuited to sequential algorithms

3Flowchart symbols

START / STOP terminator read / write input-output x = a + b processing a > b ? decision Blocks are linked by directed segments; two branches leave the decision block, marked YES and NO. Example: START → read a, b → a > b ? → (YES) write a / (NO) write b → STOP
Fig. 1 - The basic symbols used in flowcharts

4Types of statements

TypeFormNotes
Expression statementexpression;any expression followed by ; becomes a statement
Empty statement;does nothing; useful where the syntax requires a statement
Compound statement (block){ ... }groups several statements; can contain local declarations
Decision statementsif, if-else, switchchoose a branch of execution
Repetition statementswhile, do-while, forcovered in Laboratory 6
Jump statementsbreak, continue, return, gotointerrupt the normal flow
A block creates a new scopeVariables declared between braces exist only inside the block. On exit they are destroyed, and their names become available again.

5The if statement

syntactic forms
if (expression)
    statement;                     // simple form

if (expression)
    statement_1;
else
    statement_2;                   // form with an alternative

if (expression_1) {
    ...
} else if (expression_2) {
    ...
} else {
    ...                            // cascading alternatives
}
What "true" means in CThe expression in an if does not have to be a comparison. Any nonzero value is considered true, and zero is false. That is why if (n) is equivalent to if (n != 0).

6Decision simulator

Watch step by step how the conditions in an if-else if cascade are evaluated, and why the order of the tests matters.

Classifying a grade - a cascade of decisions
Why the cascade worksThe test grade < 9 seems to also accept grades under 5, but those cases were already handled by the earlier conditions. In a cascade, every branch implicitly assumes all the ones before it were false.

7The switch statement

general syntax
switch (expression) {
    case c1:
        statements;
        break;
    case c2:
        statements;
        break;
    default:
        statements;
}
AspectRule
The expression's typemust be integer or character - not float, not a string
case labelsmust be constants, distinct from each other
breakstops execution; without it, execution continues into the next case
defaultoptional; runs if no case matches
Falling through the cascade (fall-through)The absence of break makes execution continue into the following cases, regardless of their value. Sometimes this is intentional - to group several values that get the same treatment - but most often it is an oversight.

8Common mistakes

1. A semicolon after if if (a > b); is syntactically correct: the body of if becomes the empty statement, and the following block executes always. The compiler flags nothing.
2. The else ambiguity An else is always associated with the nearest unassociated if, regardless of indentation. Indentation fools the eye, not the compiler. Always use braces.
3. Comparing real numbers with == if (0.1 + 0.2 == 0.3) is false, because of the approximate binary representation. Correct: if (fabs(a - b) < 1e-9).
4. Assignment instead of comparison if (x = 0) assigns and is always false; if (x = 5) assigns and is always true. Some programmers write if (5 == x) precisely so that the mistake becomes a compile error.

9Source code

equation.c - solving the quadratic equation
#include <stdio.h>
#include <math.h>

int main(void)
{
    double a, b, c, delta, x1, x2;

    printf("Coefficients a, b, c: ");
    scanf("%lf %lf %lf", &a, &b, &c);

    if (a == 0) {
        if (b == 0) {
            if (c == 0) printf("Identity: any x is a solution\n");
            else        printf("Impossible equation\n");
        } else {
            printf("First-degree equation: x = %.4f\n", -c / b);
        }
    } else {
        delta = b * b - 4 * a * c;

        if (delta > 0) {
            x1 = (-b + sqrt(delta)) / (2 * a);
            x2 = (-b - sqrt(delta)) / (2 * a);
            printf("Two real roots: %.4f and %.4f\n", x1, x2);
        } else if (delta == 0) {
            printf("Double root: %.4f\n", -b / (2 * a));
        } else {
            printf("Complex roots: %.4f +/- %.4fi\n",
                   -b / (2 * a), sqrt(-delta) / (2 * a));
        }
    }
    return 0;
}
calculator.c - switch with grouped cases
#include <stdio.h>

int main(void)
{
    double a, b;
    char op;

    printf("Expression (e.g. 12 * 4): ");
    scanf("%lf %c %lf", &a, &op, &b);

    switch (op) {
        case '+':
            printf("%.2f\n", a + b);
            break;
        case '-':
            printf("%.2f\n", a - b);
            break;
        case '*':
        case 'x':                       // intentional grouping: * and x do the same thing
        case 'X':
            printf("%.2f\n", a * b);
            break;
        case '/':
            if (b == 0) printf("Division by zero!\n");
            else        printf("%.2f\n", a / b);
            break;
        default:
            printf("Unknown operator: %c\n", op);
    }
    return 0;
}
ambiguity.c - why braces are needed
#include <stdio.h>

int main(void)
{
    int a = 1, b = 2;

    // WRONG: the indentation suggests something other than what the compiler does
    if (a > 0)
        if (b > 5)
            printf("b is large\n");
    else                                // binds to the SECOND if, not the first!
        printf("This does NOT mean a <= 0\n");

    // CORRECT: the braces remove any ambiguity
    if (a > 0) {
        if (b > 5) {
            printf("b is large\n");
        }
    } else {
        printf("a <= 0\n");
    }
    return 0;
}

10Code workshop

Decisions are best understood by tracing them step by step. Run the programs, then change the input data to force each branch.

The quadratic equation - every case
#include <stdio.h>
#include <math.h>

int main(void)
{
    double a, b, c, delta;

    printf("Coefficients a, b, c: ");
    scanf("%lf %lf %lf", &a, &b, &c);

    if (a == 0) {
        if (b == 0) printf("Not a quadratic equation\n");
        else        printf("First degree: x = %.4f\n", -c / b);
    } else {
        delta = b * b - 4 * a * c;
        if (delta > 0) {
            printf("Two roots: %.4f and %.4f\n",
                   (-b + sqrt(delta)) / (2 * a),
                   (-b - sqrt(delta)) / (2 * a));
        } else if (delta == 0) {
            printf("Double root: %.4f\n", -b / (2 * a));
        } else {
            printf("Complex roots\n");
        }
    }
    return 0;
}
Try thisChange the input data to 1 -4 4 (double root), then to 1 1 5 (complex roots), and to 0 2 6 (first degree). Each set of values sends execution down a different branch.
switch - exercise with the days of the month
#include <stdio.h>

int main(void)
{
    int month, days = 0;

    printf("Month (1-12): ");
    scanf("%d", &month);

    switch (month) {
        case 1: case 3: case 5: case 7:
        case 8: case 10: case 12:
            days = 31;
            break;

        /* Complete the cases for the 30-day months (4, 6, 9, 11)
           and for February (28). Also add a default that
           prints "Invalid month". */
    }

    if (days > 0) printf("Month %d has %d days\n", month, days);
    return 0;
}

11Work tasks

  • Draw the flowchart for finding the maximum of three numbers, then implement it.
  • Write the complete program for solving the quadratic equation, handling every special case.
  • Implement a calculator with switch, which also handles division by zero.
  • Reproduce the mistake with ; after if and explain the observed behavior.
  • Run the example with the else ambiguity and check which if it binds to.
  • Test if (0.1 + 0.2 == 0.3) and fix the comparison using a tolerance.
  • Write a program that prints the number of days in a month, using switch with grouped cases.

12Extended application

ExtensionWrite a program that determines the day of the week for a calendar date entered by the user, using Zeller's congruence. Validate the date (month between 1 and 12, a valid day for that month, accounting for leap years) and print a clear error message for every invalid case. Use switch to print the day's name.

13Review questions

14Resources