Cover image for "C Programming Basics Part 2" highlighting key topics: Control Flow, Functions, and Arrays & Pointers, with the website colliercomputers.com and the date Jan '25.

C Programming Basics – Learn Fundamental Concepts – Part 2

Reading Time: 6 minutes

Welcome back to the C Programming Basics series! In Part 1, we covered the fundamentals like variables, data types, operators, and basic input/output operations. If you haven’t checked it out yet, it’s a great starting point to build a solid foundation.

In Part 2, we’re diving deeper into the core concepts of C programming, focusing on control flow, functions, arrays and strings, pointers and memory management, structures and unions, and file handling. These topics are essential as they help you write more dynamic, efficient, and organized code. Whether you’re new to C or brushing up on the basics, this guide will help you understand how C programs make decisions, manage data, and interact with files.

Let’s jump in!

Control Flow

Control flow statements determine the execution path of a program based on conditions or loops. They define the order in which individual statements, instructions, or functions are executed. In C, control flow statements enable you to manage how your code runs, allowing for decisions, repetitions, and branching based on specific conditions. Without control flow, programs would execute every line of code sequentially, which isn’t practical for real-world applications.

Conditional Statements:

if Statement:

if (condition) {
    // code to execute
}
int x = 10;
if (x > 5) {
    printf("x is greater than 5");
}
Explanation:

Here, x is assigned the value 10. The if statement checks if x is greater than 5. Since 10 > 5 is true, the message "x is greater than 5" will be displayed.

  • Condition: x > 5 is the condition being tested.
  • Code Block: The code inside {} runs only if the condition is true.

if-else Statement:

if (condition) {
    // code if true
} else {
    // code if false
}

Here’s a simple example that checks whether a number is even or odd:

#include <stdio.h>

int main() {
    int number = 7;

    if (number % 2 == 0) {
        // This block runs if the condition is true
        printf("%d is even.\n", number);
    } else {
        // This block runs if the condition is false
        printf("%d is odd.\n", number);
    }

    return 0;
}
Explanation
Condition:
if (number % 2 == 0)
  • This checks if the remainder when number is divided by 2 is 0 (which means the number is even).
  • The % symbol is the modulus operator, which returns the remainder of the division.
True Block:

If the condition is true, the program executes:

printf("%d is even.\n", number);
False Block:

If the condition is false, the program jumps to the else block:

printf("%d is odd.\n", number);
Sample Output:
7 is odd.

Since 7 % 2 equals 1, the condition is false, so the code inside the else block runs.

This example shows how if-else statements help your program make decisions based on conditions.

switch-case Statement:

The switch-case statement in C is a control flow structure that allows you to execute different blocks of code based on the value of an expression. It’s a cleaner and more organized alternative to using multiple if-else statements, especially when you’re comparing the same variable against different values.

The switch evaluates the given expression once and compares its result with each case. When a match is found, the corresponding block of code runs. The break statement is used to exit the switch after executing the matched case. If none of the cases match, the default case is executed (similar to an else in an if-else structure).

Key Components:
  • switch(expression): Evaluates the expression.
  • case value:: Defines a specific condition to check against the expression.
  • break;: Ends the current case, preventing fall-through to the next case.
  • default:: Executes when none of the case values match (optional but recommended).

The switch-case is commonly used for handling menus, options, user inputs, or scenarios where you need to choose from multiple possibilities based on a single variable.

switch(expression) {
    case value1: 
        // code
        break;
    case value2:
        // code
        break;
    default:
        // code if no cases match
        break;
}
int day = 3;
switch (day) {
    case 1:
        printf("Monday");
        break;
    case 2:
        printf("Tuesday");
        break;
    case 3:
        printf("Wednesday");
        break;
    default:
        printf("Invalid day");
}
Explanation:

The switch statement evaluates the value of day. Since day is 3, it matches case 3, and "Wednesday" is printed.

  • break: Stops the code from running into the next case.
  • default: Acts like an else—it runs if no cases match.

Loops:

while Loop:

The while loop keeps running as long as a specified condition is true. It checks the condition before executing the code inside the loop. If the condition is false from the beginning, the code inside the loop may never run.

while (condition) {
    // code
}
Example
int i = 0;
while (i < 5) {
    printf("%d ", i);
    i++;
}
Explanation
  • Initialization: int i = 0 sets the starting value.
  • Condition: i < 5 is checked before each loop iteration. The loop runs as long as this condition is true.
  • Update: i++ increments the value of i after each iteration.

Output: 0 1 2 3 4

The loop stops when i reaches 5 because the condition i < 5 becomes false.

for Loop:

The for loop is commonly used when you know exactly how many times you want the loop to run. It has three components: initialization, condition, and increment—all in one line for better readability.

for (init; condition; increment) {
    // code
}
for (int i = 0; i < 5; i++) {
    printf("%d ", i);
}

Explanation:
This for loop prints numbers from 0 to 4.

  • Initialization:int i = 0 initializes the loop counter.
  • Condition:i < 5 checks if the loop should continue running.
  • Increment:i++ increases i by 1 after each iteration.

