Chapter 2: C Programming Fundamentals - Grade 12

1. Functions in C

A function is a block of code that performs a specific task. By dividing a complex program into smaller, manageable functions, it becomes easier to understand, debug, and maintain. Functions are a core part of modular programming in C.

Introduction and Syntax

A function in C consists of a declaration (prototype), a definition, and a call. It takes input (arguments), processes it, and returns an output.


// Function Prototype (Declaration)
returnType functionName(dataType parameter1, dataType parameter2, ...);

// Function Definition
returnType functionName(dataType parameter1, dataType parameter2, ...) {
    // block of code to be executed
    ...
    return value; // Optional
}

// Function Call
result = functionName(argument1, argument2, ...);
    

Purpose and Advantages of Functions

Components of a Function

Types of Functions

Functions can be broadly categorized into two types:

Passing Arguments

Arguments can be passed to functions in two main ways:

Variable and its Scope

The scope of a variable determines where it can be accessed within a program.

Storage Classes

Storage classes determine the scope, lifetime, and storage location of variables.

Function with Array Example

To pass an array to a function, you pass the array's name, which decays into a pointer to its first element. The function can then access and modify the array's elements.


#include <stdio.h>

void printArray(int arr[], int size) {
    printf("Elements of array: ");
    for (int i = 0; i < size; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
}

int main() {
    int myArray[] = {10, 20, 30, 40, 50};
    int n = sizeof(myArray) / sizeof(myArray[0]);
    printArray(myArray, n);
    return 0;
}
    

Recursive Function

A recursive function is a function that calls itself. It is used to solve problems that can be broken down into smaller, self-similar sub-problems.

Syntax:


void recursiveFunction() {
    if (condition) {
        // base case to stop recursion
        return;
    }
    recursiveFunction(); // recursive call
}
    

Example: Factorial Calculation


#include <stdio.h>

long long factorial(int n) {
    // Base case: to stop the recursion
    if (n >= 1) {
        return n * factorial(n - 1);
    } else {
        return 1;
    }
}

int main() {
    int number = 5;
    printf("Factorial of %d = %lld\n", number, factorial(number));
    return 0;
}
    

Advantages and Disadvantages of Recursion:

2. Structure and Union

Structures and Unions are user-defined data types in C that allow you to combine different data types under a single name.

Structure (struct)

A structure is a collection of variables of different data types under a single name. Each member in a structure has its own memory location.

Introduction and Syntax:


// Defining a structure
struct Student {
    char name[50];
    int rollNumber;
    float marks;
};
    

Structure Size and Accessing Members:

The size of a structure is the sum of the sizes of all its members, plus any padding added by the compiler. You can access members using the dot (.) operator.


#include <stdio.h>
#include <string.h>

struct Student {
    char name[50];
    int rollNumber;
    float marks;
};

int main() {
    struct Student s1;
    strcpy(s1.name, "Alice");
    s1.rollNumber = 101;
    s1.marks = 85.5;

    printf("Student Name: %s\n", s1.name);
    printf("Roll Number: %d\n", s1.rollNumber);
    printf("Marks: %.2f\n", s1.marks);

    printf("Size of Student structure: %lu bytes\n", sizeof(struct Student));
    return 0;
}
    

Nested Structure

A nested structure is a structure that contains another structure as one of its members.


#include <stdio.h>
#include <string.h>

struct DateOfBirth {
    int day;
    int month;
    int year;
};

struct Student {
    char name[50];
    int rollNumber;
    struct DateOfBirth dob; // Nested structure
};

int main() {
    struct Student s1;
    strcpy(s1.name, "Bob");
    s1.rollNumber = 102;
    s1.dob.day = 15;
    s1.dob.month = 6;
    s1.dob.year = 2005;

    printf("Student Name: %s\n", s1.name);
    printf("Date of Birth: %d-%d-%d\n", s1.dob.day, s1.dob.month, s1.dob.year);
    return 0;
}
    

Array of Structure

An array of structures allows you to store multiple records of the same structure type.


#include <stdio.h>

struct Student {
    char name[50];
    int rollNumber;
};

int main() {
    struct Student class[3]; // Array of 3 Student structures

    class[0].rollNumber = 101;
    strcpy(class[0].name, "Alice");
    class[1].rollNumber = 102;
    strcpy(class[1].name, "Bob");
    class[2].rollNumber = 103;
    strcpy(class[2].name, "Charlie");

    for (int i = 0; i < 3; i++) {
        printf("Student %d: %s (Roll No: %d)\n", i+1, class[i].name, class[i].rollNumber);
    }
    return 0;
}
    

Passing Structure to Function

You can pass an entire structure to a function, either by value or by reference (using pointers).


#include <stdio.h>

struct Point {
    int x;
    int y;
};

// Pass by value
void printPoint(struct Point p) {
    printf("Point coordinates (pass by value): (%d, %d)\n", p.x, p.y);
}

// Pass by reference
void modifyPoint(struct Point *p) {
    p->x = 20;
    p->y = 40;
}

int main() {
    struct Point p1 = {10, 20};
    printPoint(p1);
    modifyPoint(&p1);
    printf("Modified point coordinates (pass by reference): (%d, %d)\n", p1.x, p1.y);
    return 0;
}
    

Union (union)

A union is a special data type that allows different members to share the **same memory location**. The size of a union is determined by its largest member.

Introduction and Syntax:


// Defining a union
union Data {
    int i;
    float f;
    char str[20];
};
    

Comparison between Structure and Union

Feature Structure Union
Memory Allocation Each member has its own unique memory location. All members share the same memory location.
Size Sum of the sizes of all its members (plus padding). Equal to the size of the largest member.
Value Storage All members can store values simultaneously. Only one member can store a value at a time. The last assigned value overwrites previous ones.
Keyword struct union

3. Pointers

A pointer is a variable that stores the memory address of another variable. It is a fundamental and powerful concept in C.

Introduction and Syntax:

Pointers are declared using an asterisk (*).


dataType *pointerName;
    

The address of a variable is obtained using the address-of operator (&), and the value at an address is accessed using the dereference operator (*).

Concept of Value and Address

Every variable has a value and a memory address. The value is the data stored in that memory location, and the address is the location itself. A pointer holds an address as its value.

Declaration and Initialization:


#include <stdio.h>

int main() {
    int var = 10;
    int *ptr; // Pointer declaration
    ptr = &var; // Pointer initialization (stores address of var)

    printf("Value of var: %d\n", var);
    printf("Address of var: %p\n", &var);
    printf("Value stored in ptr (address): %p\n", ptr);
    printf("Value pointed to by ptr: %d\n", *ptr);
    return 0;
}
    

Pointer and Function: Call by Reference

Pointers are essential for implementing "call by reference," allowing a function to modify the actual variables in the calling function. The address is passed to the function, and the pointer inside the function can dereference it to modify the original value.


#include <stdio.h>

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

int main() {
    int x = 10, y = 20;
    printf("Before swap: x = %d, y = %d\n", x, y);
    swap(&x, &y); // Pass addresses
    printf("After swap: x = %d, y = %d\n", x, y);
    return 0;
}
    

Comparison between Call by Value and Call by Reference:

Aspect Call by Value Call by Reference
What is Passed A copy of the argument's value. The memory address of the argument.
Modification Changes inside the function do not affect the original variable. Changes inside the function do affect the original variable.
Memory Separate memory is allocated for the parameter. The same memory location is used for the variable.
Use Case When you want to protect the original data from modification. When you need to modify the original data.

Pointer with Arrays

An array's name acts as a constant pointer to its first element. This means you can use pointers to access and traverse array elements.


#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *ptr = arr; // ptr points to the first element (arr[0])

    // Accessing elements using pointer arithmetic
    printf("Value of arr[0]: %d\n", *ptr);
    printf("Value of arr[1]: %d\n", *(ptr + 1));
    printf("Value of arr[2]: %d\n", *(ptr + 2));
    
    // Traversing the array
    printf("\nTraversing array with pointer:\n");
    for(int i = 0; i < 5; i++) {
        printf("%d ", *(ptr + i));
    }
    printf("\n");
    return 0;
}
    

