Skip to content

C Programming Essentials I

Getting Started

What is Cling?

Cling is an interactive C/C++ interpreter built on top of LLVM and Clang. It allows you to write and execute C code snippets interactively, similar to how Python or JavaScript REPLs work.

This is useful for quickly testing code, learning C, and experimenting without creating full source files and compiling them.

Installing Cling

1. Download Cling:

  • Go to the official Cling releases page
  • Choose the version appropriate for your operating system (Windows, macOS, or Linux).
  • Download the archive (ZIP or tar.gz).

2. Extract Cling:

  • Extract the downloaded archive to a folder of your choice.

3. Add Cling to your PATH (optional but recommended):

  • Add the bin directory inside the extracted folder to your system's PATH environment variable so you can run cling from the terminal conveniently.

Basic Syntax

Hello World and Program Structure

#include <stdio.h>              // Preprocessor directive

int main() {                    // Main function - entry point
    printf("Hello, World!\n");  // Function call
    return 0;                   // Return statement
}

Variables and Constants

#include <stdio.h>

int main() {
    // Variable declarations
    int age = 25;
    float height = 5.9f;
    char grade = 'A';

    // Constants
    const int MAX_SIZE = 100;
    #define PI 3.14159  // Preprocessor constant

    return 0;
}

Operators

#include <stdio.h>

int main() {
    int a = 10, b = 3;

    // Arithmetic operators
    printf("a + b = %d\n", a + b);  // Addition
    printf("a - b = %d\n", a - b);  // Subtraction
    printf("a * b = %d\n", a * b);  // Multiplication
    printf("a / b = %d\n", a / b);  // Division (integer)
    printf("a %% b = %d\n", a % b); // Modulus

    // Comparison operators
    printf("a == b: %d\n", a == b); // Equal
    printf("a != b: %d\n", a != b); // Not equal
    printf("a > b: %d\n", a > b);   // Greater than
    printf("a < b: %d\n", a < b);   // Less than

    // Logical operators
    int x = 1, y = 0;
    printf("x && y: %d\n", x && y); // Logical AND
    printf("x || y: %d\n", x || y); // Logical OR
    printf("!x: %d\n", !x);         // Logical NOT

    return 0;
}

Control Structures

#include <stdio.h>

int main() {
    int num = 15;

    // If-else statement
    if (num > 10) {
        printf("%d is greater than 10\n", num);
    } else if (num == 10) {
        printf("%d is equal to 10\n", num);
    } else {
        printf("%d is less than 10\n", num);
    }

    // Switch statement
    char grade = 'B';
    switch (grade) {
        case 'A':
            printf("Excellent!\n");
            break;
        case 'B':
            printf("Good job!\n");
            break;
        case 'C':
            printf("Well done\n");
            break;
        default:
            printf("Keep trying\n");
            break;
    }

    // For loop
    printf("For loop: ");
    for (int i = 0; i < 5; i++) {
        printf("%d ", i);
    }
    printf("\n");

    // While loop
    printf("While loop: ");
    int j = 0;
    while (j < 5) {
        printf("%d ", j);
        j++;
    }
    printf("\n");

    // Do-while loop
    printf("Do-while loop: ");
    int k = 0;
    do {
        printf("%d ", k);
        k++;
    } while (k < 5);
    printf("\n");

    return 0;
}

Functions and Parameter Passing

#include <stdio.h>

// Function declaration (prototype)
int add(int a, int b);
void greet(char name[]);
int factorial(int n);
void swap_by_value(int a, int b);
void swap_by_pointer(int *a, int *b);

int main() {
    int result = add(5, 3);
    printf("5 + 3 = %d\n", result);

    greet("Alice");

    printf("5! = %d\n", factorial(5));

    // Call by value vs Call by pointer
    int x = 10, y = 20;
    printf("Before swap: x=%d, y=%d\n", x, y);

    swap_by_value(x, y);  // Won't actually swap
    printf("After call by value: x=%d, y=%d\n", x, y);

    swap_by_pointer(&x, &y);  // Will swap
    printf("After call by pointer: x=%d, y=%d\n", x, y);

    return 0;
}

// Function definitions
int add(int a, int b) {
    return a + b;
}

void greet(char name[]) {
    printf("Hello, %s!\n", name);
}

int factorial(int n) {
    if (n <= 1) {
        return 1;
    }
    return n * factorial(n - 1);  // Recursive function
}

// Call by value - parameters are copies
void swap_by_value(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
    printf("Inside swap_by_value: a=%d, b=%d\n", a, b);
}

// Call by pointer - parameters are addresses
void swap_by_pointer(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
    printf("Inside swap_by_pointer: *a=%d, *b=%d\n", *a, *b);
}

Data Types and Memory Layout

Basic Data Types