Output: 0 1 2 3 4

The for loop is often preferred when the number of iterations is known in advance because it keeps all control logic in one line.

do-while Loop:

The do-while loop is similar to the while loop, but with one key difference: it guarantees that the code inside the loop will execute at least once, even if the condition is false. This is because the condition is checked after the code runs.

do {
    // code
} while (condition);
Example:
int i = 0;
do {
    printf("%d ", i);
    i++;
} while (i < 5);

Explanation:

  • The code inside the do block runs first.
  • After the first execution, the condition i < 5 is checked.
  • If true, the loop repeats; if false, it stops.

Output: 0 1 2 3 4

Even if i was initially set to a value like 10, the loop would still print 10 once before stopping because the condition is checked after the first run.

Key Differences Between Loop Types:

Loop TypeWhen Condition is CheckedGuaranteed to Run at Least Once?Common Use Case
whileBefore the loop startsNoWhen the number of iterations is unknown
forBefore each iterationNoWhen the number of iterations is known
do-whileAfter the loop runsYesWhen code must run at least once
Key Takeaways:

while loops are great when you don’t know how many times you’ll need to repeat the code.for loops are ideal when you know the exact number of iterations in advance.do-while loops ensure the code runs at least once, even if the condition is false.

Jump Statements:

break:

Exits the nearest enclosing loop or switch.

continue:

Skips the rest of the current iteration and moves to the next one.

goto:

Transfers control to a labeled statement.

Functions

Functions are reusable blocks of code that perform specific tasks.

Function Declaration:

return-type function_name(parameter_list) {
    // function body
}
int add(int a, int b) {
    return a + b;
}

int main() {
    int result = add(5, 3);
    printf("%d", result);
    return 0;
}

Explanation:

  • Function Declaration: int add(int a, int b) defines a function that takes two integers and returns their sum.
  • Calling the Function: In main(), add(5, 3) is called, and it returns 8, which gets printed.

Passing Parameters:

By Value:

The actual value is passed, and changes inside the function do not affect the original variable.

void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

By Reference:

Using pointers to modify the original variables.

void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

Return Values:

Functions can return a single value using the return statement.

Arrays and Strings

Arrays store multiple values of the same type, and strings are arrays of characters.

Array Initialization:

int scores[5] = {1, 2, 3, 4, 5};

Accessing Elements:

printf("%d", scores[0]); // Outputs 1

Multidimensional Arrays:

int matrix[2][3] = {{1, 2, 3}, {4, 5, 6}};

Strings in C:

Strings are null-terminated character arrays.

char name[] = "Hello";

String Functions:

strlen(), strcpy(), strcmp(), strcat()

Pointers and Memory Management

Pointers hold memory addresses and allow direct manipulation of memory.

Pointer Declaration:

int var = 20;
int *ptr = &var;
int x = 10;
int *ptr = &x;
printf("%d", *ptr);

Explanation:

  • Pointer Declaration: int *ptr declares a pointer to an integer.
  • Address Assignment: &x assigns the memory address of x to ptr.
  • Dereferencing: *ptr accesses the value stored at the memory address, which is 10.

Array and Pointer Relationship:

Arrays decay into pointers when passed to functions.

void printArray(int arr[]) {
    // arr is a pointer to the first element
}

Dynamic Memory Allocation:

malloc():

Allocates memory at runtime.

int *ptr = (int*) malloc(sizeof(int));

calloc(), realloc(), free() for managing dynamic memory.

Structures and Unions

Structures bundle different data types into a single unit, while unions store different data types in the same memory space.

Structure Declaration:

struct Student {
    int roll;
    char name[20];
    float marks;
};

Accessing Members:

struct Student s1 = {1, "John", 85.5};
printf("%d", s1.roll);

Union Declaration:

union Data {
    int i;
    float f;
};

File Handling

Reading from and writing to files allows data persistence.

Opening Files:

FILE *fp = fopen("file.txt", "r");

Reading and Writing:

  • fscanf(), fpritnf()
  • fgets(), fputs()
  • fclose(fp) to close the file.

Best Practices and Common Errors

  • Use meaningful variable names and follow a consistent coding style.
  • Always check for memory leaks when using dynamic allocation.
  • Handle potential errors in functions like malloc() and fopen().
  • Avoid buffer overflow by using functions with bounds checking.

Conclusion:

That wraps up Part 2 of the C Programming Basics series! We’ve covered key concepts like control flow, functions, arrays, pointers, and even file handling. These topics are the building blocks for writing more complex C programs.

If any of these concepts feel tricky, don’t worry—C can be challenging when you’re just starting out. The key is to practice by writing small programs and experimenting with different code examples. If you missed Part 1, be sure to check it out to solidify your fundamentals.

Stay tuned for Part 3, where we’ll explore even more about C programming. Happy coding!

Have questions or want to share your thoughts? Drop a comment below—I’d love to hear from you!


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *