C Programming Fundamentals and Practical Code Examples

Unary, Binary, and Ternary Operators in C

A unary operator in C is an operator that works on only one operand. Common unary operators include ++ (increment), -- (decrement), - (unary minus), ! (logical NOT), and sizeof.

A binary operator in C is an operator that works on two operands. Examples include:

  • Arithmetic operators: +, -, *, /, %
  • Relational operators: ==, !=, >, <, >=, <=
  • Logical operators: &&, ||
  • Bitwise operators: &, |, >>, <<
  • Assignment operators: =, +=, -=, *=, /=

The ternary operator in C (?:) is a conditional operator that works on three operands. It is used as a shorthand for the if–else statement.

Syntax: condition ? expression1 : expression2

Data Types and Function Declarations

A data type is a classification that specifies the type of data a variable can store in a program. It determines the memory size, range of values, and operations that can be performed on the data. Primitive data types are basic data types provided by C, such as int, char, float, and double.

Function Pointer Declaration

int *fun(char *, int *);

This declares a function fun that takes a character pointer and an integer pointer as arguments and returns an integer pointer.

Call by Value vs. Call by Reference

Call by Value: In call by value, a copy of the actual variable is passed to the function. Any changes made inside the function do not affect the original variable.

#include <stdio.h>

void change(int x) {
    x = 10;
}

int main() {
    int a = 5;
    change(a);
    printf("%d", a); // Output: 5
    return 0;
}

Call by Reference: In call by reference, the address of the variable is passed to the function. Changes made inside the function directly affect the original variable.

#include <stdio.h>

void change(int *x) {
    *x = 10;
}

int main() {
    int a = 5;
    change(&a);
    printf("%d", a); // Output: 10
    return 0;
}

Dynamic Memory Allocation: malloc vs. calloc

Dynamic memory allocation allows memory allocation at runtime.

  • malloc(): Allocates a single block of memory.
  • calloc(): Allocates multiple blocks and initializes memory to zero.

Loop Control and Prime Number Summation

Entry-controlled vs. Exit-controlled Loops

  • Entry-controlled loop: The condition is checked before execution (e.g., for, while).
  • Exit-controlled loop: The condition is checked after execution (e.g., do-while).

Program: Sum of Prime Numbers from 1 to N

#include <stdio.h>

int isPrime(int n) {
    int i;
    if (n < 2) return 0;
    for (i = 2; i <= n/2; i++)
        if (n % i == 0) return 0;
    return 1;
}

int main() {
    int n, i, sum = 0;
    scanf("%d", &n);
    for (i = 1; i <= n; i++)
        if (isPrime(i))
            sum += i;
    printf("%d", sum);
    return 0;
}

Matrix Multiplication and String Reversal

Program: Multiply Two n×n Matrices

#include <stdio.h>

int main() {
    int n, i, j, k;
    int a[10][10], b[10][10], c[10][10] = {0};
    scanf("%d", &n);
    for(i=0; i<n; i++)
        for(j=0; j<n; j++)
            scanf("%d", &a[i][j]);
    for(i=0; i<n; i++)
        for(j=0; j<n; j++)
            scanf("%d", &b[i][j]);
    for(i=0; i<n; i++)
        for(j=0; j<n; j++)
            for(k=0; k<n; k++)
                c[i][j] += a[i][k] * b[k][j];
    for(i=0; i<n; i++) {
        for(j=0; j<n; j++)
            printf("%d ", c[i][j]);
        printf("\n");
    }
    return 0;
}

Program: Reverse a String Using Pointers

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

int main() {
    char str[100], *p, temp;
    int i, len;
    scanf("%s", str);
    len = strlen(str);
    p = str;
    for(i=0; i<len/2; i++) {
        temp = *(p+i);
        *(p+i) = *(p+len-i-1);
        *(p+len-i-1) = temp;
    }
    printf("%s", str);
    return 0;
}

File Handling: Word Count and Frequency

The following program reads words from input.txt, counts the total number of words, and tracks the most frequent word.

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

#define MAX_WORDS 20000
#define WORD_LEN 50

