Hello World
#include <stdio.h> // Include standard I/O library
int main() {
printf("Hello, World!\n"); // Print to console
return 0; // Return success status
}
Compile and run:
gcc hello.c -o hello # Compile with GCC
./hello # Execute program
clang hello.c -o hello # Compile with Clang
./hello # Execute program
Variables & Types
// Basic data types
int age = 25; // Integer (typically 4 bytes)
float price = 19.99; // Single-precision float (4 bytes)
double pi = 3.14159; // Double-precision float (8 bytes)
char letter = 'A'; // Single character (1 byte)
char name[] = "Alice"; // String (array of chars)
// Type modifiers
unsigned int count = 100; // Only positive values
long long big_num = 1234567890L; // Larger integer range
short small = 32767; // Smaller integer range
const int MAX = 100; // Constant (immutable)
// Type sizes
sizeof(int); // Returns size in bytes
Operators
// Arithmetic
int a = 10 + 5; // Addition
int b = 10 - 5; // Subtraction
int c = 10 * 5; // Multiplication
int d = 10 / 3; // Division (integer: 3)
int e = 10 % 3; // Modulus (remainder: 1)
// Increment/Decrement
a++; // Post-increment
++a; // Pre-increment
b--; // Post-decrement
--b; // Pre-decrement
// Comparison
a == b; // Equal to
a != b; // Not equal to
a < b; // Less than
a > b; // Greater than
a <= b; // Less than or equal
a >= b; // Greater than or equal
// Logical
(a && b); // AND
(a || b); // OR
!a; // NOT
// Bitwise
a & b; // AND
a | b; // OR
a ^ b; // XOR
~a; // NOT
a << 2; // Left shift
a >> 2; // Right shift
Control Flow
// If-else statement
if (age >= 18) {
printf("Adult\n");
} else if (age >= 13) {
printf("Teen\n");
} else {
printf("Child\n");
}
// Ternary operator
int max = (a > b) ? a : b; // Shorthand if-else
// Switch statement
switch (grade) {
case 'A':
printf("Excellent\n");
break; // Prevent fall-through
case 'B':
printf("Good\n");
break;
default:
printf("Keep trying\n");
}
// While loop
int i = 0;
while (i < 5) {
printf("%d\n", i);
i++;
}
// Do-while loop (executes at least once)
do {
printf("%d\n", i);
i++;
} while (i < 5);
// For loop
for (int i = 0; i < 5; i++) {
printf("%d\n", i);
}
// Break and continue
for (int i = 0; i < 10; i++) {
if (i == 5) break; // Exit loop
if (i % 2 == 0) continue; // Skip to next iteration
printf("%d\n", i);
}
Functions
// Function declaration (prototype)
int add(int a, int b);
// Function definition
int add(int a, int b) {
return a + b;
}
// Void function (no return value)
void greet(char name[]) {
printf("Hello, %s!\n", name);
}
// Function with default behavior
void print_number(int n) {
if (n == 0) return; // Early return
printf("%d\n", n);
}
// Recursive function
int factorial(int n) {
if (n <= 1) return 1; // Base case
return n * factorial(n - 1); // Recursive call
}
// Main function (program entry point)
int main(int argc, char *argv[]) {
printf("Hello, World!\n");
return 0; // Return status code
}
Pointers
// Pointer basics
int x = 10;
int *ptr = &x; // Pointer stores address of x
printf("%d\n", *ptr); // Dereference: access value (10)
printf("%p\n", ptr); // Print address
// Modifying through pointers
*ptr = 20; // Changes x to 20
// Null pointer
int *null_ptr = NULL; // Safe initialization
if (null_ptr != NULL) { // Always check before dereferencing
printf("%d\n", *null_ptr);
}
// Pointer arithmetic
int arr[] = {1, 2, 3, 4, 5};
int *p = arr; // Points to first element
p++; // Move to next element
printf("%d\n", *p); // Prints 2
// Double pointers
int **pp = &ptr; // Pointer to pointer
printf("%d\n", **pp); // Double dereference
// Function pointers
int (*func_ptr)(int, int) = add; // Pointer to function
int result = func_ptr(5, 3); // Call through pointer
Arrays
// Array declaration
int numbers[5]; // Uninitialized array
int scores[5] = {90, 85, 88, 92, 78}; // Initialized array
int values[] = {1, 2, 3}; // Size inferred (3)
// Accessing elements
int first = scores[0]; // First element (index 0)
scores[2] = 95; // Modify element
// Array size
int size = sizeof(scores) / sizeof(scores[0]); // Calculate length
// Multidimensional arrays
int matrix[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int value = matrix[1][2]; // Access element (6)
// Arrays and pointers
int *p = numbers; // Array name is pointer to first element
printf("%d\n", *(p + 2)); // Access third element
Strings
// String declaration
char str1[] = "Hello"; // Array with null terminator
char str2[10] = "World"; // Fixed-size buffer
char *str3 = "Constant"; // Pointer to string literal
// String functions (string.h)
strlen(str1); // Length (excluding \0)
strcpy(str2, str1); // Copy str1 to str2
strcat(str1, str2); // Concatenate str2 to str1
strcmp(str1, str2); // Compare (0 if equal)
strncpy(str2, str1, 5); // Copy n characters
strncat(str1, str2, 3); // Concatenate n characters
// String manipulation
char buffer[50];
sprintf(buffer, "Age: %d", 25); // Format string into buffer
sscanf("42", "%d", &age); // Parse string into variable
// Character operations (ctype.h)
isalpha('A'); // Check if letter
isdigit('5'); // Check if digit
toupper('a'); // Convert to uppercase
tolower('A'); // Convert to lowercase
Structs
// Struct definition
struct Person {
char name[50];
int age;
float height;
};
// Struct initialization
struct Person person1 = {"Alice", 30, 5.6};
struct Person person2 = {.age = 25, .name = "Bob"}; // Designated initializers
// Accessing members
printf("%s\n", person1.name); // Dot notation
person1.age = 31; // Modify member
// Pointer to struct
struct Person *ptr = &person1;
printf("%s\n", ptr->name); // Arrow notation for pointers
ptr->age = 32; // Modify through pointer
// Typedef for cleaner syntax
typedef struct {
int x;
int y;
} Point;
Point p1 = {10, 20}; // No need for "struct" keyword
// Nested structs
typedef struct {
Point position;
int radius;
} Circle;
Circle c = {{100, 200}, 50};
printf("%d\n", c.position.x); // Access nested member
Memory Management
// Dynamic memory allocation
int *arr = (int *)malloc(5 * sizeof(int)); // Allocate memory
if (arr == NULL) {
printf("Memory allocation failed\n");
return 1;
}
// Using allocated memory
arr[0] = 10;
arr[1] = 20;
// Freeing memory
free(arr); // Always free allocated memory
arr = NULL; // Prevent dangling pointer
// Calloc (allocates and initializes to zero)
int *zeros = (int *)calloc(5, sizeof(int)); // 5 integers, all zero
free(zeros);
// Realloc (resize allocated memory)
int *resized = (int *)realloc(arr, 10 * sizeof(int)); // Expand to 10
if (resized != NULL) {
arr = resized;
}
free(arr);
// Memory operations (string.h)
int buffer[10];
memset(buffer, 0, sizeof(buffer)); // Fill with value
memcpy(dest, src, size); // Copy memory block
memmove(dest, src, size); // Safe copy (handles overlap)
memcmp(buf1, buf2, size); // Compare memory blocks
File I/O
// Opening files
FILE *file = fopen("data.txt", "r"); // Read mode
// Modes: "r" (read), "w" (write), "a" (append), "r+", "w+", "a+"
if (file == NULL) {
perror("Error opening file");
return 1;
}
// Reading from file
char buffer[100];
fgets(buffer, 100, file); // Read line
fscanf(file, "%s %d", name, &age); // Formatted read
int ch = fgetc(file); // Read single character
// Writing to file
FILE *out = fopen("output.txt", "w");
fprintf(out, "Name: %s\n", name); // Formatted write
fputs("Hello, World!\n", out); // Write string
fputc('A', out); // Write character
// File positioning
fseek(file, 0, SEEK_SET); // Move to beginning
fseek(file, 0, SEEK_END); // Move to end
fseek(file, 10, SEEK_CUR); // Move 10 bytes from current
long pos = ftell(file); // Get current position
rewind(file); // Reset to beginning
// Closing files
fclose(file); // Always close files
fclose(out);
// Binary file I/O
struct Person p = {"Alice", 30, 5.6};
FILE *bin = fopen("data.bin", "wb");
fwrite(&p, sizeof(struct Person), 1, bin); // Write binary
fclose(bin);
FILE *bin_in = fopen("data.bin", "rb");
struct Person loaded;
fread(&loaded, sizeof(struct Person), 1, bin_in); // Read binary
fclose(bin_in);
Error Handling
Return Codes
// Function returning error codes
int divide(int a, int b, int *result) {
if (b == 0) {
return -1; // Error code for division by zero
}
*result = a / b;
return 0; // Success
}
// Using the function
int result;
if (divide(10, 2, &result) == 0) {
printf("Result: %d\n", result);
} else {
fprintf(stderr, "Error: Division by zero\n");
}
errno (Global Error Variable)
#include <errno.h>
#include <string.h>
// Opening a file with error checking
FILE *file = fopen("nonexistent.txt", "r");
if (file == NULL) {
printf("Error code: %d\n", errno); // Print error number
printf("Error: %s\n", strerror(errno)); // Convert to message
perror("fopen"); // Print error with prefix
return 1;
}
// Common errno values
// ENOENT (2) - No such file or directory
// EACCES (13) - Permission denied
// ENOMEM (12) - Out of memory
// EINVAL (22) - Invalid argument
// EIO (5) - Input/output error
perror() and strerror()
// perror() - prints error message with prefix
FILE *f = fopen("data.txt", "r");
if (f == NULL) {
perror("Failed to open file"); // Prints: "Failed to open file: No such file or directory"
return 1;
}
// strerror() - returns error message string
char *error_msg = strerror(errno);
fprintf(stderr, "Error: %s\n", error_msg);
// Custom error messages
if (age < 0) {
fprintf(stderr, "Error: Invalid age %d\n", age);
return EXIT_FAILURE;
}
assert() for Debugging
#include <assert.h>
// Assert fails if condition is false (debug only)
int array[10];
int index = 5;
assert(index >= 0 && index < 10); // Verify bounds
array[index] = 42;
// Disable assertions in production
// Compile with -DNDEBUG flag: gcc -DNDEBUG file.c
assert(ptr != NULL); // No-op in release builds
goto for Error Cleanup
// Clean up multiple resources on error
int process_file(const char *filename) {
FILE *file = NULL;
char *buffer = NULL;
int result = -1; // Assume failure
file = fopen(filename, "r");
if (file == NULL) {
perror("fopen");
goto cleanup; // Jump to cleanup
}
buffer = malloc(1024);
if (buffer == NULL) {
fprintf(stderr, "Out of memory\n");
goto cleanup;
}
// Process file...
result = 0; // Success
cleanup:
free(buffer); // Safe even if NULL
if (file != NULL) fclose(file);
return result;
}
Custom Error Enums
// Define custom error codes
typedef enum {
SUCCESS = 0,
ERR_FILE_NOT_FOUND = 1,
ERR_OUT_OF_MEMORY = 2,
ERR_INVALID_INPUT = 3,
ERR_NETWORK_FAILURE = 4
} ErrorCode;
// Function using custom error codes
ErrorCode read_config(const char *path) {
FILE *f = fopen(path, "r");
if (f == NULL) {
return ERR_FILE_NOT_FOUND;
}
char *buffer = malloc(512);
if (buffer == NULL) {
fclose(f);
return ERR_OUT_OF_MEMORY;
}
// Process config...
free(buffer);
fclose(f);
return SUCCESS;
}
// Convert error code to message
const char *error_to_string(ErrorCode err) {
switch (err) {
case SUCCESS: return "Success";
case ERR_FILE_NOT_FOUND: return "File not found";
case ERR_OUT_OF_MEMORY: return "Out of memory";
case ERR_INVALID_INPUT: return "Invalid input";
case ERR_NETWORK_FAILURE: return "Network failure";
default: return "Unknown error";
}
}
Error Handling Patterns
// Pattern 1: Check and return early
int safe_divide(int a, int b, int *result) {
if (result == NULL) return -1; // Null pointer check
if (b == 0) return -1; // Division by zero
*result = a / b;
return 0;
}
// Pattern 2: Cascading checks with goto
int init_resources(void) {
void *res1 = NULL, *res2 = NULL, *res3 = NULL;
res1 = malloc(100);
if (!res1) goto error;
res2 = malloc(200);
if (!res2) goto error;
res3 = malloc(300);
if (!res3) goto error;
return 0;
error:
free(res3);
free(res2);
free(res1);
return -1;
}
// Pattern 3: Wrapper functions
FILE *safe_fopen(const char *path, const char *mode) {
FILE *f = fopen(path, mode);
if (f == NULL) {
fprintf(stderr, "Failed to open '%s': %s\n",
path, strerror(errno));
}
return f;
}
// Pattern 4: Defensive programming
void process_array(int *arr, size_t len) {
if (arr == NULL || len == 0) {
fprintf(stderr, "Invalid input\n");
return;
}
for (size_t i = 0; i < len; i++) {
// Process each element...
}
}
Preprocessor
// Include directives
#include <stdio.h> // Standard library
#include "myheader.h" // Local header file
// Macro definitions
#define PI 3.14159 // Constant macro
#define MAX(a, b) ((a) > (b) ? (a) : (b)) // Function-like macro
#define SQUARE(x) ((x) * (x)) // Always use parentheses
// Conditional compilation
#ifdef DEBUG
printf("Debug mode\n");
#endif
#ifndef HEADER_H
#define HEADER_H
// Header file content
#endif
#if defined(LINUX)
// Linux-specific code
#elif defined(WINDOWS)
// Windows-specific code
#else
// Default code
#endif
// Predefined macros
__FILE__ // Current file name
__LINE__ // Current line number
__DATE__ // Compilation date
__TIME__ // Compilation time
// Stringification
#define STRINGIFY(x) #x
printf("%s\n", STRINGIFY(Hello)); // Prints "Hello"
// Token pasting
#define CONCAT(a, b) a##b
int CONCAT(var, 123) = 10; // Creates var123
Standard Library Functions
// stdio.h - Input/Output
printf("Format: %d\n", value); // Print to stdout
scanf("%d", &value); // Read from stdin
getchar(); // Read single character
putchar('A'); // Write single character
puts("Hello"); // Print string with newline
// stdlib.h - Utilities
atoi("123"); // String to int
atof("3.14"); // String to float
abs(-5); // Absolute value
rand(); // Random number
srand(time(NULL)); // Seed random generator
exit(0); // Exit program
// math.h - Mathematics
sqrt(16); // Square root
pow(2, 3); // Power (2^3)
ceil(3.2); // Round up (4)
floor(3.8); // Round down (3)
sin(angle); // Sine
cos(angle); // Cosine
// time.h - Date/Time
time_t now = time(NULL); // Current time
struct tm *local = localtime(&now); // Convert to local time
char timestr[26];
strftime(timestr, 26, "%Y-%m-%d", local); // Format time
Common Patterns
// Error handling
if (ptr == NULL) {
fprintf(stderr, "Error: %s\n", strerror(errno));
return EXIT_FAILURE;
}
// Command-line arguments
int main(int argc, char *argv[]) {
for (int i = 0; i < argc; i++) {
printf("Arg %d: %s\n", i, argv[i]);
}
return 0;
}
// Dynamic array
typedef struct {
int *data;
int size;
int capacity;
} DynamicArray;
void append(DynamicArray *arr, int value) {
if (arr->size >= arr->capacity) {
arr->capacity *= 2;
arr->data = realloc(arr->data, arr->capacity * sizeof(int));
}
arr->data[arr->size++] = value;
}
// Swap function
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
Compiler Comparison
| Feature | GCC | Clang | MSVC | TCC |
|---|---|---|---|---|
| Platform | Linux, macOS, Windows (MinGW) | Linux, macOS, Windows | Windows only | Cross-platform |
| Standards | C89, C99, C11, C17, C23 | C89, C99, C11, C17, C23 | C89, C99, C11, C17 | C89, C99 |
| Optimization | Excellent | Excellent | Excellent | Basic |
| Compile Speed | Moderate | Fast | Moderate | Very fast |
| Error Messages | Good | Excellent (most detailed) | Good | Basic |
| Debugging | GDB integration | LLDB integration | Visual Studio debugger | Limited |
| License | GPL | Apache 2.0 | Proprietary | LGPL |
| Best For | General use, Linux dev | Modern tooling, diagnostics | Windows native apps | Quick prototyping |
Common compiler flags:
gcc -Wall -Wextra file.c # Enable all warnings
gcc -O2 file.c # Optimization level 2
gcc -g file.c # Include debug symbols
gcc -std=c11 file.c # Use C11 standard
gcc -o output file.c # Specify output name