#include <stdio.h>

int main() {
    char c = 'A';           // 1 byte
    short s = 1000;         // 2 bytes
    int i = 100000;         // 4 bytes (typically)
    long l = 1000000L;      // 8 bytes (on 64-bit)
    float f = 3.14f;        // 4 bytes
    double d = 3.14159;     // 8 bytes

    printf("Sizes: char=%zu, int=%zu, long=%zu\n", 
           sizeof(c), sizeof(i), sizeof(l));

    return 0;
}

Arrays and Strings

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

int main() {
    // Array declaration and initialization
    int numbers[5] = {1, 2, 3, 4, 5};
    char vowels[] = {'a', 'e', 'i', 'o', 'u'};

    // String handling
    char message[6] = "Hello";  // Actually stores: 'H','e','l','l','o','\0'
    char buffer[128];           // Can store 127 characters + null terminator

    // Single quotes ' are used for char
    // Double quotes " are used for string (null-terminated array of char)

    printf("Message: %s (length: %zu)\n", message, strlen(message));
    printf("Buffer size: %zu bytes\n", sizeof(buffer));
    printf("Max string length in buffer: %zu characters\n", sizeof(buffer) - 1);

    // Demonstrating null terminator
    printf("Characters in 'Hello':\n");
    for (int i = 0; i <= 5; i++) {
        printf("message[%d] = '%c' (ASCII: %d)\n", i, message[i], message[i]);
    }

    // String input with proper bounds checking
    printf("Enter a string (max 127 chars): ");
    if (fgets(buffer, sizeof(buffer), stdin)) {
        // Remove newline
        size_t len = strlen(buffer);
        if (len > 0 && buffer[len-1] == '\n') {
            buffer[len-1] = '\0';
        }
        printf("You entered: %s\n", buffer);
    }

    return 0;
}

Boolean Logic in C

#include <stdio.h>
#include <stdbool.h>  // C99 standard - provides bool, true, false

int main() {
    // C does not have built-in Boolean values
    // 0 represents False, any non-zero value represents True

    int is_valid = 1;      // True
    int is_empty = 0;      // False
    int count = 42;        // Also True

    printf("Boolean demonstrations:\n");
    printf("is_valid (1): %s\n", is_valid ? "True" : "False");
    printf("is_empty (0): %s\n", is_empty ? "True" : "False");
    printf("count (42): %s\n", count ? "True" : "False");

    // Using stdbool.h (C99 and later)
    bool true_flag = true;
    bool false_flag = false;

    printf("\nUsing stdbool.h:\n");
    printf("true_flag: %s\n", true_flag ? "True" : "False");
    printf("false_flag: %s\n", false_flag ? "True" : "False");

    // Logical operations return 0 or 1
    int result = (5 > 3);  // result will be 1
    printf("5 > 3 evaluates to: %d\n", result);

    return 0;
}

Endianness

#include <stdio.h>

void check_endianness() {
    unsigned int x = 0x12345678;
    unsigned char *ptr = (unsigned char*)&x;

    printf("Address: %p\n", ptr);
    printf("Byte 0: 0x%02x\n", ptr[0]);
    printf("Byte 1: 0x%02x\n", ptr[1]);
    printf("Byte 2: 0x%02x\n", ptr[2]);
    printf("Byte 3: 0x%02x\n", ptr[3]);

    if (ptr[0] == 0x78) {
        printf("Little Endian\n");
    } else {
        printf("Big Endian\n");
    }
}

Basic Pointers

Introduction to Pointers

#include <stdio.h>

int main() {
    int value = 42;
    int *ptr = &value;

    // & is the "address-of" operator; 
    // it gives the memory address of a variable.  

    // * is the "dereference" operator; 
    // it accesses the value stored at a memory address (pointer)

    printf("value = %d\n", value);
    printf("Address of value (&value) = %p\n", &value);
    printf("ptr = %p\n", ptr);
    printf("Value pointed to by ptr (*ptr) = %d\n", *ptr);
    printf("Address of ptr (&ptr) = %p\n", &ptr);

    // Modifying through pointer
    *ptr = 100;
    printf("After *ptr = 100, value = %d\n", value);

    return 0;
}

Pointers and Arrays

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *ptr = arr;  // arr is a pointer to first element

    printf("Array elements using different notations:\n");
    for (int i = 0; i < 5; i++) {
        printf("arr[%d] = %d, *(arr+%d) = %d, *(ptr+%d) = %d\n", 
               i, arr[i], i, *(arr + i), i, *(ptr + i));
    }

    // Pointer arithmetic
    printf("\nPointer arithmetic:\n");
    printf("ptr points to: %d\n", *ptr);
    ptr++;  // Move to next element
    printf("After ptr++, points to: %d\n", *ptr);

    return 0;
}