Unit 2 - Notes

CSE101

Unit 2: Control structures and Input/Output functions

1. Decision Making and Branching

Control structures dictate the flow of program execution. Branching statements allow the program to skip execution of a code block or execute it based on the validity of a specific condition.

1.1 The if Statement

The simplest form of decision control. It executes a block of code only if the specified condition evaluates to true (non-zero).

Syntax:

C
if (condition) {
    // Code to execute if condition is true
}

Example:

C
int x = 10;
if (x > 5) {
    printf("x is greater than 5");
}

1.2 The if...else Statement

Provides an alternative path. If the condition is true, the if block executes; otherwise, the else block executes.

Syntax:

C
if (condition) {
    // Code for true
} else {
    // Code for false
}

Example:

C
int num = 4;
if (num % 2 == 0) {
    printf("Even Number");
} else {
    printf("Odd Number");
}

1.3 The else if Ladder

Used to test multiple conditions in sequence. The program checks conditions from top to bottom; the first true condition triggers its associated block, and the rest are skipped.

Syntax:

C
if (condition1) {
    // statement 1
} else if (condition2) {
    // statement 2
} else {
    // default statement
}

1.4 The switch Case Statement

A multi-way branch statement that provides an easy way to dispatch execution to different parts of code based on the value of an expression. It is often a cleaner alternative to long else if ladders when comparing a single variable against constants.

Key Rules:

  • The expression must evaluate to an integer or character.
  • case labels must be constants.
  • break is strictly necessary to prevent "fall-through" (executing subsequent cases).
  • default executes if no cases match.

Syntax:

C
switch (expression) {
    case constant1:
        // code
        break;
    case constant2:
        // code
        break;
    default:
        // default code
}

Example:

C
char grade = 'B';
switch(grade) {
    case 'A': printf("Excellent"); break;
    case 'B': printf("Good"); break;
    case 'C': printf("Fair"); break;
    default:  printf("Invalid Grade");
}


2. Loop Control Structures (Iteration)

Loops allow a block of code to be executed repeatedly until a specific condition is met.

2.1 The while Loop (Entry-Controlled)

The condition is evaluated before the loop body executes. If the condition is initially false, the loop body never runs.

Syntax:

C
while (condition) {
    // Code to repeat
    // Increment/Decrement logic
}

Example:

C
int i = 0;
while (i < 5) {
    printf("%d ", i);
    i++;
}

2.2 The do...while Loop (Exit-Controlled)

The condition is evaluated after the loop body executes. This guarantees the loop body runs at least once.

Syntax:

C
do {
    // Code to repeat
} while (condition); // Note the semicolon

Example:

C
int i = 10;
do {
    printf("%d", i); // Prints 10 even though 10 is not < 5
    i++;
} while (i < 5);

2.3 The for Loop

The most compact loop structure, typically used when the number of iterations is known. It combines initialization, condition testing, and increment/decrement in one line.

Syntax:

C
for (initialization; condition; update) {
    // Code to repeat
}

Example:

C
for (int i = 0; i < 5; i++) {
    printf("%d ", i);
}


3. Jump Statements

These statements transfer control unconditionally to another part of the program.

3.1 break

  • Usage: Used in switch statements and loops.
  • Action: Immediately terminates the nearest enclosing loop or switch structure. Control passes to the statement following the loop/switch.

3.2 continue

  • Usage: Used only in loops.
  • Action: Skips the remaining code in the current iteration and jumps to the next iteration check (update/condition step).

3.3 goto

  • Usage: Unconditional jump to a labeled statement.
  • Note: Generally discouraged ("spaghetti code") as it reduces readability, but useful in specific system programming contexts (e.g., breaking out of deep nested loops).

Example:

C
for(int i=0; i<10; i++) {
    if(i == 5) goto cleanup;
}
cleanup:
printf("Jumped out of loop");

3.4 return

  • Usage: Used in functions.
  • Action: Terminates the execution of a function and optionally returns a value to the caller.