int main() {
    FILE *fp;
    char word[WORD_LEN];
    char words[MAX_WORDS][WORD_LEN];
    int count[MAX_WORDS] = {0};
    int totalWords = 0, uniqueWords = 0;
    int i, maxIndex = 0;

    fp = fopen("input.txt", "r");
    if (fp == NULL) {
        printf("File not found");
        return 0;
    }

    while (fscanf(fp, "%s", word) != EOF) {
        for (i = 0; word[i]; i++) word[i] = tolower(word[i]);
        totalWords++;
        for (i = 0; i < uniqueWords; i++) {
            if (strcmp(words[i], word) == 0) {
                count[i]++;
                break;
            }
        }
        if (i == uniqueWords) {
            strcpy(words[uniqueWords], word);
            count[uniqueWords] = 1;
            uniqueWords++;
        }
    }
    fclose(fp);

    for (i = 1; i < uniqueWords; i++) {
        if (count[i] > count[maxIndex]) maxIndex = i;
    }

    printf("Total number of words = %d\n", totalWords);
    printf("Most frequent word = %s\n", words[maxIndex]);
    printf("Frequency = %d\n", count[maxIndex]);
    return 0;
}

Currency Denomination and Storage Classes

Program: Currency Denomination

#include <stdio.h>

int main() {
    int amt;
    scanf("%d", &amt);
    printf("100 = %d\n", amt/100); amt %= 100;
    printf("50 = %d\n", amt/50); amt %= 50;
    printf("20 = %d\n", amt/20); amt %= 20;
    printf("10 = %d\n", amt/10); amt %= 10;
    printf("5 = %d\n", amt/5); amt %= 5;
    printf("1 = %d\n", amt);
    return 0;
}

Scope, Visibility, and Lifetime of Variables

  • auto: Local scope, block visibility, lifetime within the block.
  • register: Same as auto but stored in a CPU register for faster access.
  • static: Local scope, but the lifetime persists throughout the program.
  • external: Global scope, visible across multiple files.

Command Line Arguments, Structures, and Unions

argc and argv

argc is the argument count, and argv is the argument vector (an array of strings).

#include <stdio.h>

int main(int argc, char *argv[]) {
    int count = 0, i;
    for(i=1; i<argc; i++) count++;
    printf("%d", count);
    return 0;
}

Structures vs. Unions

  • Structure: A user-defined data type that groups different types. It allocates memory for all members.
  • Union: All members share the same memory location. It allocates memory equal to the largest member.

Error Types and Branching Statements

Types of Errors

  • Syntax error: A grammar mistake (e.g., missing ;).
  • Logical error: The program runs but gives the wrong output (e.g., + instead of *).
  • Runtime error: Occurs during execution (e.g., division by zero).

Branching Statements

  1. if statement: Executes code if a condition is true.
  2. if-else statement: Provides an alternative path if the condition is false.
  3. else-if ladder: Checks multiple conditions in sequence.
  4. switch statement: Selects one of many code blocks to be executed.

Arrays and Matrix Operations

An array is a collection of similar data elements stored in contiguous memory locations.

  • 1-D Array: int a[5];
  • 2-D Array: int a[3][3];

Program: Difference Between Diagonal and Row Sum

#include <stdio.h>

int main() {
    int m, n, i, j, a[10][10], diagSum = 0, rowSum = 0;
    scanf("%d %d", &m, &n);
    for(i=0; i<m; i++)
        for(j=0; j<n; j++)
            scanf("%d", &a[i][j]);
    for(i=0; i<m; i++) diagSum += a[i][i];
    for(j=0; j<n; j++) rowSum += a[0][j];
    printf("Difference = %d", diagSum - rowSum);
    return 0;
}

Functions and Tribonacci Recursion

Functions are classified into four types based on arguments and return values:

  1. No arguments, no return value.
  2. Arguments, no return value.
  3. No arguments, return value.
  4. Arguments and return value.

Recursive Program for Tribonacci Series

#include <stdio.h>

int trib(int n) {
    if(n == 0) return 0;
    if(n == 1 || n == 2) return 1;
    return trib(n-1) + trib(n-2) + trib(n-3);
}

int main() {
    int n;
    scanf("%d", &n);
    printf("%d", trib(n));
    return 0;
}

Data Structures and Singly Linked Lists

An Abstract Data Type (ADT) defines a data type by its behavior rather than implementation (e.g., Stack, Queue).

  • Linear Data Structure: Elements are arranged sequentially (e.g., Arrays, Linked Lists).
  • Non-Linear Data Structure: Elements are arranged hierarchically (e.g., Trees, Graphs).

Singly Linked List Operations

Each node contains data and a pointer to the next node.

  • Insertion (Beginning): new->next = head; head = new;
  • Deletion (Beginning): temp = head; head = head->next; free(temp);