Advanced topics

1. Preprocessor Directives

Preprocessor directives are instructions that are processed before the actual compilation of the code begins. They start with the # symbol and are used for tasks like including files or defining constants.

#define

The #define directive defines a constant or macro. It helps make the code more readable and easier to maintain.

Syntax:

#define NAME value

Example:

#include <stdio.h>

#define PI 3.14159  // Define a constant for PI

int main() {
    printf("Value of PI: %.5f\n", PI);  // Use the defined constant
    return 0;
}
  • #define PI 3.14159: Defines PI as 3.14159.

  • This allows us to use PI in our code instead of writing the number directly each time.

#include

The #include directive is used to include the contents of one file within another file. It’s commonly used to include standard library headers or other user-defined files.

Syntax:

#include <header.h>    // For standard library headers
#include "myheader.h"  // For user-defined headers

Example:

#include <stdio.h>  // Include standard I/O functions
#include "myheader.h"  // Include a user-defined header file

int main() {
    printf("Hello, World!\n");
    return 0;
}
  • #include <stdio.h>: Includes the standard input/output library.

  • #include "myheader.h": Includes a custom header file named myheader.h.


2. Command Line Arguments

Command line arguments are used to pass additional information to a program when it is executed. They provide a way to control the behavior of the program from the command line.

Syntax:

int main(int argc, char *argv[]) {
    // argc: Number of command line arguments
    // argv: Array of strings representing the arguments
}

Example:

#include <stdio.h>

int main(int argc, char *argv[]) {
    printf("Number of arguments: %d\n", argc);
    
    for (int i = 0; i < argc; i++) {
        printf("Argument %d: %s\n", i, argv[i]);
    }
    
    return 0;
}
  • argc: Counts how many arguments were passed to the program.

  • argv: An array of strings, where each string is one of the command line arguments.

Running the Program:

$ ./program arg1 arg2
Number of arguments: 3
Argument 0: ./program
Argument 1: arg1
Argument 2: arg2

3. Linked Lists

A linked list is a data structure where each element (node) points to the next one, forming a chain. This allows for flexible memory usage and easy insertion and deletion of elements.

Basic Linked List Node

Definition:

typedef struct Node {
    int data;          // Data part
    struct Node *next; // Pointer to the next node
} Node;

Example:

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int data;
    struct Node *next;
} Node;

int main() {
    // Create nodes
    Node *head = (Node *)malloc(sizeof(Node));
    Node *second = (Node *)malloc(sizeof(Node));
    Node *third = (Node *)malloc(sizeof(Node));
    
    // Assign data and link nodes
    head->data = 1;
    head->next = second;
    
    second->data = 2;
    second->next = third;
    
    third->data = 3;
    third->next = NULL;
    
    // Traverse and print list
    Node *temp = head;
    while (temp != NULL) {
        printf("%d -> ", temp->data);
        temp = temp->next;
    }
    printf("NULL\n");
    
    // Free memory
    free(head);
    free(second);
    free(third);
    
    return 0;
}
  • Node Structure: Contains data and a pointer to the next node.

  • Traversal: Moving from the head node through each next node until reaching NULL.


4. Stacks

A stack is a data structure that follows the Last In, First Out (LIFO) principle. It has two main operations: push (add an item) and pop (remove an item).

Stack Implementation Using Linked List

Example:

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int data;
    struct Node *next;
} Node;

typedef struct Stack {
    Node *top;
} Stack;

// Function to create a new stack
Stack *createStack() {
    Stack *stack = (Stack *)malloc(sizeof(Stack));
    stack->top = NULL;
    return stack;
}

// Push an item onto the stack
void push(Stack *stack, int data) {
    Node *newNode = (Node *)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = stack->top;
    stack->top = newNode;
}

// Pop an item from the stack
int pop(Stack *stack) {
    if (stack->top == NULL) {
        printf("Stack is empty\n");
        return -1;
    }
    Node *temp = stack->top;
    int data = temp->data;
    stack->top = stack->top->next;
    free(temp);
    return data;
}

// Print the stack
void printStack(Stack *stack) {
    Node *temp = stack->top;
    while (temp != NULL) {
        printf("%d -> ", temp->data);
        temp = temp->next;
    }
    printf("NULL\n");
}

int main() {
    Stack *stack = createStack();
    
    push(stack, 10);
    push(stack, 20);
    push(stack, 30);
    
    printStack(stack);
    
    printf("Popped: %d\n", pop(stack));
    printStack(stack);
    
    return 0;
}
  • Push: Adds a new item to the top of the stack.

  • Pop: Removes and returns the item from the top of the stack.


5. Queues

A queue is a data structure that follows the First In, First Out (FIFO) principle. It has two main operations: enqueue (add an item) and dequeue (remove an item).

Queue Implementation Using Linked List

Example:

#include <stdio.h>
#include <stdlib.h>

typedef struct Node {
    int data;
    struct Node *next;
} Node;

typedef struct Queue {
    Node *front;
    Node *rear;
} Queue;

// Function to create a new queue
Queue *createQueue() {
    Queue *queue = (Queue *)malloc(sizeof(Queue));
    queue->front = NULL;
    queue->rear = NULL;
    return queue;
}

// Enqueue an item
void enqueue(Queue *queue, int data) {
    Node *newNode = (Node *)malloc(sizeof(Node));
    newNode->data = data;
    newNode->next = NULL;
    if (queue->rear == NULL) {
        queue->front = newNode;
        queue->rear = newNode;
    } else {
        queue->rear->next = newNode;
        queue->rear = newNode;
    }
}

// Dequeue an item
int dequeue(Queue *queue) {
    if (queue->front == NULL) {
        printf("Queue is empty\n");
        return -1;
    }
    Node *temp = queue->front;
    int data = temp->data;
    queue->front = queue->front->next;
    if (queue->front == NULL) {
        queue->rear = NULL;
    }
    free(temp);
    return data;
}

// Print the queue
void printQueue(Queue *queue) {
    Node *temp = queue->front;
    while (temp != NULL) {
        printf("%d -> ", temp->data);
        temp = temp->next;
    }
    printf("NULL\n");
}

int main() {
    Queue *queue = createQueue();
    
    enqueue(queue, 10);
    enqueue(queue, 20);
    enqueue(queue, 30);
    
    printQueue(queue);
    
    printf("Dequeued: %d\n", dequeue(queue));
    printQueue(queue);
    
    return 0;
}
  • Enqueue: Adds a new item to the rear of the queue.

  • Dequeue: Removes and returns the item from the front of the queue.


Summary

  • Preprocessor Directives: #define for constants, #include for file inclusion.

  • Command Line Arguments: Access program arguments from the command line.

  • Linked Lists: Dynamic data structures with nodes linked together.

  • Stacks: LIFO structure with push and pop operations.

  • Queues: FIFO structure with enqueue and dequeue operations.

Last updated

Was this helpful?