Advantages and Disadvantages of Pointers:

4. File Handling

File handling in C allows a program to store and retrieve data from files on disk, ensuring data persistence even after the program terminates.

Concept of Data File and Need for File Handling in C

A data file is a collection of related records stored on a physical storage device. File handling is necessary for managing data that needs to be stored permanently and shared between different program executions.

Files can be categorized as **Sequential** (accessed in a sequence from beginning to end) or **Random** (accessed directly at any location). Most of the file handling functions are for sequential access.

File Handling Functions

These are standard library functions for performing file operations. All of them use a file pointer (FILE*).

Random Access Functions

These functions allow you to move the file pointer to any location in the file for random access.

File Opening Modes

Steps to Work with File in C

  1. Define File Pointer: Create a pointer of type FILE. Example: FILE *fp;
  2. Open File with Required Mode: Use fopen() to open the file.
  3. Read, Write, Append Operations: Perform the desired operation using appropriate functions.
  4. Close the File: Use fclose() to close the file and save changes.

Reading Data from Files:


#include <stdio.h>

int main() {
    FILE *fp;
    char buffer[100];
    fp = fopen("example.txt", "r");
    if (fp == NULL) {
        printf("Error opening file!\n");
        return 1;
    }
    while (fgets(buffer, 100, fp) != NULL) {
        printf("%s", buffer);
    }
    fclose(fp);
    return 0;
}
    

Writing Data on Files:


#include <stdio.h>

int main() {
    FILE *fp;
    fp = fopen("example_write.txt", "w");
    if (fp == NULL) {
        printf("Error creating file!\n");
        return 1;
    }
    fprintf(fp, "Hello, world!\n");
    fprintf(fp, "This is a test.");
    fclose(fp);
    printf("Data written to file successfully.\n");
    return 0;
}
    

Appending Data Files:


#include <stdio.h>

int main() {
    FILE *fp;
    fp = fopen("example_write.txt", "a");
    if (fp == NULL) {
        printf("Error opening file!\n");
        return 1;
    }
    fprintf(fp, "\nAppending a new line.");
    fclose(fp);
    printf("Data appended to file successfully.\n");
    return 0;
}
    

End of File (EOF)

EOF is a macro defined in stdio.h that stands for "End of File." It's a special constant value returned by file input functions (like getc() or fscanf()) to indicate that the end of the file has been reached, preventing the program from reading beyond the file's content.

5. The typedef Keyword

The typedef keyword is used to create an alias or a new name for an existing data type. It is commonly used to make code more readable and portable.

Syntax:


typedef existing_dataType new_name;
    

Example:


#include <stdio.h>

typedef unsigned int UINT;
typedef struct Student Student;

struct Student {
    char name[50];
    int rollNumber;
};

int main() {
    UINT number = 100;
    Student s1; // Using the new alias
    s1.rollNumber = 20;

    printf("Number: %u\n", number);
    printf("Student roll number: %d\n", s1.rollNumber);
    return 0;
}