C Basics
C is a general-purpose, procedural programming language developed by Dennis Ritchie at Bell Labs in 1972. It's the foundation for many modern languages.
C
#include <stdio.h>
int main() {
// This is a comment
printf("Hello, World!\n");
/* Multi-line
comment */
return 0; // Exit status
}
// Compile: gcc program.c -o program
// Run: ./program
Input/Output
C
#include <stdio.h>
int main() {
int age;
char name[50];
float salary;
// Input
printf("Enter your name: ");
scanf("%s", name); // No & for arrays
printf("Enter your age: ");
scanf("%d", &age); // & for address
printf("Enter salary: ");
scanf("%f", &salary);
// Output
printf("Name: %s\n", name);
printf("Age: %d\n", age);
printf("Salary: %.2f\n", salary);
return 0;
}
Data Types
| Type | Size | Format | Range |
|---|---|---|---|
char | 1 byte | %c | -128 to 127 |
unsigned char | 1 byte | %c | 0 to 255 |
short | 2 bytes | %hd | -32,768 to 32,767 |
int | 4 bytes | %d | -2³¹ to 2³¹-1 |
unsigned int | 4 bytes | %u | 0 to 2³²-1 |
long | 8 bytes | %ld | -2⁶³ to 2⁶³-1 |
float | 4 bytes | %f | 3.4E-38 to 3.4E+38 |
double | 8 bytes | %lf | 1.7E-308 to 1.7E+308 |
C
// Variable declaration
int age = 25;
float price = 99.99f;
double pi = 3.14159265359;
char grade = 'A';
// Constants
const int MAX = 100;
#define PI 3.14159
// Type modifiers
unsigned int positive = 100;
signed int negative = -50;
long long bigNum = 9223372036854775807LL;
// sizeof operator
printf("Size of int: %zu bytes\n", sizeof(int));
printf("Size of double: %zu bytes\n", sizeof(double));
// Type casting
int a = 5, b = 2;
float result = (float)a / b; // 2.5, not 2
Control Flow
C
// if-else
if (age >= 18) {
printf("Adult\n");
} else if (age >= 13) {
printf("Teenager\n");
} else {
printf("Child\n");
}
// Ternary operator
int max = (a > b) ? a : b;
// Switch statement
switch (grade) {
case 'A':
printf("Excellent!\n");
break;
case 'B':
printf("Good!\n");
break;
default:
printf("Try harder!\n");
}
// for loop
for (int i = 0; i < 5; i++) {
printf("%d ", i);
}
// while loop
int count = 0;
while (count < 5) {
printf("%d ", count);
count++;
}
// do-while loop
do {
printf("%d ", count);
count--;
} while (count > 0);
// break and continue
for (int i = 0; i < 10; i++) {
if (i == 3) continue; // Skip 3
if (i == 7) break; // Stop at 7
printf("%d ", i);
}
// goto (avoid if possible)
goto label;
// ...
label:
printf("Jumped here\n");
Functions
C
// Function declaration (prototype)
int add(int a, int b);
void greet(char name[]);
// Function definition
int add(int a, int b) {
return a + b;
}
void greet(char name[]) {
printf("Hello, %s!\n", name);
}
// Pass by value (copy)
void increment(int x) {
x++; // Doesn't affect original
}
// Pass by reference (pointer)
void incrementRef(int *x) {
(*x)++; // Affects original
}
// Multiple return values using pointers
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
// Array as parameter
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
}
// Recursive function
int factorial(int n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
// Usage
int main() {
int result = add(3, 5);
greet("Alice");
int a = 5, b = 10;
swap(&a, &b); // Pass addresses
int nums[] = {1, 2, 3, 4, 5};
printArray(nums, 5);
return 0;
}
Pointers
A pointer is a variable that stores the memory address of another variable.
& = Address-of operator | * = Dereference operator
C
// Basic pointers
int x = 10;
int *ptr = &x; // ptr holds address of x
printf("Value of x: %d\n", x); // 10
printf("Address of x: %p\n", &x); // 0x7fff...
printf("Value of ptr: %p\n", ptr); // Same address
printf("Value at ptr: %d\n", *ptr); // 10 (dereferencing)
*ptr = 20; // Modify value through pointer
printf("x is now: %d\n", x); // 20
// Pointer arithmetic
int arr[] = {10, 20, 30, 40, 50};
int *p = arr; // Points to first element
printf("%d\n", *p); // 10
printf("%d\n", *(p + 1)); // 20
printf("%d\n", *(p + 2)); // 30
p++; // Move to next element
printf("%d\n", *p); // 20
// Array and pointers
// arr[i] is equivalent to *(arr + i)
// &arr[i] is equivalent to (arr + i)
// Pointer to pointer
int **pp = &ptr;
printf("%d\n", **pp); // 20
// NULL pointer
int *null_ptr = NULL;
if (null_ptr == NULL) {
printf("Pointer is NULL\n");
}
// Void pointer (generic pointer)
void *generic = &x;
printf("%d\n", *(int*)generic); // Cast before dereference
// Function pointers
int add(int a, int b) { return a + b; }
int (*funcPtr)(int, int) = add;
printf("%d\n", funcPtr(3, 5)); // 8
Structures
C
// Structure definition
struct Person {
char name[50];
int age;
float salary;
};
// Using typedef
typedef struct {
int x;
int y;
} Point;
int main() {
// Declaration and initialization
struct Person p1 = {"Alice", 25, 50000.00};
// Access members
printf("Name: %s\n", p1.name);
printf("Age: %d\n", p1.age);
// Modify members
p1.age = 26;
// Array of structures
struct Person people[3] = {
{"Alice", 25, 50000},
{"Bob", 30, 60000},
{"Charlie", 35, 70000}
};
// Pointer to structure
struct Person *ptr = &p1;
printf("Name: %s\n", ptr->name); // Arrow operator
printf("Age: %d\n", (*ptr).age); // Equivalent
// Using typedef
Point origin = {0, 0};
// Nested structures
struct Address {
char city[50];
int zip;
};
struct Employee {
char name[50];
struct Address addr;
};
struct Employee emp = {"John", {"NYC", 10001}};
printf("City: %s\n", emp.addr.city);
return 0;
}
Dynamic Memory
C
#include <stdlib.h>
// malloc - allocate uninitialized memory
int *arr = (int*) malloc(5 * sizeof(int));
if (arr == NULL) {
printf("Memory allocation failed!\n");
return 1;
}
// Use the array
for (int i = 0; i < 5; i++) {
arr[i] = i * 10;
}
// calloc - allocate and initialize to 0
int *arr2 = (int*) calloc(5, sizeof(int));
// realloc - resize allocated memory
arr = (int*) realloc(arr, 10 * sizeof(int));
// free - deallocate memory
free(arr);
arr = NULL; // Good practice: set to NULL after free
free(arr2);
arr2 = NULL;
// Dynamic 2D array
int rows = 3, cols = 4;
int **matrix = (int**) malloc(rows * sizeof(int*));
for (int i = 0; i < rows; i++) {
matrix[i] = (int*) malloc(cols * sizeof(int));
}
// Use matrix
matrix[1][2] = 100;
// Free 2D array (in reverse order)
for (int i = 0; i < rows; i++) {
free(matrix[i]);
}
free(matrix);
Common Memory Errors:
• Memory leak (not calling free)
• Dangling pointer (using after free)
• Double free
• Buffer overflow
• Memory leak (not calling free)
• Dangling pointer (using after free)
• Double free
• Buffer overflow
File I/O
C
#include <stdio.h>
// File modes: "r" read, "w" write, "a" append
// "r+" read/write, "rb" binary read
// Writing to file
FILE *file = fopen("output.txt", "w");
if (file == NULL) {
printf("Error opening file!\n");
return 1;
}
fprintf(file, "Hello, File!\n");
fprintf(file, "Number: %d\n", 42);
fputs("Another line\n", file);
fputc('X', file);
fclose(file);
// Reading from file
FILE *readFile = fopen("output.txt", "r");
if (readFile == NULL) {
printf("Error opening file!\n");
return 1;
}
char buffer[100];
// Read line by line
while (fgets(buffer, sizeof(buffer), readFile) != NULL) {
printf("%s", buffer);
}
// Or read character by character
int ch;
while ((ch = fgetc(readFile)) != EOF) {
putchar(ch);
}
// Read formatted input
int num;
char str[50];
fscanf(readFile, "%s %d", str, &num);
fclose(readFile);
// Binary file operations
struct Data {
int id;
char name[20];
};
struct Data data = {1, "Test"};
// Write binary
FILE *binFile = fopen("data.bin", "wb");
fwrite(&data, sizeof(struct Data), 1, binFile);
fclose(binFile);
// Read binary
FILE *binRead = fopen("data.bin", "rb");
fread(&data, sizeof(struct Data), 1, binRead);
fclose(binRead);