4. Type Conversion and Modifiers

4.1 Type Modifiers

Modifiers alter the meaning of base data types (int, char, double) to yield a new type or change the storage range.

  1. signed: Default for int and char. Holds positive and negative values.
  2. unsigned: Holds only zero and positive values. Doubles the positive range of the variable.
  3. short: Reduces memory usage (usually 2 bytes for int).
  4. long: Increases memory usage/range (usually 4 or 8 bytes).

Example:
unsigned int age = 25; (Age cannot be negative).

4.2 Type Conversion (Type Casting)

Converting a value from one data type to another.

1. Implicit Conversion (Coercion):
Performed automatically by the compiler. Usually happens when a smaller type is assigned to a larger type (e.g., int to float).

C
int i = 10;
float f = i; // 10.0

2. Explicit Conversion (Casting):
Forced by the programmer. Essential when losing precision is a risk or doing integer division.
Syntax: (type_name) expression

Example:

C
int a = 5, b = 2;
float result;
result = a / b;         // Result is 2.0 (integer division)
result = (float)a / b;  // Result is 2.5 (explicit cast)


5. Input and Output Functions

C uses standard library functions defined in <stdio.h> for I/O operations.

5.1 Formatted I/O Functions

These functions allow data to be read or written in a specific format defined by the user using format specifiers.

printf() (Print Formatted)

Used to output data to the standard output (console).

  • Format Specifiers: %d (int), %f (float), %c (char), %s (string), %lf (double).
  • Escape Sequences: \n (newline), \t (tab).

Example:

C
int age = 20;
printf("Age is: %d\n", age);
printf("Price: %.2f", 99.999); // Width formatting (2 decimal places) -> 100.00

scanf() (Scan Formatted)

Used to read data from standard input (keyboard).

  • Address Operator (&): Required for primitive types (int, float, char) to tell scanf where to store the input in memory. Strings (arrays) do not need &.

Example:

C
int id;
char name[20];
printf("Enter ID and Name: ");
scanf("%d %s", &id, name); // Reads integer and string (up to whitespace)

5.2 Unformatted I/O Functions

These functions deal with characters or strings directly without format specifiers. They are generally faster but less flexible.

Character I/O

  1. getchar(): Reads a single character from standard input.
  2. putchar(char): Writes a single character to standard output.
  3. getch() / getche(): (Non-standard, usually in <conio.h>). Reads a character without pressing enter. getche echoes the character; getch does not.

String I/O

  1. gets(str): Reads a line of text (including spaces) until a newline is found.
    • Warning: Deprecated in modern C due to buffer overflow risks. Uses fgets is preferred in production, though gets is often covered in academic syllabi.
  2. puts(str): Writes a string to standard output and automatically appends a newline character.

Example:

C
char str[50];
puts("Enter text:");
gets(str);      // Reads spaces, unlike scanf("%s")
puts("You typed:");
puts(str);


6. Designing Structured Programs in C

Structured programming is a paradigm aimed at improving the clarity, quality, and development time of a computer program by making extensive use of the control structures described above.

Key Principles

  1. Top-Down Design: Breaking a complex problem into smaller, manageable sub-problems (modules/functions).
  2. Modularity: Writing code in distinct, independent blocks (functions) that perform specific tasks.
  3. Standard Control Flow: Avoiding goto (spaghetti code) in favor of:
    • Sequence: Linear execution.
    • Selection: if, switch.
    • Iteration: for, while.

Steps to Design a Structured Program

  1. Problem Definition: Clearly understand the inputs and desired outputs.
  2. Algorithm Design: Create a step-by-step logic (pseudocode or flowchart).
  3. Coding: Implement the logic using structured control statements.
  4. Testing and Debugging: verify logical correctness using test cases.

Benefits:

  • Maintainability: Easier to update specific modules without breaking the whole system.
  • Readability: Logic follows a natural flow.
  • Reusability: Functions can be reused in other programs.