diff --git a/LEARNING_C_WITH_CLAY.md b/LEARNING_C_WITH_CLAY.md index 273a737..27e521d 100644 --- a/LEARNING_C_WITH_CLAY.md +++ b/LEARNING_C_WITH_CLAY.md @@ -4,17 +4,28 @@ 1. [Introduction to C and Clay](#introduction) 2. [Chapter 1: C Basics - Your First Program](#chapter-1) 3. [Chapter 2: Variables and Data Types](#chapter-2) -4. [Chapter 3: Functions](#chapter-3) -5. [Chapter 4: Pointers - The Heart of C](#chapter-4) -6. [Chapter 5: Structs and Typedef](#chapter-5) -7. [Chapter 6: Arrays and Memory](#chapter-6) -8. [Chapter 7: Preprocessor and Macros](#chapter-7) -9. [Chapter 8: Advanced Macros and Metaprogramming](#chapter-8) -10. [Chapter 9: Memory Management](#chapter-9) -11. [Chapter 10: Header Files and Project Organization](#chapter-10) -12. [Chapter 11: Enums and Unions](#chapter-11) -13. [Chapter 12: Function Pointers and Callbacks](#chapter-12) -14. [Chapter 13: Building Complete Programs](#chapter-13) +4. [Chapter 3: Operators](#chapter-3) +5. [Chapter 4: Control Flow](#chapter-4) +6. [Chapter 5: Loops](#chapter-5) +7. [Chapter 6: Functions](#chapter-6) +8. [Chapter 7: Pointers - The Heart of C](#chapter-7) +9. [Chapter 8: Structs and Typedef](#chapter-8) +10. [Chapter 9: Arrays and Memory](#chapter-9) +11. [Chapter 10: Strings](#chapter-10) +12. [Chapter 11: Type Casting and Qualifiers](#chapter-11) +13. [Chapter 12: Storage Classes and Scope](#chapter-12) +14. [Chapter 13: Recursion](#chapter-13) +15. [Chapter 14: Bit Manipulation](#chapter-14) +16. [Chapter 15: Preprocessor and Macros](#chapter-15) +17. [Chapter 16: Advanced Macros and Metaprogramming](#chapter-16) +18. [Chapter 17: Memory Management](#chapter-17) +19. [Chapter 18: Header Files and Project Organization](#chapter-18) +20. [Chapter 19: Enums and Unions](#chapter-19) +21. [Chapter 20: Function Pointers and Callbacks](#chapter-20) +22. [Chapter 21: Standard Library Basics](#chapter-21) +23. [Chapter 22: File I/O](#chapter-22) +24. [Chapter 23: Command-Line Arguments](#chapter-23) +25. [Chapter 24: Building Complete Programs](#chapter-24) --- @@ -219,7 +230,809 @@ const Clay_Color CLAY_COLOR_BLACK = {0, 0, 0, 255}; --- -## Chapter 3: Functions {#chapter-3} +## Chapter 3: Operators {#chapter-3} + +### 3.1 Arithmetic Operators + +Basic math operations: + +```c +int main(void) { + int a = 10, b = 3; + + int sum = a + b; // 13 (addition) + int diff = a - b; // 7 (subtraction) + int product = a * b; // 30 (multiplication) + int quotient = a / b; // 3 (integer division) + int remainder = a % b; // 1 (modulo/remainder) + + // Floating-point division + float result = 10.0f / 3.0f; // 3.333... + + return 0; +} +``` + +### 3.2 Increment and Decrement + +```c +int main(void) { + int x = 5; + + // Post-increment (use then increment) + int a = x++; // a = 5, x = 6 + + // Pre-increment (increment then use) + int b = ++x; // x = 7, b = 7 + + // Post-decrement + int c = x--; // c = 7, x = 6 + + // Pre-decrement + int d = --x; // x = 5, d = 5 + + return 0; +} +``` + +**Clay Example** (from clay.h): +```c +// Pre-increment used for index management +Clay__currentContext->layoutElements.length++; + +// Post-increment to get current then move +element = array->internalArray[index++]; +``` + +### 3.3 Relational Operators + +Compare values: + +```c +int main(void) { + int a = 10, b = 20; + + int equal = (a == b); // 0 (false) + int notEqual = (a != b); // 1 (true) + int less = (a < b); // 1 (true) + int lessOrEqual = (a <= b); // 1 (true) + int greater = (a > b); // 0 (false) + int greaterOrEqual = (a >= b); // 0 (false) + + return 0; +} +``` + +**Clay Example** (from clay.h): +```c +static inline float Clay__Max(float a, float b) { + return a > b ? a : b; // Using > operator +} + +if (config->type == CLAY_SIZING_TYPE_FIXED) { + // Using == operator +} +``` + +### 3.4 Logical Operators + +Boolean logic: + +```c +int main(void) { + int a = 1, b = 0; // 1 = true, 0 = false + + int andResult = a && b; // 0 (both must be true) + int orResult = a || b; // 1 (at least one true) + int notResult = !a; // 0 (logical NOT) + + // Short-circuit evaluation + if (ptr != NULL && *ptr > 0) { + // Safe: *ptr only evaluated if ptr != NULL + } + + return 0; +} +``` + +**Clay Example** (from clay.h): +```c +if (element->layoutConfig && + element->layoutConfig->sizing.width.type == CLAY_SIZING_TYPE_GROW) { + // Short-circuit: second condition only checked if first is true +} +``` + +### 3.5 Bitwise Operators + +Work on individual bits: + +```c +int main(void) { + unsigned int a = 5; // 0101 in binary + unsigned int b = 3; // 0011 in binary + + unsigned int and = a & b; // 0001 = 1 (AND) + unsigned int or = a | b; // 0111 = 7 (OR) + unsigned int xor = a ^ b; // 0110 = 6 (XOR) + unsigned int not = ~a; // 1010 (NOT, inverts all bits) + + // Bit shifts + unsigned int leftShift = a << 1; // 1010 = 10 (multiply by 2) + unsigned int rightShift = a >> 1; // 0010 = 2 (divide by 2) + + return 0; +} +``` + +**Clay Example** (from clay.h): +```c +// Bit flags for corner radius +typedef enum { + CLAY_CORNER_RADIUS_TOP_LEFT = 1 << 0, // 0001 + CLAY_CORNER_RADIUS_TOP_RIGHT = 1 << 1, // 0010 + CLAY_CORNER_RADIUS_BOTTOM_LEFT = 1 << 2, // 0100 + CLAY_CORNER_RADIUS_BOTTOM_RIGHT = 1 << 3 // 1000 +} Clay_CornerRadiusSet; + +// Combine flags with OR +int flags = CLAY_CORNER_RADIUS_TOP_LEFT | CLAY_CORNER_RADIUS_TOP_RIGHT; + +// Check if flag is set with AND +if (flags & CLAY_CORNER_RADIUS_TOP_LEFT) { + // Top left corner has radius +} +``` + +### 3.6 Assignment Operators + +```c +int main(void) { + int x = 10; + + x += 5; // x = x + 5 (15) + x -= 3; // x = x - 3 (12) + x *= 2; // x = x * 2 (24) + x /= 4; // x = x / 4 (6) + x %= 4; // x = x % 4 (2) + + // Bitwise compound assignments + x &= 3; // x = x & 3 + x |= 4; // x = x | 4 + x ^= 1; // x = x ^ 1 + x <<= 1; // x = x << 1 + x >>= 1; // x = x >> 1 + + return 0; +} +``` + +### 3.7 Ternary Operator + +Compact if-else: + +```c +int main(void) { + int a = 10, b = 20; + + // condition ? value_if_true : value_if_false + int max = (a > b) ? a : b; + + // Equivalent to: + int max2; + if (a > b) { + max2 = a; + } else { + max2 = b; + } + + return 0; +} +``` + +**Clay Example** (from clay.h): +```c +static inline float Clay__Min(float a, float b) { + return a < b ? a : b; // Ternary operator +} + +// Nested ternary (less readable) +int result = (x > 0) ? 1 : (x < 0) ? -1 : 0; +``` + +### 3.8 sizeof Operator + +Get size of type or variable: + +```c +#include + +int main(void) { + printf("int: %zu bytes\n", sizeof(int)); + printf("float: %zu bytes\n", sizeof(float)); + printf("double: %zu bytes\n", sizeof(double)); + printf("char: %zu bytes\n", sizeof(char)); + printf("pointer: %zu bytes\n", sizeof(void*)); + + int arr[10]; + printf("array: %zu bytes\n", sizeof(arr)); // 40 bytes (10 * 4) + + return 0; +} +``` + +**Clay Example** (from clay.h): +```c +// Get size of struct +size_t size = sizeof(Clay_LayoutElement); + +// Allocate memory +void *mem = malloc(count * sizeof(Clay_RenderCommand)); + +// Calculate array length +int length = sizeof(array) / sizeof(array[0]); +``` + +### 3.9 Comma Operator + +Evaluate multiple expressions: + +```c +int main(void) { + int a, b, c; + + // Comma operator: evaluates left to right, returns rightmost + a = (b = 5, c = 10, b + c); // a = 15 + + // Common in for loops + for (int i = 0, j = 10; i < j; i++, j--) { + // i increments, j decrements + } + + return 0; +} +``` + +**Clay Example** (from clay.h): +```c +// Used in macro for-loop trick +#define CLAY(...) \ + for ( \ + CLAY__ELEMENT_DEFINITION_LATCH = ( \ + Clay__OpenElement(), /* First */ \ + Clay__ConfigureOpenElement(...), /* Second */ \ + 0 /* Result */ \ + ); \ + /* ... */ \ + ) +``` + +### 3.10 Operator Precedence + +Order of evaluation (high to low): + +```c +int main(void) { + // Precedence matters! + int x = 2 + 3 * 4; // 14, not 20 (* before +) + int y = (2 + 3) * 4; // 20 (parentheses first) + + // Common precedence + // 1. () [] -> . + // 2. ! ~ ++ -- + - * & sizeof + // 3. * / % + // 4. + - + // 5. << >> + // 6. < <= > >= + // 7. == != + // 8. & + // 9. ^ + // 10. | + // 11. && + // 12. || + // 13. ?: + // 14. = += -= etc. + // 15. , + + return 0; +} +``` + +**Tip**: When in doubt, use parentheses for clarity! + +### 3.11 Key Concepts Learned +- ✅ Arithmetic operators (+, -, *, /, %) +- ✅ Increment/decrement (++, --) +- ✅ Relational operators (==, !=, <, >, <=, >=) +- ✅ Logical operators (&&, ||, !) +- ✅ Bitwise operators (&, |, ^, ~, <<, >>) +- ✅ Assignment operators (=, +=, -=, etc.) +- ✅ Ternary operator (?:) +- ✅ sizeof operator +- ✅ Operator precedence + +--- + +## Chapter 4: Control Flow {#chapter-4} + +### 4.1 if Statement + +Basic conditional execution: + +```c +int main(void) { + int age = 18; + + if (age >= 18) { + printf("Adult\n"); + } + + return 0; +} +``` + +**Clay Example** (from clay.h): +```c +if (layoutElement->layoutConfig) { + // Process layout config +} + +if (element == NULL) { + return; // Early return +} +``` + +### 4.2 if-else Statement + +```c +int main(void) { + int score = 75; + + if (score >= 60) { + printf("Pass\n"); + } else { + printf("Fail\n"); + } + + return 0; +} +``` + +### 4.3 else-if Chains + +```c +int main(void) { + int grade = 85; + + if (grade >= 90) { + printf("A\n"); + } else if (grade >= 80) { + printf("B\n"); + } else if (grade >= 70) { + printf("C\n"); + } else if (grade >= 60) { + printf("D\n"); + } else { + printf("F\n"); + } + + return 0; +} +``` + +**Clay Example** (from clay.h): +```c +if (config->type == CLAY_SIZING_TYPE_FIT) { + // Handle FIT sizing +} else if (config->type == CLAY_SIZING_TYPE_GROW) { + // Handle GROW sizing +} else if (config->type == CLAY_SIZING_TYPE_FIXED) { + // Handle FIXED sizing +} +``` + +### 4.4 Nested if Statements + +```c +int main(void) { + int age = 25; + int hasLicense = 1; + + if (age >= 18) { + if (hasLicense) { + printf("Can drive\n"); + } else { + printf("Need license\n"); + } + } else { + printf("Too young\n"); + } + + return 0; +} +``` + +### 4.5 switch Statement + +Multiple conditions based on value: + +```c +int main(void) { + int day = 3; + + switch (day) { + case 1: + printf("Monday\n"); + break; + case 2: + printf("Tuesday\n"); + break; + case 3: + printf("Wednesday\n"); + break; + case 4: + printf("Thursday\n"); + break; + case 5: + printf("Friday\n"); + break; + case 6: + case 7: + printf("Weekend\n"); + break; + default: + printf("Invalid day\n"); + break; + } + + return 0; +} +``` + +**Important**: `break` is required to exit switch, otherwise execution "falls through"! + +**Clay Example** (from clay.h): +```c +switch (commandType) { + case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: { + // Render rectangle + break; + } + case CLAY_RENDER_COMMAND_TYPE_TEXT: { + // Render text + break; + } + case CLAY_RENDER_COMMAND_TYPE_IMAGE: { + // Render image + break; + } + default: { + // Unknown command + break; + } +} +``` + +### 4.6 Fall-through in switch + +Intentional fall-through can be useful: + +```c +int main(void) { + char ch = 'a'; + + switch (ch) { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + printf("Vowel\n"); + break; + default: + printf("Consonant\n"); + break; + } + + return 0; +} +``` + +### 4.7 goto Statement + +Jump to a label (use sparingly): + +```c +int main(void) { + int error = processData(); + + if (error) { + goto cleanup; + } + + error = processMoreData(); + + if (error) { + goto cleanup; + } + + return 0; + +cleanup: + freeResources(); + return 1; +} +``` + +**When goto is acceptable:** +- Error handling with cleanup +- Breaking out of nested loops +- State machines + +**Clay doesn't use goto** - demonstrates clean error handling without it! + +### 4.8 Key Concepts Learned +- ✅ if, else, else-if statements +- ✅ Nested conditionals +- ✅ switch-case statements +- ✅ break in switch +- ✅ Fall-through behavior +- ✅ goto statement (use carefully) + +--- + +## Chapter 5: Loops {#chapter-5} + +### 5.1 while Loop + +Repeat while condition is true: + +```c +int main(void) { + int count = 0; + + while (count < 5) { + printf("%d\n", count); + count++; + } + // Output: 0 1 2 3 4 + + return 0; +} +``` + +**Clay Example** (from clay.h): +```c +while (currentElement != NULL) { + // Process element + currentElement = currentElement->next; +} +``` + +### 5.2 do-while Loop + +Execute at least once, then check condition: + +```c +int main(void) { + int count = 0; + + do { + printf("%d\n", count); + count++; + } while (count < 5); + // Output: 0 1 2 3 4 + + // Even runs once if condition is false + int x = 10; + do { + printf("Runs once\n"); + } while (x < 5); // False, but body already executed + + return 0; +} +``` + +### 5.3 for Loop + +Most common loop for counting: + +```c +int main(void) { + // for (initialization; condition; increment) + for (int i = 0; i < 5; i++) { + printf("%d\n", i); + } + // Output: 0 1 2 3 4 + + // Multiple variables + for (int i = 0, j = 10; i < j; i++, j--) { + printf("i=%d, j=%d\n", i, j); + } + + return 0; +} +``` + +**Clay Example** (from clay.h): +```c +for (int i = 0; i < elementCount; i++) { + Clay_LayoutElement *element = &elements[i]; + // Process element +} + +// Iterate backwards +for (int i = array->length - 1; i >= 0; i--) { + // Process in reverse +} +``` + +### 5.4 break Statement + +Exit loop early: + +```c +int main(void) { + for (int i = 0; i < 10; i++) { + if (i == 5) { + break; // Exit loop when i is 5 + } + printf("%d\n", i); + } + // Output: 0 1 2 3 4 + + return 0; +} +``` + +**Clay Example** (from clay.h): +```c +for (int i = 0; i < maxIterations; i++) { + if (found) { + break; // Stop searching + } + // Continue searching... +} +``` + +### 5.5 continue Statement + +Skip to next iteration: + +```c +int main(void) { + for (int i = 0; i < 10; i++) { + if (i % 2 == 0) { + continue; // Skip even numbers + } + printf("%d\n", i); + } + // Output: 1 3 5 7 9 (odd numbers only) + + return 0; +} +``` + +### 5.6 Nested Loops + +Loops inside loops: + +```c +int main(void) { + // Print multiplication table + for (int i = 1; i <= 5; i++) { + for (int j = 1; j <= 5; j++) { + printf("%3d ", i * j); + } + printf("\n"); + } + + return 0; +} +``` + +**Clay Example** (from clay.h): +```c +// Iterate through 2D structure +for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + Clay_LayoutElement *cell = GetCell(row, col); + // Process cell + } +} +``` + +### 5.7 Breaking from Nested Loops + +```c +int main(void) { + int found = 0; + + for (int i = 0; i < 10 && !found; i++) { + for (int j = 0; j < 10; j++) { + if (i * j == 42) { + found = 1; + break; // Only breaks inner loop + } + } + } + + // Alternative with goto (acceptable here) + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + if (i * j == 42) { + goto found_it; // Breaks both loops + } + } + } +found_it: + printf("Found it!\n"); + + return 0; +} +``` + +### 5.8 Infinite Loops + +```c +int main(void) { + // Infinite loop - use break to exit + while (1) { // or for(;;) or while(true) + int input = getInput(); + if (input == -1) { + break; + } + processInput(input); + } + + return 0; +} +``` + +### 5.9 Loop Patterns + +**Count up:** +```c +for (int i = 0; i < n; i++) { } +``` + +**Count down:** +```c +for (int i = n - 1; i >= 0; i--) { } +``` + +**Step by 2:** +```c +for (int i = 0; i < n; i += 2) { } +``` + +**Iterate array:** +```c +for (int i = 0; i < arraySize; i++) { + printf("%d\n", array[i]); +} +``` + +**Iterate with pointer:** +```c +for (int *p = array; p < array + arraySize; p++) { + printf("%d\n", *p); +} +``` + +### 5.10 Key Concepts Learned +- ✅ while loops +- ✅ do-while loops +- ✅ for loops +- ✅ break statement +- ✅ continue statement +- ✅ Nested loops +- ✅ Infinite loops +- ✅ Common loop patterns + +--- + +## Chapter 6: Functions {#chapter-6} ### 3.1 Function Basics diff --git a/docs/14_bit_manipulation.md b/docs/14_bit_manipulation.md new file mode 100644 index 0000000..273246b --- /dev/null +++ b/docs/14_bit_manipulation.md @@ -0,0 +1,661 @@ +# Chapter 14: Bit Manipulation in C + +## Complete Guide with Clay Library Examples + +--- + +## 14.1 Binary Number System + +Understanding binary is essential for bit manipulation: + +```c +// Decimal vs Binary +0 = 0000 +1 = 0001 +2 = 0010 +3 = 0011 +4 = 0100 +5 = 0101 +6 = 0110 +7 = 0111 +8 = 1000 +``` + +### Converting Binary to Decimal + +```c +#include + +int binaryToDecimal(int binary) { + int decimal = 0, base = 1; + while (binary > 0) { + int lastDigit = binary % 10; + decimal += lastDigit * base; + base *= 2; + binary /= 10; + } + return decimal; +} + +int main(void) { + printf("%d\n", binaryToDecimal(1010)); // 10 + printf("%d\n", binaryToDecimal(1111)); // 15 + return 0; +} +``` + +--- + +## 14.2 Bitwise Operators + +### AND Operator (&) + +```c +// Both bits must be 1 +int a = 5; // 0101 +int b = 3; // 0011 +int c = a & b; // 0001 = 1 + +// Check if number is even +int isEven(int n) { + return (n & 1) == 0; // Check if last bit is 0 +} +``` + +**Clay Example:** +```c +// Check if corner radius flag is set +typedef enum { + CLAY_CORNER_RADIUS_TOP_LEFT = 1 << 0, // 0001 + CLAY_CORNER_RADIUS_TOP_RIGHT = 1 << 1, // 0010 + CLAY_CORNER_RADIUS_BOTTOM_LEFT = 1 << 2, // 0100 + CLAY_CORNER_RADIUS_BOTTOM_RIGHT = 1 << 3 // 1000 +} Clay_CornerRadiusSet; + +// Check if top-left corner has radius +if (flags & CLAY_CORNER_RADIUS_TOP_LEFT) { + // Top left corner has radius +} +``` + +### OR Operator (|) + +```c +// At least one bit must be 1 +int a = 5; // 0101 +int b = 3; // 0011 +int c = a | b; // 0111 = 7 + +// Set specific bit +int setBit(int num, int pos) { + return num | (1 << pos); +} +``` + +**Clay Example:** +```c +// Combine multiple corner radius flags +int flags = CLAY_CORNER_RADIUS_TOP_LEFT | + CLAY_CORNER_RADIUS_TOP_RIGHT; // 0011 = both top corners + +// Add another flag +flags |= CLAY_CORNER_RADIUS_BOTTOM_LEFT; // Now 0111 = three corners +``` + +### XOR Operator (^) + +```c +// Bits must be different +int a = 5; // 0101 +int b = 3; // 0011 +int c = a ^ b; // 0110 = 6 + +// Swap two numbers without temp variable +void swap(int *a, int *b) { + *a = *a ^ *b; + *b = *a ^ *b; + *a = *a ^ *b; +} +``` + +### NOT Operator (~) + +```c +// Inverts all bits +int a = 5; // 00000101 +int b = ~a; // 11111010 (in 8-bit) + +// Clear specific bit +int clearBit(int num, int pos) { + return num & ~(1 << pos); +} +``` + +### Left Shift (<<) + +```c +// Multiply by 2^n +int a = 5; // 0101 +int b = a << 1; // 1010 = 10 (multiply by 2) +int c = a << 2; // 10100 = 20 (multiply by 4) + +// Fast power of 2 +int powerOf2(int n) { + return 1 << n; // 2^n +} +``` + +**Clay Example:** +```c +// Define bit flags with left shift +typedef enum { + CLAY_CORNER_RADIUS_TOP_LEFT = 1 << 0, // 1 + CLAY_CORNER_RADIUS_TOP_RIGHT = 1 << 1, // 2 + CLAY_CORNER_RADIUS_BOTTOM_LEFT = 1 << 2, // 4 + CLAY_CORNER_RADIUS_BOTTOM_RIGHT = 1 << 3 // 8 +} Clay_CornerRadiusSet; +``` + +### Right Shift (>>) + +```c +// Divide by 2^n +int a = 20; // 10100 +int b = a >> 1; // 01010 = 10 (divide by 2) +int c = a >> 2; // 00101 = 5 (divide by 4) + +// Extract specific bits +int getBits(int num, int start, int count) { + return (num >> start) & ((1 << count) - 1); +} +``` + +--- + +## 14.3 Common Bit Operations + +### Check if Bit is Set + +```c +int isBitSet(int num, int pos) { + return (num & (1 << pos)) != 0; +} + +int main(void) { + int num = 5; // 0101 + printf("%d\n", isBitSet(num, 0)); // 1 (bit 0 is set) + printf("%d\n", isBitSet(num, 1)); // 0 (bit 1 is not set) + printf("%d\n", isBitSet(num, 2)); // 1 (bit 2 is set) + return 0; +} +``` + +### Set a Bit + +```c +int setBit(int num, int pos) { + return num | (1 << pos); +} + +int main(void) { + int num = 5; // 0101 + num = setBit(num, 1); // 0111 = 7 + printf("%d\n", num); + return 0; +} +``` + +### Clear a Bit + +```c +int clearBit(int num, int pos) { + return num & ~(1 << pos); +} + +int main(void) { + int num = 7; // 0111 + num = clearBit(num, 1); // 0101 = 5 + printf("%d\n", num); + return 0; +} +``` + +### Toggle a Bit + +```c +int toggleBit(int num, int pos) { + return num ^ (1 << pos); +} + +int main(void) { + int num = 5; // 0101 + num = toggleBit(num, 1); // 0111 = 7 + num = toggleBit(num, 1); // 0101 = 5 (back to original) + printf("%d\n", num); + return 0; +} +``` + +--- + +## 14.4 Bit Masks + +Masks select specific bits: + +```c +// Extract RGB components from 32-bit color +typedef struct { + uint32_t color; // 0xAARRGGBB +} Color; + +uint8_t getRed(Color c) { + return (c.color >> 16) & 0xFF; // Mask: 0x00FF0000 +} + +uint8_t getGreen(Color c) { + return (c.color >> 8) & 0xFF; // Mask: 0x0000FF00 +} + +uint8_t getBlue(Color c) { + return c.color & 0xFF; // Mask: 0x000000FF +} + +uint8_t getAlpha(Color c) { + return (c.color >> 24) & 0xFF; // Mask: 0xFF000000 +} + +uint32_t makeColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { + return ((uint32_t)a << 24) | + ((uint32_t)r << 16) | + ((uint32_t)g << 8) | + (uint32_t)b; +} +``` + +**Clay Example (conceptual):** +```c +// Clay uses float colors, but shows similar concepts +typedef struct { + float r, g, b, a; +} Clay_Color; + +// If Clay used packed colors: +uint32_t packColor(Clay_Color c) { + uint8_t r = (uint8_t)(c.r * 255); + uint8_t g = (uint8_t)(c.g * 255); + uint8_t b = (uint8_t)(c.b * 255); + uint8_t a = (uint8_t)(c.a * 255); + return (a << 24) | (r << 16) | (g << 8) | b; +} +``` + +--- + +## 14.5 Bit Fields in Structs + +Pack multiple values efficiently: + +```c +struct Flags { + unsigned int isVisible : 1; // 1 bit + unsigned int isEnabled : 1; // 1 bit + unsigned int priority : 3; // 3 bits (0-7) + unsigned int id : 11; // 11 bits +}; // Total: 16 bits = 2 bytes + +int main(void) { + struct Flags f = {0}; + f.isVisible = 1; + f.isEnabled = 1; + f.priority = 5; + f.id = 1024; + + printf("Size: %zu bytes\n", sizeof(f)); // 2 or 4 (compiler dependent) + printf("Priority: %u\n", f.priority); + return 0; +} +``` + +**Clay Example (conceptual):** +```c +// Clay could use bit fields for layout flags +typedef struct { + uint32_t layoutDirection : 1; // 0 = horizontal, 1 = vertical + uint32_t wrapChildren : 1; // Wrap to next line + uint32_t alignmentX : 2; // 0-3 for alignment options + uint32_t alignmentY : 2; + uint32_t reserved : 26; // Future use +} Clay_LayoutFlags; +``` + +--- + +## 14.6 Counting Set Bits + +### Method 1: Loop + +```c +int countSetBits(int n) { + int count = 0; + while (n > 0) { + count += n & 1; // Add last bit + n >>= 1; // Shift right + } + return count; +} +``` + +### Method 2: Brian Kernighan's Algorithm + +```c +int countSetBits(int n) { + int count = 0; + while (n > 0) { + n &= (n - 1); // Clear rightmost set bit + count++; + } + return count; +} + +// Example: n = 12 (1100) +// 1100 & 1011 = 1000 (count = 1) +// 1000 & 0111 = 0000 (count = 2) +``` + +### Method 3: Lookup Table + +```c +// Precomputed table for 4-bit numbers +int table[16] = { + 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4 +}; + +int countSetBits(int n) { + int count = 0; + while (n > 0) { + count += table[n & 0xF]; // Count 4 bits at a time + n >>= 4; + } + return count; +} +``` + +--- + +## 14.7 Power of Two + +### Check if Power of 2 + +```c +int isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; +} + +// Examples: +// 4 (100) & 3 (011) = 0 → true +// 5 (101) & 4 (100) = 4 → false +// 8 (1000) & 7 (0111) = 0 → true +``` + +### Next Power of 2 + +```c +int nextPowerOfTwo(int n) { + if (n <= 0) return 1; + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + return n + 1; +} + +int main(void) { + printf("%d\n", nextPowerOfTwo(5)); // 8 + printf("%d\n", nextPowerOfTwo(17)); // 32 + return 0; +} +``` + +--- + +## 14.8 Swap Values + +### Without Temporary Variable + +```c +void swap(int *a, int *b) { + if (a != b) { // Must check for same address + *a ^= *b; + *b ^= *a; + *a ^= *b; + } +} +``` + +### Swap Nibbles (4-bit) + +```c +int swapNibbles(int n) { + return ((n & 0x0F) << 4) | ((n & 0xF0) >> 4); +} + +// Example: 0x5A → 0xA5 +``` + +--- + +## 14.9 Reverse Bits + +```c +uint32_t reverseBits(uint32_t n) { + uint32_t result = 0; + for (int i = 0; i < 32; i++) { + result <<= 1; // Shift result left + result |= (n & 1); // Add rightmost bit of n + n >>= 1; // Shift n right + } + return result; +} +``` + +--- + +## 14.10 Parity + +Check if number of set bits is even or odd: + +```c +int getParity(int n) { + int parity = 0; + while (n > 0) { + parity ^= (n & 1); + n >>= 1; + } + return parity; // 0 = even, 1 = odd +} +``` + +--- + +## 14.11 Gray Code + +Convert between binary and Gray code: + +```c +// Binary to Gray +int binaryToGray(int n) { + return n ^ (n >> 1); +} + +// Gray to Binary +int grayToBinary(int n) { + int binary = 0; + while (n > 0) { + binary ^= n; + n >>= 1; + } + return binary; +} +``` + +--- + +## 14.12 Position of Rightmost Set Bit + +```c +int rightmostSetBit(int n) { + return n & ~(n - 1); +} + +// Example: 12 (1100) +// Returns: 4 (0100) - position of rightmost 1 +``` + +--- + +## 14.13 Toggle All Bits After Rightmost Set Bit + +```c +int toggleAfterRightmost(int n) { + return n ^ (n - 1); +} + +// Example: 12 (1100) +// Returns: 15 (1111) +``` + +--- + +## 14.14 Extract and Set Bit Ranges + +```c +// Extract bits from position p to p+n +int extractBits(int num, int p, int n) { + return (num >> p) & ((1 << n) - 1); +} + +// Set bits from position p to p+n +int setBits(int num, int p, int n, int value) { + int mask = ((1 << n) - 1) << p; + return (num & ~mask) | ((value << p) & mask); +} +``` + +--- + +## 14.15 Practical Applications in Clay + +### Bit Flags for UI State + +```c +typedef enum { + CLAY_ELEMENT_VISIBLE = 1 << 0, // 0x01 + CLAY_ELEMENT_ENABLED = 1 << 1, // 0x02 + CLAY_ELEMENT_FOCUSED = 1 << 2, // 0x04 + CLAY_ELEMENT_HOVERED = 1 << 3, // 0x08 + CLAY_ELEMENT_PRESSED = 1 << 4, // 0x10 + CLAY_ELEMENT_SELECTED = 1 << 5, // 0x20 + CLAY_ELEMENT_DISABLED = 1 << 6, // 0x40 + CLAY_ELEMENT_HIDDEN = 1 << 7 // 0x80 +} Clay_ElementFlags; + +typedef struct { + uint32_t flags; +} Clay_Element; + +// Check state +int isVisible(Clay_Element *el) { + return (el->flags & CLAY_ELEMENT_VISIBLE) != 0; +} + +// Set state +void setVisible(Clay_Element *el, int visible) { + if (visible) { + el->flags |= CLAY_ELEMENT_VISIBLE; // Set bit + } else { + el->flags &= ~CLAY_ELEMENT_VISIBLE; // Clear bit + } +} + +// Toggle state +void toggleVisible(Clay_Element *el) { + el->flags ^= CLAY_ELEMENT_VISIBLE; +} + +// Multiple states at once +void setInteractive(Clay_Element *el) { + el->flags |= (CLAY_ELEMENT_VISIBLE | + CLAY_ELEMENT_ENABLED); +} +``` + +### Optimized Hash Functions + +```c +// Clay uses hashing for element lookup +uint32_t hashString(const char *str, size_t length) { + uint32_t hash = 0; + for (size_t i = 0; i < length; i++) { + hash = (hash << 5) - hash + str[i]; // hash * 31 + c + // Using bit shift instead of multiply + } + return hash; +} +``` + +### Memory Alignment + +```c +// Align size to power of 2 +size_t alignSize(size_t size, size_t alignment) { + return (size + alignment - 1) & ~(alignment - 1); +} + +// Example: align to 16 bytes +// size = 25 +// (25 + 15) & ~15 = 40 & 0xFFFFFFF0 = 32 +``` + +--- + +## 14.16 Performance Tips + +**Use bit operations for:** +- ✅ Powers of 2 multiplication/division +- ✅ Flag checks (faster than booleans) +- ✅ Color packing/unpacking +- ✅ Hash functions +- ✅ Alignment calculations + +**Avoid for:** +- ❌ Regular arithmetic (compiler optimizes) +- ❌ Readability-critical code +- ❌ Floating-point operations + +--- + +## 14.17 Key Concepts Learned +- ✅ Bitwise operators: &, |, ^, ~, <<, >> +- ✅ Bit manipulation: set, clear, toggle, check +- ✅ Bit masks and extraction +- ✅ Bit fields in structs +- ✅ Counting set bits +- ✅ Power of 2 operations +- ✅ Practical applications in Clay +- ✅ Performance considerations + +--- + +## Practice Exercises + +1. Write a function to count trailing zeros in a number +2. Implement bitwise rotation (rotate left/right) +3. Find the only non-duplicate number in an array (all others appear twice) +4. Swap all odd and even bits in a number +5. Add two numbers without using + operator +6. Implement a bit vector data structure +7. Create a compact permission system using bit flags +8. Write efficient popcount for 64-bit numbers diff --git a/docs/21_standard_library.md b/docs/21_standard_library.md new file mode 100644 index 0000000..afd7cfa --- /dev/null +++ b/docs/21_standard_library.md @@ -0,0 +1,727 @@ +# Chapter 21: C Standard Library Basics + +## Complete Guide with Clay Library Examples + +--- + +## 21.1 What is the C Standard Library? + +The C Standard Library provides essential functions for: +- Input/Output (`stdio.h`) +- String manipulation (`string.h`) +- Memory management (`stdlib.h`) +- Math operations (`math.h`) +- Character handling (`ctype.h`) +- Time/Date (`time.h`) + +**Clay's Approach:** Clay is **zero-dependency** - it doesn't use the standard library! This shows how to write portable C without stdlib. + +--- + +## 21.2 stdio.h - Input/Output + +### Printf Family + +```c +#include + +int main(void) { + // Basic printf + printf("Hello, World!\n"); + + // Format specifiers + int age = 25; + float height = 5.9f; + char grade = 'A'; + + printf("Age: %d\n", age); // int + printf("Height: %.2f\n", height); // float with 2 decimals + printf("Grade: %c\n", grade); // char + printf("Hex: %x\n", 255); // hexadecimal (ff) + printf("Pointer: %p\n", (void*)&age); // pointer address + + // Width and padding + printf("%5d\n", 42); // " 42" (right-aligned) + printf("%-5d\n", 42); // "42 " (left-aligned) + printf("%05d\n", 42); // "00042" (zero-padded) + + return 0; +} +``` + +### Sprintf - Format to String + +```c +#include + +int main(void) { + char buffer[100]; + + int x = 10, y = 20; + sprintf(buffer, "Point: (%d, %d)", x, y); + printf("%s\n", buffer); // "Point: (10, 20)" + + // Safer version with size limit + snprintf(buffer, sizeof(buffer), "Value: %d", 42); + + return 0; +} +``` + +### Scanf Family + +```c +#include + +int main(void) { + int age; + float height; + char name[50]; + + printf("Enter age: "); + scanf("%d", &age); // Note: address-of operator! + + printf("Enter height: "); + scanf("%f", &height); + + printf("Enter name: "); + scanf("%49s", name); // Limit input to avoid overflow + + printf("Name: %s, Age: %d, Height: %.1f\n", name, age, height); + + return 0; +} +``` + +### File Operations + +```c +#include + +int main(void) { + FILE *file; + + // Write to file + file = fopen("output.txt", "w"); + if (file == NULL) { + printf("Error opening file!\n"); + return 1; + } + fprintf(file, "Hello, File!\n"); + fclose(file); + + // Read from file + file = fopen("output.txt", "r"); + if (file != NULL) { + char buffer[100]; + while (fgets(buffer, sizeof(buffer), file) != NULL) { + printf("%s", buffer); + } + fclose(file); + } + + return 0; +} +``` + +**Clay doesn't use stdio.h** - it's renderer-agnostic and doesn't handle file I/O internally. + +--- + +## 21.3 stdlib.h - General Utilities + +### Memory Allocation + +```c +#include + +int main(void) { + // Allocate memory + int *arr = (int*)malloc(10 * sizeof(int)); + if (arr == NULL) { + printf("Memory allocation failed!\n"); + return 1; + } + + // Use array + for (int i = 0; i < 10; i++) { + arr[i] = i * 2; + } + + // Resize array + arr = (int*)realloc(arr, 20 * sizeof(int)); + + // Free memory + free(arr); + + return 0; +} +``` + +**Clay's Approach:** Uses custom arena allocators instead of malloc/free! + +```c +// Clay's arena allocator (from clay.h) +typedef struct { + size_t capacity; + size_t nextAllocation; + char *memory; +} Clay_Arena; + +void* Clay__AllocateArena(Clay_Arena *arena, size_t size) { + if (arena->nextAllocation + size <= arena->capacity) { + void *ptr = arena->memory + arena->nextAllocation; + arena->nextAllocation += size; + return ptr; + } + return NULL; // Out of memory +} +``` + +### String to Number Conversion + +```c +#include + +int main(void) { + // String to integer + int num1 = atoi("123"); // 123 + long num2 = atol("123456789"); // 123456789 + long long num3 = atoll("9999999999"); // 9999999999 + + // String to float + double num4 = atof("3.14159"); // 3.14159 + + // More robust conversion with error checking + char *endptr; + long value = strtol("123abc", &endptr, 10); + if (*endptr != '\0') { + printf("Invalid number: stopped at '%s'\n", endptr); + } + + return 0; +} +``` + +### Random Numbers + +```c +#include +#include + +int main(void) { + // Seed random number generator + srand(time(NULL)); + + // Generate random numbers + for (int i = 0; i < 5; i++) { + int random = rand(); // 0 to RAND_MAX + printf("%d\n", random); + } + + // Random in range [min, max] + int min = 1, max = 100; + int randomInRange = min + rand() % (max - min + 1); + printf("Random (1-100): %d\n", randomInRange); + + return 0; +} +``` + +### Program Termination + +```c +#include + +void cleanup(void) { + printf("Cleaning up...\n"); +} + +int main(void) { + // Register cleanup function + atexit(cleanup); + + // Normal exit + // exit(0); // Success + // exit(1); // Failure + + // Abnormal termination + // abort(); // Immediate termination + + return 0; +} // cleanup() called automatically +``` + +### Environment Variables + +```c +#include +#include + +int main(void) { + // Get environment variable + char *path = getenv("PATH"); + if (path != NULL) { + printf("PATH: %s\n", path); + } + + char *home = getenv("HOME"); + if (home != NULL) { + printf("HOME: %s\n", home); + } + + return 0; +} +``` + +--- + +## 21.4 string.h - String Manipulation + +### String Length + +```c +#include + +int main(void) { + char str[] = "Hello"; + size_t len = strlen(str); // 5 + printf("Length: %zu\n", len); + + return 0; +} +``` + +**Clay's Implementation** (from clay.h): +```c +// Clay uses explicit length, no strlen needed +typedef struct { + int32_t length; // Length stored directly! + const char *chars; +} Clay_String; + +// O(1) length access +int getLength(Clay_String *str) { + return str->length; // No need to count! +} +``` + +### String Copy + +```c +#include + +int main(void) { + char src[] = "Hello"; + char dest[20]; + + // Copy string + strcpy(dest, src); + + // Copy with size limit (safer) + strncpy(dest, src, sizeof(dest) - 1); + dest[sizeof(dest) - 1] = '\0'; // Ensure null termination + + printf("%s\n", dest); + + return 0; +} +``` + +### String Concatenation + +```c +#include + +int main(void) { + char str[50] = "Hello"; + + // Concatenate + strcat(str, " World"); // "Hello World" + + // Concatenate with limit (safer) + strncat(str, "!", sizeof(str) - strlen(str) - 1); + + printf("%s\n", str); + + return 0; +} +``` + +### String Comparison + +```c +#include + +int main(void) { + char str1[] = "Apple"; + char str2[] = "Banana"; + + // Compare strings + int result = strcmp(str1, str2); + if (result < 0) { + printf("%s comes before %s\n", str1, str2); + } else if (result > 0) { + printf("%s comes after %s\n", str1, str2); + } else { + printf("Strings are equal\n"); + } + + // Compare n characters + if (strncmp(str1, str2, 3) == 0) { + printf("First 3 characters match\n"); + } + + return 0; +} +``` + +### Memory Operations + +```c +#include + +int main(void) { + char buffer[20]; + + // Set memory to value + memset(buffer, 'A', 10); + buffer[10] = '\0'; + printf("%s\n", buffer); // "AAAAAAAAAA" + + // Copy memory + char src[] = "Hello"; + char dest[20]; + memcpy(dest, src, strlen(src) + 1); // Include \0 + + // Move memory (handles overlapping regions) + memmove(dest + 2, dest, strlen(dest) + 1); // Shift right + printf("%s\n", dest); // "HeHello" + + // Compare memory + if (memcmp(src, dest, 5) == 0) { + printf("Memory regions match\n"); + } + + return 0; +} +``` + +**Clay's Approach:** +```c +// Clay uses custom memory functions when needed +static inline void Clay__MemoryCopy( + void *dest, + const void *src, + size_t size +) { + char *d = (char*)dest; + const char *s = (const char*)src; + for (size_t i = 0; i < size; i++) { + d[i] = s[i]; + } +} +``` + +--- + +## 21.5 math.h - Mathematical Functions + +```c +#include +#include + +int main(void) { + // Power and roots + printf("2^3 = %.0f\n", pow(2, 3)); // 8 + printf("sqrt(16) = %.0f\n", sqrt(16)); // 4 + printf("cbrt(27) = %.0f\n", cbrt(27)); // 3 + + // Trigonometry + printf("sin(π/2) = %.1f\n", sin(M_PI / 2)); // 1.0 + printf("cos(0) = %.1f\n", cos(0)); // 1.0 + printf("tan(π/4) = %.1f\n", tan(M_PI / 4)); // 1.0 + + // Rounding + printf("ceil(3.2) = %.0f\n", ceil(3.2)); // 4 + printf("floor(3.8) = %.0f\n", floor(3.8)); // 3 + printf("round(3.5) = %.0f\n", round(3.5)); // 4 + + // Absolute value + printf("fabs(-5.5) = %.1f\n", fabs(-5.5)); // 5.5 + printf("abs(-5) = %d\n", abs(-5)); // 5 + + // Logarithms + printf("log(e) = %.1f\n", log(M_E)); // 1.0 + printf("log10(100) = %.0f\n", log10(100)); // 2 + + // Exponential + printf("exp(1) = %.2f\n", exp(1)); // 2.72 (e) + + return 0; +} +``` + +**Clay's Implementation:** +```c +// Clay implements its own min/max (no stdlib needed) +static inline float Clay__Min(float a, float b) { + return a < b ? a : b; +} + +static inline float Clay__Max(float a, float b) { + return a > b ? a : b; +} + +static inline float Clay__Clamp(float value, float min, float max) { + return Clay__Max(min, Clay__Min(value, max)); +} +``` + +--- + +## 21.6 ctype.h - Character Handling + +```c +#include +#include + +int main(void) { + char ch = 'A'; + + // Character testing + if (isalpha(ch)) printf("Letter\n"); + if (isdigit(ch)) printf("Digit\n"); + if (isalnum(ch)) printf("Alphanumeric\n"); + if (isupper(ch)) printf("Uppercase\n"); + if (islower(ch)) printf("Lowercase\n"); + if (isspace(ch)) printf("Whitespace\n"); + if (ispunct(ch)) printf("Punctuation\n"); + + // Character conversion + printf("Upper: %c\n", toupper('a')); // 'A' + printf("Lower: %c\n", tolower('A')); // 'a' + + // Practical example: validate identifier + int isValidIdentifier(const char *str) { + if (!isalpha(str[0]) && str[0] != '_') { + return 0; // Must start with letter or _ + } + for (int i = 1; str[i] != '\0'; i++) { + if (!isalnum(str[i]) && str[i] != '_') { + return 0; + } + } + return 1; + } + + printf("valid_name: %d\n", isValidIdentifier("valid_name")); // 1 + printf("123invalid: %d\n", isValidIdentifier("123invalid")); // 0 + + return 0; +} +``` + +--- + +## 21.7 time.h - Time and Date + +```c +#include +#include + +int main(void) { + // Current time + time_t now = time(NULL); + printf("Seconds since epoch: %ld\n", now); + + // Convert to readable format + struct tm *timeinfo = localtime(&now); + printf("Current time: %s", asctime(timeinfo)); + + // Format time + char buffer[80]; + strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo); + printf("Formatted: %s\n", buffer); + + // Measure execution time + clock_t start = clock(); + + // Do some work + for (int i = 0; i < 1000000; i++) { + // Busy work + } + + clock_t end = clock(); + double cpu_time = ((double)(end - start)) / CLOCKS_PER_SEC; + printf("CPU time: %.6f seconds\n", cpu_time); + + // Sleep (POSIX) + // sleep(1); // Sleep 1 second + + return 0; +} +``` + +--- + +## 21.8 assert.h - Debugging + +```c +#include +#include + +int divide(int a, int b) { + assert(b != 0); // Crash if b is 0 (in debug builds) + return a / b; +} + +int main(void) { + int result = divide(10, 2); // OK + printf("Result: %d\n", result); + + // result = divide(10, 0); // Crashes with error message + + // Disable asserts in release + // Compile with: gcc -DNDEBUG program.c + + return 0; +} +``` + +**Clay's Approach:** +```c +// Clay has custom error handling +#define CLAY__ASSERT(condition) \ + if (!(condition)) { \ + Clay__ErrorHandler(...); \ + } +``` + +--- + +## 21.9 stdint.h - Fixed-Width Integers + +```c +#include +#include + +int main(void) { + // Exact-width integers + int8_t i8 = 127; // -128 to 127 + uint8_t u8 = 255; // 0 to 255 + int16_t i16 = 32767; // -32768 to 32767 + uint16_t u16 = 65535; // 0 to 65535 + int32_t i32 = 2147483647; + uint32_t u32 = 4294967295; + int64_t i64 = 9223372036854775807; + uint64_t u64 = 18446744073709551615ULL; + + // Pointer-sized integers + intptr_t iptr; // Can hold pointer + uintptr_t uptr; + + // Fast types (at least N bits) + int_fast32_t fast32; // Fast 32-bit (may be 64-bit) + int_least32_t least32; // At least 32-bit (may be 32+) + + // Print with proper format specifiers + printf("int32: %" PRId32 "\n", i32); + printf("uint64: %" PRIu64 "\n", u64); + + return 0; +} +``` + +**Clay uses fixed-width types extensively:** +```c +typedef struct { + int32_t capacity; // Exactly 32 bits + int32_t length; + uint32_t *internalArray; +} Clay__int32_tArray; +``` + +--- + +## 21.10 stdbool.h - Boolean Type + +```c +#include +#include + +int main(void) { + bool isActive = true; + bool isValid = false; + + if (isActive) { + printf("Active!\n"); + } + + // Boolean operations + bool result = isActive && !isValid; // true + + return 0; +} +``` + +**Pre-C99 approach:** +```c +typedef enum { + false = 0, + true = 1 +} bool; +``` + +--- + +## 21.11 limits.h - Implementation Limits + +```c +#include +#include + +int main(void) { + printf("CHAR_BIT: %d\n", CHAR_BIT); // 8 + printf("CHAR_MIN: %d\n", CHAR_MIN); + printf("CHAR_MAX: %d\n", CHAR_MAX); + printf("INT_MIN: %d\n", INT_MIN); // -2147483648 + printf("INT_MAX: %d\n", INT_MAX); // 2147483647 + printf("LONG_MAX: %ld\n", LONG_MAX); + + // Check for overflow + int x = INT_MAX; + if (x + 1 < x) { + printf("Overflow detected!\n"); + } + + return 0; +} +``` + +--- + +## 21.12 Key Concepts Learned +- ✅ stdio.h for I/O operations +- ✅ stdlib.h for memory and utilities +- ✅ string.h for string manipulation +- ✅ math.h for mathematical functions +- ✅ ctype.h for character handling +- ✅ time.h for time/date operations +- ✅ assert.h for debugging +- ✅ stdint.h for fixed-width types +- ✅ stdbool.h for boolean type +- ✅ Clay's zero-dependency approach + +--- + +## Practice Exercises + +1. Write a program to read a file and count words +2. Implement your own strlen without using stdlib +3. Create a simple calculator using scanf and math.h +4. Build a random password generator +5. Make a function to format time as "X days, Y hours, Z minutes" +6. Implement case-insensitive string comparison +7. Create a memory pool allocator (like Clay's arena) +8. Write a benchmark utility using clock() diff --git a/docs/22_file_io.md b/docs/22_file_io.md new file mode 100644 index 0000000..8e2798d --- /dev/null +++ b/docs/22_file_io.md @@ -0,0 +1,805 @@ +# Chapter 22: File I/O in C + +## Complete Guide with Clay Library Examples + +--- + +## 22.1 Introduction to File I/O + +C provides file operations through `stdio.h`: +- Open files +- Read/write data +- Close files +- Navigate file position +- Check file status + +**Clay's Approach:** Clay doesn't do file I/O - it's a UI layout library. But applications using Clay need file operations for saving/loading UI state, configurations, etc. + +--- + +## 22.2 Opening and Closing Files + +### Basic File Operations + +```c +#include + +int main(void) { + FILE *file; + + // Open file for writing + file = fopen("output.txt", "w"); + if (file == NULL) { + printf("Error opening file!\n"); + return 1; + } + + // Write to file + fprintf(file, "Hello, File!\n"); + + // Close file + fclose(file); + + return 0; +} +``` + +### File Modes + +| Mode | Description | Creates if not exists | Truncates existing | +|------|-------------|----------------------|-------------------| +| `"r"` | Read only | No | No | +| `"w"` | Write only | Yes | Yes | +| `"a"` | Append | Yes | No | +| `"r+"` | Read/Write | No | No | +| `"w+"` | Read/Write | Yes | Yes | +| `"a+"` | Read/Append | Yes | No | +| `"rb"` | Read binary | No | No | +| `"wb"` | Write binary | Yes | Yes | + +```c +FILE *fr = fopen("input.txt", "r"); // Read text +FILE *fw = fopen("output.txt", "w"); // Write text +FILE *fa = fopen("log.txt", "a"); // Append text +FILE *fb = fopen("data.bin", "rb"); // Read binary +``` + +--- + +## 22.3 Writing to Files + +### fprintf - Formatted Output + +```c +#include + +int main(void) { + FILE *file = fopen("data.txt", "w"); + if (file == NULL) { + return 1; + } + + int age = 25; + float height = 5.9f; + char name[] = "John"; + + // Write formatted data + fprintf(file, "Name: %s\n", name); + fprintf(file, "Age: %d\n", age); + fprintf(file, "Height: %.1f\n", height); + + fclose(file); + return 0; +} +``` + +### fputs - Write String + +```c +#include + +int main(void) { + FILE *file = fopen("output.txt", "w"); + if (file == NULL) return 1; + + fputs("Line 1\n", file); + fputs("Line 2\n", file); + fputs("Line 3\n", file); + + fclose(file); + return 0; +} +``` + +### fputc - Write Character + +```c +#include + +int main(void) { + FILE *file = fopen("output.txt", "w"); + if (file == NULL) return 1; + + fputc('H', file); + fputc('i', file); + fputc('\n', file); + + fclose(file); + return 0; +} +``` + +### fwrite - Write Binary Data + +```c +#include + +typedef struct { + int id; + char name[50]; + float salary; +} Employee; + +int main(void) { + FILE *file = fopen("employees.dat", "wb"); + if (file == NULL) return 1; + + Employee emp = {1, "John Doe", 50000.0f}; + + // Write struct to binary file + size_t written = fwrite(&emp, sizeof(Employee), 1, file); + if (written != 1) { + printf("Write error!\n"); + } + + fclose(file); + return 0; +} +``` + +--- + +## 22.4 Reading from Files + +### fscanf - Formatted Input + +```c +#include + +int main(void) { + FILE *file = fopen("data.txt", "r"); + if (file == NULL) return 1; + + char name[50]; + int age; + float height; + + // Read formatted data + fscanf(file, "Name: %s\n", name); + fscanf(file, "Age: %d\n", &age); + fscanf(file, "Height: %f\n", &height); + + printf("Name: %s, Age: %d, Height: %.1f\n", name, age, height); + + fclose(file); + return 0; +} +``` + +### fgets - Read Line + +```c +#include + +int main(void) { + FILE *file = fopen("input.txt", "r"); + if (file == NULL) return 1; + + char buffer[256]; + + // Read line by line + while (fgets(buffer, sizeof(buffer), file) != NULL) { + printf("%s", buffer); + } + + fclose(file); + return 0; +} +``` + +### fgetc - Read Character + +```c +#include + +int main(void) { + FILE *file = fopen("input.txt", "r"); + if (file == NULL) return 1; + + int ch; + + // Read character by character + while ((ch = fgetc(file)) != EOF) { + putchar(ch); + } + + fclose(file); + return 0; +} +``` + +### fread - Read Binary Data + +```c +#include + +typedef struct { + int id; + char name[50]; + float salary; +} Employee; + +int main(void) { + FILE *file = fopen("employees.dat", "rb"); + if (file == NULL) return 1; + + Employee emp; + + // Read struct from binary file + size_t read = fread(&emp, sizeof(Employee), 1, file); + if (read == 1) { + printf("ID: %d, Name: %s, Salary: %.2f\n", + emp.id, emp.name, emp.salary); + } + + fclose(file); + return 0; +} +``` + +--- + +## 22.5 File Position + +### ftell - Get Position + +```c +#include + +int main(void) { + FILE *file = fopen("data.txt", "r"); + if (file == NULL) return 1; + + // Get current position + long pos = ftell(file); + printf("Position: %ld\n", pos); // 0 (at start) + + // Read some data + char buffer[10]; + fgets(buffer, sizeof(buffer), file); + + // Get new position + pos = ftell(file); + printf("Position after read: %ld\n", pos); + + fclose(file); + return 0; +} +``` + +### fseek - Set Position + +```c +#include + +int main(void) { + FILE *file = fopen("data.txt", "r"); + if (file == NULL) return 1; + + // Seek to end + fseek(file, 0, SEEK_END); + long size = ftell(file); + printf("File size: %ld bytes\n", size); + + // Seek to beginning + fseek(file, 0, SEEK_SET); + + // Seek forward 10 bytes + fseek(file, 10, SEEK_CUR); + + fclose(file); + return 0; +} +``` + +**Seek origins:** +- `SEEK_SET` - Beginning of file +- `SEEK_CUR` - Current position +- `SEEK_END` - End of file + +### rewind - Reset to Beginning + +```c +#include + +int main(void) { + FILE *file = fopen("data.txt", "r"); + if (file == NULL) return 1; + + // Read file + char buffer[100]; + fgets(buffer, sizeof(buffer), file); + + // Go back to start + rewind(file); // Same as fseek(file, 0, SEEK_SET) + + // Read again + fgets(buffer, sizeof(buffer), file); + + fclose(file); + return 0; +} +``` + +--- + +## 22.6 File Status + +### feof - Check End of File + +```c +#include + +int main(void) { + FILE *file = fopen("input.txt", "r"); + if (file == NULL) return 1; + + char ch; + while (!feof(file)) { + ch = fgetc(file); + if (ch != EOF) { + putchar(ch); + } + } + + fclose(file); + return 0; +} +``` + +### ferror - Check Errors + +```c +#include + +int main(void) { + FILE *file = fopen("output.txt", "w"); + if (file == NULL) return 1; + + fprintf(file, "Test\n"); + + if (ferror(file)) { + printf("Error writing to file!\n"); + clearerr(file); // Clear error flag + } + + fclose(file); + return 0; +} +``` + +### File Existence + +```c +#include + +int fileExists(const char *filename) { + FILE *file = fopen(filename, "r"); + if (file != NULL) { + fclose(file); + return 1; + } + return 0; +} + +int main(void) { + if (fileExists("config.txt")) { + printf("Config file found!\n"); + } else { + printf("Config file not found!\n"); + } + return 0; +} +``` + +--- + +## 22.7 Practical Examples + +### Copy File + +```c +#include + +int copyFile(const char *src, const char *dest) { + FILE *source = fopen(src, "rb"); + if (source == NULL) return 0; + + FILE *target = fopen(dest, "wb"); + if (target == NULL) { + fclose(source); + return 0; + } + + // Copy buffer by buffer + char buffer[1024]; + size_t bytes; + + while ((bytes = fread(buffer, 1, sizeof(buffer), source)) > 0) { + fwrite(buffer, 1, bytes, target); + } + + fclose(source); + fclose(target); + return 1; +} + +int main(void) { + if (copyFile("input.txt", "output.txt")) { + printf("File copied successfully!\n"); + } + return 0; +} +``` + +### Count Lines in File + +```c +#include + +int countLines(const char *filename) { + FILE *file = fopen(filename, "r"); + if (file == NULL) return -1; + + int lines = 0; + int ch; + + while ((ch = fgetc(file)) != EOF) { + if (ch == '\n') { + lines++; + } + } + + fclose(file); + return lines; +} + +int main(void) { + int lines = countLines("input.txt"); + printf("Lines: %d\n", lines); + return 0; +} +``` + +### Read Entire File + +```c +#include +#include + +char* readFile(const char *filename, size_t *size) { + FILE *file = fopen(filename, "rb"); + if (file == NULL) return NULL; + + // Get file size + fseek(file, 0, SEEK_END); + long filesize = ftell(file); + rewind(file); + + // Allocate buffer + char *buffer = (char*)malloc(filesize + 1); + if (buffer == NULL) { + fclose(file); + return NULL; + } + + // Read entire file + size_t read = fread(buffer, 1, filesize, file); + buffer[read] = '\0'; // Null terminate + + if (size != NULL) { + *size = read; + } + + fclose(file); + return buffer; +} + +int main(void) { + size_t size; + char *content = readFile("input.txt", &size); + + if (content != NULL) { + printf("Content (%zu bytes):\n%s\n", size, content); + free(content); + } + + return 0; +} +``` + +--- + +## 22.8 Configuration File (Clay Example) + +### Save Clay UI Configuration + +```c +#include + +typedef struct { + float width; + float height; + int layoutDirection; + int padding; +} Clay_LayoutConfig; + +int saveLayoutConfig(const char *filename, Clay_LayoutConfig *config) { + FILE *file = fopen(filename, "w"); + if (file == NULL) return 0; + + fprintf(file, "width=%.2f\n", config->width); + fprintf(file, "height=%.2f\n", config->height); + fprintf(file, "layoutDirection=%d\n", config->layoutDirection); + fprintf(file, "padding=%d\n", config->padding); + + fclose(file); + return 1; +} + +int loadLayoutConfig(const char *filename, Clay_LayoutConfig *config) { + FILE *file = fopen(filename, "r"); + if (file == NULL) return 0; + + fscanf(file, "width=%f\n", &config->width); + fscanf(file, "height=%f\n", &config->height); + fscanf(file, "layoutDirection=%d\n", &config->layoutDirection); + fscanf(file, "padding=%d\n", &config->padding); + + fclose(file); + return 1; +} + +int main(void) { + Clay_LayoutConfig config = { + .width = 800.0f, + .height = 600.0f, + .layoutDirection = 0, + .padding = 16 + }; + + // Save config + saveLayoutConfig("layout.cfg", &config); + + // Load config + Clay_LayoutConfig loaded = {0}; + if (loadLayoutConfig("layout.cfg", &loaded)) { + printf("Loaded: %.0fx%.0f, dir=%d, pad=%d\n", + loaded.width, loaded.height, + loaded.layoutDirection, loaded.padding); + } + + return 0; +} +``` + +--- + +## 22.9 Binary File Format + +### Save/Load Array + +```c +#include +#include + +typedef struct { + int count; + float *values; +} FloatArray; + +int saveFloatArray(const char *filename, FloatArray *arr) { + FILE *file = fopen(filename, "wb"); + if (file == NULL) return 0; + + // Write count + fwrite(&arr->count, sizeof(int), 1, file); + + // Write values + fwrite(arr->values, sizeof(float), arr->count, file); + + fclose(file); + return 1; +} + +FloatArray* loadFloatArray(const char *filename) { + FILE *file = fopen(filename, "rb"); + if (file == NULL) return NULL; + + FloatArray *arr = (FloatArray*)malloc(sizeof(FloatArray)); + + // Read count + fread(&arr->count, sizeof(int), 1, file); + + // Allocate and read values + arr->values = (float*)malloc(arr->count * sizeof(float)); + fread(arr->values, sizeof(float), arr->count, file); + + fclose(file); + return arr; +} + +int main(void) { + // Create array + FloatArray arr; + arr.count = 5; + arr.values = (float*)malloc(5 * sizeof(float)); + for (int i = 0; i < 5; i++) { + arr.values[i] = i * 1.5f; + } + + // Save + saveFloatArray("data.bin", &arr); + + // Load + FloatArray *loaded = loadFloatArray("data.bin"); + if (loaded != NULL) { + printf("Loaded %d values:\n", loaded->count); + for (int i = 0; i < loaded->count; i++) { + printf("%.1f ", loaded->values[i]); + } + printf("\n"); + + free(loaded->values); + free(loaded); + } + + free(arr.values); + return 0; +} +``` + +--- + +## 22.10 Error Handling + +### Robust File Operations + +```c +#include +#include +#include + +typedef enum { + FILE_OK, + FILE_ERROR_OPEN, + FILE_ERROR_READ, + FILE_ERROR_WRITE +} FileError; + +FileError writeData(const char *filename, const char *data) { + FILE *file = fopen(filename, "w"); + if (file == NULL) { + printf("Open error: %s\n", strerror(errno)); + return FILE_ERROR_OPEN; + } + + if (fputs(data, file) == EOF) { + printf("Write error: %s\n", strerror(errno)); + fclose(file); + return FILE_ERROR_WRITE; + } + + fclose(file); + return FILE_OK; +} + +int main(void) { + FileError err = writeData("output.txt", "Hello!\n"); + if (err != FILE_OK) { + printf("Error code: %d\n", err); + } + return 0; +} +``` + +--- + +## 22.11 Temporary Files + +```c +#include + +int main(void) { + // Create temporary file + FILE *temp = tmpfile(); + if (temp == NULL) { + printf("Error creating temp file!\n"); + return 1; + } + + // Use temp file + fprintf(temp, "Temporary data\n"); + rewind(temp); + + char buffer[100]; + fgets(buffer, sizeof(buffer), temp); + printf("Read: %s", buffer); + + // File automatically deleted on close + fclose(temp); + + return 0; +} +``` + +--- + +## 22.12 Buffer Control + +### Set Buffer Mode + +```c +#include + +int main(void) { + FILE *file = fopen("output.txt", "w"); + if (file == NULL) return 1; + + // Disable buffering + setbuf(file, NULL); + + // Or set custom buffer + char buffer[BUFSIZ]; + setvbuf(file, buffer, _IOFBF, BUFSIZ); // Full buffering + + // _IONBF = No buffering + // _IOLBF = Line buffering + // _IOFBF = Full buffering + + fprintf(file, "Data\n"); + + // Force write buffer + fflush(file); + + fclose(file); + return 0; +} +``` + +--- + +## 22.13 Key Concepts Learned +- ✅ Opening and closing files +- ✅ File modes (read, write, append, binary) +- ✅ Writing: fprintf, fputs, fputc, fwrite +- ✅ Reading: fscanf, fgets, fgetc, fread +- ✅ File position: ftell, fseek, rewind +- ✅ File status: feof, ferror +- ✅ Binary file operations +- ✅ Error handling +- ✅ Configuration files +- ✅ Buffer control + +--- + +## Practice Exercises + +1. Create a text editor that can save/load files +2. Build a CSV parser and writer +3. Implement a simple database using binary files +4. Create a log file system with timestamps +5. Write a file encryption/decryption program +6. Build a file comparison utility (diff) +7. Implement a config file parser (INI format) +8. Create a file compression utility (run-length encoding) diff --git a/docs/23_command_line_arguments.md b/docs/23_command_line_arguments.md new file mode 100644 index 0000000..4427da0 --- /dev/null +++ b/docs/23_command_line_arguments.md @@ -0,0 +1,817 @@ +# Chapter 23: Command-Line Arguments in C + +## Complete Guide with Clay Library Examples + +--- + +## 23.1 Introduction to Command-Line Arguments + +When you run a program from the terminal: +```bash +./program arg1 arg2 arg3 +``` + +C provides access to these arguments through `main`: + +```c +int main(int argc, char *argv[]) { + // argc = argument count + // argv = argument vector (array of strings) + return 0; +} +``` + +**Parts:** +- `argc` - Number of arguments (including program name) +- `argv` - Array of argument strings +- `argv[0]` - Program name +- `argv[1]` to `argv[argc-1]` - Actual arguments +- `argv[argc]` - NULL pointer + +--- + +## 23.2 Basic Example + +```c +#include + +int main(int argc, char *argv[]) { + printf("Program name: %s\n", argv[0]); + printf("Argument count: %d\n", argc); + + printf("Arguments:\n"); + for (int i = 0; i < argc; i++) { + printf(" argv[%d] = %s\n", i, argv[i]); + } + + return 0; +} +``` + +**Running:** +```bash +$ ./program hello world 123 +Program name: ./program +Argument count: 4 +Arguments: + argv[0] = ./program + argv[1] = hello + argv[2] = world + argv[3] = 123 +``` + +--- + +## 23.3 Processing Arguments + +### Check Argument Count + +```c +#include + +int main(int argc, char *argv[]) { + if (argc != 3) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + char *name = argv[1]; + int age = atoi(argv[2]); // Convert string to int + + printf("Name: %s, Age: %d\n", name, age); + return 0; +} +``` + +**Running:** +```bash +$ ./program John 25 +Name: John, Age: 25 + +$ ./program John +Usage: ./program +``` + +--- + +## 23.4 Parsing Numeric Arguments + +```c +#include +#include + +int main(int argc, char *argv[]) { + if (argc != 4) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + // Convert arguments to numbers + int a = atoi(argv[1]); // Integer + long b = atol(argv[2]); // Long + double c = atof(argv[3]); // Double + + printf("a = %d\n", a); + printf("b = %ld\n", b); + printf("c = %.2f\n", c); + + return 0; +} +``` + +**Running:** +```bash +$ ./program 10 1000000 3.14 +a = 10 +b = 1000000 +c = 3.14 +``` + +--- + +## 23.5 Command-Line Flags + +### Simple Flags + +```c +#include +#include + +int main(int argc, char *argv[]) { + int verbose = 0; + int debug = 0; + + // Check for flags + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-v") == 0 || + strcmp(argv[i], "--verbose") == 0) { + verbose = 1; + } + else if (strcmp(argv[i], "-d") == 0 || + strcmp(argv[i], "--debug") == 0) { + debug = 1; + } + } + + printf("Verbose: %s\n", verbose ? "ON" : "OFF"); + printf("Debug: %s\n", debug ? "ON" : "OFF"); + + return 0; +} +``` + +**Running:** +```bash +$ ./program -v +Verbose: ON +Debug: OFF + +$ ./program -v -d +Verbose: ON +Debug: ON + +$ ./program --verbose --debug +Verbose: ON +Debug: ON +``` + +--- + +## 23.6 Flags with Values + +```c +#include +#include +#include + +int main(int argc, char *argv[]) { + char *output = "output.txt"; // Default + int level = 1; // Default + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) { + output = argv[++i]; // Next argument is the value + } + else if (strcmp(argv[i], "-l") == 0 && i + 1 < argc) { + level = atoi(argv[++i]); + } + } + + printf("Output: %s\n", output); + printf("Level: %d\n", level); + + return 0; +} +``` + +**Running:** +```bash +$ ./program -o result.txt -l 5 +Output: result.txt +Level: 5 + +$ ./program +Output: output.txt +Level: 1 +``` + +--- + +## 23.7 getopt for Option Parsing + +POSIX provides `getopt` for standard option parsing: + +```c +#include +#include // POSIX + +int main(int argc, char *argv[]) { + int opt; + int verbose = 0; + char *output = NULL; + int level = 1; + + // Parse options + while ((opt = getopt(argc, argv, "vo:l:")) != -1) { + switch (opt) { + case 'v': + verbose = 1; + break; + case 'o': + output = optarg; // Option argument + break; + case 'l': + level = atoi(optarg); + break; + case '?': + printf("Unknown option: %c\n", optopt); + return 1; + } + } + + // Process remaining arguments + for (int i = optind; i < argc; i++) { + printf("Non-option arg: %s\n", argv[i]); + } + + printf("Verbose: %d\n", verbose); + printf("Output: %s\n", output ? output : "none"); + printf("Level: %d\n", level); + + return 0; +} +``` + +**Running:** +```bash +$ ./program -v -o test.txt -l 3 file1 file2 +Non-option arg: file1 +Non-option arg: file2 +Verbose: 1 +Output: test.txt +Level: 3 +``` + +--- + +## 23.8 Clay Example: UI Configuration + +Imagine a Clay-based application with command-line options: + +```c +#include +#include +#include + +typedef struct { + int width; + int height; + int fullscreen; + char *title; +} AppConfig; + +void printUsage(const char *programName) { + printf("Usage: %s [options]\n", programName); + printf("Options:\n"); + printf(" -w Window width (default: 800)\n"); + printf(" -h Window height (default: 600)\n"); + printf(" -f Fullscreen mode\n"); + printf(" -t Window title\n"); + printf(" --help Show this help\n"); +} + +int parseArgs(int argc, char *argv[], AppConfig *config) { + // Defaults + config->width = 800; + config->height = 600; + config->fullscreen = 0; + config->title = "Clay Application"; + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-w") == 0 && i + 1 < argc) { + config->width = atoi(argv[++i]); + } + else if (strcmp(argv[i], "-h") == 0 && i + 1 < argc) { + config->height = atoi(argv[++i]); + } + else if (strcmp(argv[i], "-f") == 0) { + config->fullscreen = 1; + } + else if (strcmp(argv[i], "-t") == 0 && i + 1 < argc) { + config->title = argv[++i]; + } + else if (strcmp(argv[i], "--help") == 0) { + return 0; // Show help + } + else { + printf("Unknown option: %s\n", argv[i]); + return 0; + } + } + + return 1; +} + +int main(int argc, char *argv[]) { + AppConfig config; + + if (!parseArgs(argc, argv, &config)) { + printUsage(argv[0]); + return 1; + } + + printf("Starting Clay application:\n"); + printf(" Size: %dx%d\n", config.width, config.height); + printf(" Fullscreen: %s\n", config.fullscreen ? "Yes" : "No"); + printf(" Title: %s\n", config.title); + + // Initialize Clay with config + // Clay_Dimensions screenSize = {config.width, config.height}; + // Clay_Initialize(...); + + return 0; +} +``` + +**Running:** +```bash +$ ./clay_app -w 1024 -h 768 -f -t "My UI" +Starting Clay application: + Size: 1024x768 + Fullscreen: Yes + Title: My UI + +$ ./clay_app --help +Usage: ./clay_app [options] +Options: + -w <width> Window width (default: 800) + -h <height> Window height (default: 600) + -f Fullscreen mode + -t <title> Window title + --help Show this help +``` + +--- + +## 23.9 Subcommands (git-style) + +```c +#include <stdio.h> +#include <string.h> + +void cmd_init(int argc, char *argv[]) { + printf("Initializing...\n"); +} + +void cmd_add(int argc, char *argv[]) { + if (argc < 1) { + printf("Error: add requires a file argument\n"); + return; + } + printf("Adding: %s\n", argv[0]); +} + +void cmd_commit(int argc, char *argv[]) { + char *message = "Default message"; + if (argc >= 2 && strcmp(argv[0], "-m") == 0) { + message = argv[1]; + } + printf("Committing: %s\n", message); +} + +int main(int argc, char *argv[]) { + if (argc < 2) { + printf("Usage: %s <command> [args]\n", argv[0]); + printf("Commands: init, add, commit\n"); + return 1; + } + + char *command = argv[1]; + int cmd_argc = argc - 2; + char **cmd_argv = argv + 2; + + if (strcmp(command, "init") == 0) { + cmd_init(cmd_argc, cmd_argv); + } + else if (strcmp(command, "add") == 0) { + cmd_add(cmd_argc, cmd_argv); + } + else if (strcmp(command, "commit") == 0) { + cmd_commit(cmd_argc, cmd_argv); + } + else { + printf("Unknown command: %s\n", command); + return 1; + } + + return 0; +} +``` + +**Running:** +```bash +$ ./mygit init +Initializing... + +$ ./mygit add file.txt +Adding: file.txt + +$ ./mygit commit -m "Initial commit" +Committing: Initial commit +``` + +--- + +## 23.10 Environment Variables + +Access environment variables alongside arguments: + +```c +#include <stdio.h> +#include <stdlib.h> + +int main(int argc, char *argv[], char *envp[]) { + printf("Arguments:\n"); + for (int i = 0; i < argc; i++) { + printf(" %s\n", argv[i]); + } + + printf("\nEnvironment Variables:\n"); + for (int i = 0; envp[i] != NULL; i++) { + printf(" %s\n", envp[i]); + } + + // Or use getenv + char *home = getenv("HOME"); + printf("\nHOME: %s\n", home); + + return 0; +} +``` + +--- + +## 23.11 Argument Validation + +### Robust Argument Parser + +```c +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <errno.h> + +int parseInteger(const char *str, int *out) { + char *endptr; + errno = 0; + + long val = strtol(str, &endptr, 10); + + if (errno == ERANGE || val > INT_MAX || val < INT_MIN) { + return 0; // Out of range + } + + if (endptr == str || *endptr != '\0') { + return 0; // Not a valid number + } + + *out = (int)val; + return 1; +} + +int main(int argc, char *argv[]) { + if (argc != 2) { + printf("Usage: %s <number>\n", argv[0]); + return 1; + } + + int value; + if (!parseInteger(argv[1], &value)) { + printf("Error: '%s' is not a valid integer\n", argv[1]); + return 1; + } + + printf("Valid integer: %d\n", value); + return 0; +} +``` + +--- + +## 23.12 Configuration Priority + +Combine defaults, config files, and command-line arguments: + +```c +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +typedef struct { + int port; + char *host; + int debug; +} ServerConfig; + +void setDefaults(ServerConfig *config) { + config->port = 8080; + config->host = "localhost"; + config->debug = 0; +} + +void loadConfigFile(ServerConfig *config, const char *filename) { + FILE *file = fopen(filename, "r"); + if (file == NULL) return; + + char line[256]; + while (fgets(line, sizeof(line), file)) { + if (strncmp(line, "port=", 5) == 0) { + config->port = atoi(line + 5); + } + else if (strncmp(line, "host=", 5) == 0) { + config->host = strdup(line + 5); + // Remove newline + config->host[strcspn(config->host, "\n")] = 0; + } + } + + fclose(file); +} + +void parseArgs(ServerConfig *config, int argc, char *argv[]) { + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) { + config->port = atoi(argv[++i]); + } + else if (strcmp(argv[i], "-h") == 0 && i + 1 < argc) { + config->host = argv[++i]; + } + else if (strcmp(argv[i], "-d") == 0) { + config->debug = 1; + } + } +} + +int main(int argc, char *argv[]) { + ServerConfig config; + + // Priority: defaults < config file < command line + setDefaults(&config); + loadConfigFile(&config, "server.cfg"); + parseArgs(&config, argc, argv); + + printf("Server configuration:\n"); + printf(" Host: %s\n", config.host); + printf(" Port: %d\n", config.port); + printf(" Debug: %s\n", config.debug ? "ON" : "OFF"); + + return 0; +} +``` + +--- + +## 23.13 Wildcard Arguments + +Handle wildcards expanded by shell: + +```c +#include <stdio.h> + +int main(int argc, char *argv[]) { + if (argc < 2) { + printf("Usage: %s <files...>\n", argv[0]); + return 1; + } + + printf("Processing %d files:\n", argc - 1); + for (int i = 1; i < argc; i++) { + printf(" - %s\n", argv[i]); + } + + return 0; +} +``` + +**Running:** +```bash +$ ./program *.txt +Processing 3 files: + - file1.txt + - file2.txt + - file3.txt +``` + +--- + +## 23.14 Interactive vs Batch Mode + +```c +#include <stdio.h> +#include <string.h> + +int interactiveMode(void) { + char input[100]; + + while (1) { + printf("> "); + if (fgets(input, sizeof(input), stdin) == NULL) { + break; + } + + // Remove newline + input[strcspn(input, "\n")] = 0; + + if (strcmp(input, "quit") == 0) { + break; + } + + printf("You entered: %s\n", input); + } + + return 0; +} + +int batchMode(const char *filename) { + FILE *file = fopen(filename, "r"); + if (file == NULL) { + printf("Error: Cannot open %s\n", filename); + return 1; + } + + char line[100]; + while (fgets(line, sizeof(line), file)) { + // Process line + printf("Processing: %s", line); + } + + fclose(file); + return 0; +} + +int main(int argc, char *argv[]) { + if (argc == 1) { + // No arguments: interactive mode + printf("Interactive mode (type 'quit' to exit)\n"); + return interactiveMode(); + } + else { + // Arguments provided: batch mode + for (int i = 1; i < argc; i++) { + printf("Processing file: %s\n", argv[i]); + batchMode(argv[i]); + } + return 0; + } +} +``` + +--- + +## 23.15 Clay Application Example + +Complete Clay application with arguments: + +```c +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +// #define CLAY_IMPLEMENTATION +// #include "clay.h" + +typedef struct { + int width; + int height; + int fps; + char *layout_file; + int benchmark; +} ClayAppConfig; + +void printHelp(const char *program) { + printf("Usage: %s [options] [layout_file]\n", program); + printf("\nOptions:\n"); + printf(" -w, --width <N> Window width (default: 1024)\n"); + printf(" -h, --height <N> Window height (default: 768)\n"); + printf(" --fps <N> Target FPS (default: 60)\n"); + printf(" --benchmark Run in benchmark mode\n"); + printf(" --help Show this help\n"); + printf("\nExamples:\n"); + printf(" %s --width 1920 --height 1080 layout.clay\n", program); + printf(" %s --benchmark\n", program); +} + +int parseArguments(int argc, char *argv[], ClayAppConfig *config) { + // Defaults + config->width = 1024; + config->height = 768; + config->fps = 60; + config->layout_file = NULL; + config->benchmark = 0; + + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "-w") == 0 || strcmp(argv[i], "--width") == 0) { + if (++i >= argc) return 0; + config->width = atoi(argv[i]); + } + else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--height") == 0) { + if (++i >= argc) return 0; + config->height = atoi(argv[i]); + } + else if (strcmp(argv[i], "--fps") == 0) { + if (++i >= argc) return 0; + config->fps = atoi(argv[i]); + } + else if (strcmp(argv[i], "--benchmark") == 0) { + config->benchmark = 1; + } + else if (strcmp(argv[i], "--help") == 0) { + return 0; + } + else if (argv[i][0] != '-') { + config->layout_file = argv[i]; + } + else { + printf("Unknown option: %s\n", argv[i]); + return 0; + } + } + + return 1; +} + +int main(int argc, char *argv[]) { + ClayAppConfig config; + + if (!parseArguments(argc, argv, &config)) { + printHelp(argv[0]); + return 1; + } + + printf("Clay Application Starting:\n"); + printf(" Resolution: %dx%d\n", config.width, config.height); + printf(" Target FPS: %d\n", config.fps); + printf(" Benchmark: %s\n", config.benchmark ? "Yes" : "No"); + if (config.layout_file) { + printf(" Layout File: %s\n", config.layout_file); + } + + // Initialize Clay + // Clay_Dimensions windowSize = {config.width, config.height}; + // Clay_Initialize(...); + + // Main loop... + + return 0; +} +``` + +--- + +## 23.16 Key Concepts Learned +- ✅ argc and argv basics +- ✅ Processing command-line arguments +- ✅ Parsing numeric arguments +- ✅ Command-line flags +- ✅ Flags with values +- ✅ getopt for option parsing +- ✅ Subcommands +- ✅ Environment variables +- ✅ Argument validation +- ✅ Configuration priority +- ✅ Interactive vs batch mode +- ✅ Clay application with arguments + +--- + +## Practice Exercises + +1. Build a calculator that accepts expressions as arguments +2. Create a file search utility with filtering options +3. Implement a CSV processor with column selection +4. Build a simple HTTP server with configurable port +5. Create a code formatter with style options +6. Implement a task manager CLI (add, list, complete) +7. Build an image converter with format options +8. Create a benchmarking tool with various options diff --git a/docs/README_C_TUTORIALS.md b/docs/README_C_TUTORIALS.md new file mode 100644 index 0000000..5687444 --- /dev/null +++ b/docs/README_C_TUTORIALS.md @@ -0,0 +1,455 @@ +# Complete C Programming Guide Using Clay Library + +## Master C Programming Step-by-Step with Real-World Examples + +This comprehensive guide teaches you C programming from basics to advanced concepts, using the professional Clay UI layout library as a real-world reference throughout. + +--- + +## 📚 What You'll Learn + +- ✅ **All C fundamentals** - Variables, operators, control flow, loops +- ✅ **Memory management** - Pointers, arrays, dynamic allocation +- ✅ **Advanced concepts** - Macros, bit manipulation, recursion +- ✅ **Real-world patterns** - As demonstrated by Clay library +- ✅ **Professional practices** - Code organization, error handling +- ✅ **Practical applications** - File I/O, command-line tools + +--- + +## 📖 Complete Tutorial Index + +### Part 1: Fundamentals (Main Guide) +**File: `LEARNING_C_WITH_CLAY.md`** + +1. **Chapter 1: C Basics** - Your first program, includes, comments +2. **Chapter 2: Variables and Data Types** - int, float, char, fixed-width types +3. **Chapter 3: Operators** - Arithmetic, logical, bitwise, ternary +4. **Chapter 4: Control Flow** - if/else, switch, goto +5. **Chapter 5: Loops** - while, for, do-while, break, continue +6. **Chapter 6: Functions** - Declaration, definition, parameters, recursion +7. **Chapter 7: Pointers** - Memory addresses, dereferencing, pointer arithmetic +8. **Chapter 8: Structs and Typedef** - Grouping data, nested structs, designated initializers +9. **Chapter 9: Arrays** - Static arrays, multidimensional, relationship with pointers +10. **Chapter 10: Strings** - C strings, Clay's string implementation +11. **Chapter 11: Type Casting** - Implicit/explicit conversion, const, volatile +12. **Chapter 12: Storage Classes** - auto, static, extern, scope, lifetime +13. **Chapter 13: Recursion** - Base cases, tail recursion, tree traversal + +### Part 2: Advanced Topics (Separate Files) + +#### **Chapter 14: Bit Manipulation** 📄 +**File: `docs/14_bit_manipulation.md`** +- Bitwise operators (&, |, ^, ~, <<, >>) +- Bit flags and masks +- Set/clear/toggle/check bits +- Counting set bits +- Power of 2 operations +- Practical applications in Clay +- Performance optimizations + +#### **Chapter 15: Preprocessor and Macros** +**File: `LEARNING_C_WITH_CLAY.md`** (Chapter 15) +- #define and #include +- Conditional compilation (#ifdef, #ifndef) +- Header guards +- Function-like macros +- Stringification and token pasting +- Predefined macros + +#### **Chapter 16: Advanced Macros** +**File: `LEARNING_C_WITH_CLAY.md`** (Chapter 16) +- Variadic macros +- X-Macros pattern +- _Generic for type selection +- Compound literals +- For-loop macro trick (Clay's CLAY() macro) +- Macro debugging + +#### **Chapter 17: Memory Management** +**File: `LEARNING_C_WITH_CLAY.md`** (Chapter 17) +- Stack vs heap +- malloc, calloc, realloc, free +- Memory errors and debugging +- Arena allocators (Clay's approach) +- Memory pools +- Alignment + +#### **Chapter 18: Header Files** +**File: `LEARNING_C_WITH_CLAY.md`** (Chapter 18) +- Header vs source files +- Header guards and #pragma once +- Single-header library pattern (Clay) +- Forward declarations +- Opaque pointers +- Platform-specific code + +#### **Chapter 19: Enums and Unions** +**File: `LEARNING_C_WITH_CLAY.md`** (Chapter 19) +- Enum basics and typedef +- Bit flags with enums +- Unions for memory efficiency +- Tagged unions +- Anonymous structs/unions + +#### **Chapter 20: Function Pointers** +**File: `LEARNING_C_WITH_CLAY.md`** (Chapter 20) +- Function pointer basics +- Typedef for cleaner syntax +- Callbacks (Clay's measurement callbacks) +- Function pointer arrays +- User data pattern + +#### **Chapter 21: Standard Library Basics** 📄 +**File: `docs/21_standard_library.md`** +- stdio.h - printf, scanf, file operations +- stdlib.h - malloc, atoi, rand, exit +- string.h - strlen, strcpy, strcmp +- math.h - pow, sqrt, trigonometry +- ctype.h - character testing +- time.h - time operations +- Clay's zero-dependency approach + +#### **Chapter 22: File I/O** 📄 +**File: `docs/22_file_io.md`** +- Opening and closing files +- File modes (read, write, append, binary) +- fprintf, fscanf, fgets, fputs +- fread, fwrite for binary data +- File position (ftell, fseek, rewind) +- Error handling +- Configuration files for Clay apps +- Binary file formats + +#### **Chapter 23: Command-Line Arguments** 📄 +**File: `docs/23_command_line_arguments.md`** +- argc and argv basics +- Parsing arguments +- Command-line flags +- getopt for option parsing +- Subcommands (git-style) +- Configuration priority +- Clay application with arguments +- Interactive vs batch mode + +#### **Chapter 24: Building Complete Programs** +**File: `LEARNING_C_WITH_CLAY.md`** (Chapter 24) +- Complete Clay example +- Compiling with gcc/clang +- Makefiles for automation +- Multi-file projects +- Common C patterns +- Best practices + +--- + +## 🎯 Learning Path + +### Beginner (Chapters 1-9) +Start here if you're new to C. Learn the fundamentals: +- Basic syntax and data types +- Control structures and loops +- Functions and pointers +- Structs and arrays + +**Estimated time:** 2-3 weeks + +### Intermediate (Chapters 10-17) +Build on fundamentals with more advanced topics: +- String manipulation +- Type casting and storage classes +- Recursion and bit manipulation +- Preprocessor and macros +- Memory management + +**Estimated time:** 3-4 weeks + +### Advanced (Chapters 18-24) +Master professional C development: +- Project organization +- Advanced data structures +- Function pointers and callbacks +- File I/O and system interaction +- Complete application development + +**Estimated time:** 2-3 weeks + +--- + +## 🚀 Quick Start + +1. **Read the main guide** (`LEARNING_C_WITH_CLAY.md`) from Chapter 1 +2. **Follow along** by writing the code examples +3. **Study Clay's implementation** in `clay.h` for real-world patterns +4. **Complete practice exercises** at the end of each chapter +5. **Refer to specialized topics** in the `docs/` folder as needed + +--- + +## 💡 Why Learn C with Clay? + +### Clay Library Features +- **Single-header**: Entire library in one file +- **Zero dependencies**: No standard library required +- **High performance**: Microsecond layout calculations +- **Professional code**: Production-ready patterns +- **Well-documented**: Clear, readable implementation + +### What Clay Teaches You +- ✅ Arena allocators for memory management +- ✅ Macro DSL design +- ✅ Single-header library pattern +- ✅ API design principles +- ✅ Zero-dependency C programming +- ✅ Performance optimization techniques +- ✅ Portable C code practices + +--- + +## 📁 File Structure + +``` +clay/ +├── LEARNING_C_WITH_CLAY.md # Main tutorial (Chapters 1-13, 15-20, 24) +├── clay.h # The Clay library (reference) +├── docs/ +│ ├── README_C_TUTORIALS.md # This index file +│ ├── 14_bit_manipulation.md # Chapter 14: Bit operations +│ ├── 21_standard_library.md # Chapter 21: stdlib overview +│ ├── 22_file_io.md # Chapter 22: File operations +│ └── 23_command_line_arguments.md # Chapter 23: argc/argv +└── examples/ # Clay examples to study +``` + +--- + +## 🔧 Prerequisites + +- A C compiler (gcc, clang, or MSVC) +- Text editor or IDE +- Basic command-line knowledge +- Curiosity and patience! + +### Setting Up + +**Linux/Mac:** +```bash +gcc --version # Check compiler +``` + +**Windows:** +- Install MinGW or Visual Studio +- Or use WSL (Windows Subsystem for Linux) + +--- + +## 📝 How to Use This Guide + +### Reading the Main Tutorial + +```bash +# View in terminal +less LEARNING_C_WITH_CLAY.md + +# Or open in your favorite markdown viewer +``` + +### Compiling Examples + +```c +// example.c +#include <stdio.h> + +int main(void) { + printf("Hello, C!\n"); + return 0; +} +``` + +```bash +# Compile +gcc -o example example.c + +# Run +./example +``` + +### Studying Clay + +```c +// your_program.c +#define CLAY_IMPLEMENTATION +#include "clay.h" + +int main(void) { + // Your Clay UI code here + return 0; +} +``` + +--- + +## 🎓 Practice Exercises + +Each chapter includes practice exercises. Try them all! + +**Example exercises:** +- Chapter 5: Build a number guessing game +- Chapter 7: Implement your own string functions +- Chapter 14: Create a permission system with bit flags +- Chapter 22: Build a CSV parser +- Chapter 24: Create a complete Clay application + +--- + +## 📚 Additional Resources + +### Clay Resources +- **Clay Website**: https://nicbarker.com/clay +- **Clay GitHub**: https://github.com/nicbarker/clay +- **Examples**: See `clay/examples/` directory + +### C Programming Resources +- **C Reference**: https://en.cppreference.com/w/c +- **Book**: "The C Programming Language" by K&R +- **Book**: "Modern C" by Jens Gustedt +- **Online**: C tutorials on YouTube, freeCodeCamp + +### Tools +- **Compiler Explorer**: https://godbolt.org +- **Valgrind**: Memory leak detection +- **GDB**: Debugging +- **Clang-format**: Code formatting + +--- + +## 🤝 Contributing + +Found an error? Have a suggestion? Contributions welcome! + +--- + +## ⭐ Features of This Guide + +- ✅ **Progressive learning** - Start simple, build complexity +- ✅ **Real-world examples** - Every concept shown in Clay +- ✅ **Complete coverage** - All C topics from basics to advanced +- ✅ **Practical focus** - Build real programs, not just theory +- ✅ **Professional patterns** - Learn industry best practices +- ✅ **Zero to hero** - From "Hello World" to complex applications + +--- + +## 🎯 Learning Goals + +After completing this guide, you will be able to: + +1. ✅ Write efficient, well-structured C programs +2. ✅ Understand memory management and pointers +3. ✅ Use advanced C features (macros, unions, bit manipulation) +4. ✅ Organize multi-file C projects +5. ✅ Read and understand professional C code (like Clay) +6. ✅ Debug and optimize C programs +7. ✅ Build complete applications with file I/O and CLI +8. ✅ Apply C knowledge to systems programming + +--- + +## 📖 Chapter Dependencies + +``` +Chapter 1-2 (Basics) + ↓ +Chapter 3-5 (Control Flow) + ↓ +Chapter 6 (Functions) + ↓ +Chapter 7 (Pointers) ←─────────┐ + ↓ │ +Chapter 8 (Structs) │ + ↓ │ +Chapter 9 (Arrays) ────────────┘ + ↓ +Chapter 10 (Strings) + ↓ +Chapter 11-12 (Advanced Types) + ↓ +Chapter 13 (Recursion) + + ├─→ Chapter 14 (Bit Manipulation) + ├─→ Chapter 15-16 (Macros) + ├─→ Chapter 17 (Memory) + ├─→ Chapter 18 (Organization) + ├─→ Chapter 19 (Enums/Unions) + ├─→ Chapter 20 (Function Pointers) + ├─→ Chapter 21 (Standard Library) + ├─→ Chapter 22 (File I/O) + └─→ Chapter 23 (Command Line) + ↓ + Chapter 24 (Complete Programs) +``` + +--- + +## 🏆 Completion Checklist + +Track your progress: + +- [ ] Chapter 1-5: Fundamentals +- [ ] Chapter 6-9: Functions, Pointers, Structs, Arrays +- [ ] Chapter 10-13: Strings, Casting, Storage, Recursion +- [ ] Chapter 14: Bit Manipulation +- [ ] Chapter 15-16: Preprocessor and Macros +- [ ] Chapter 17: Memory Management +- [ ] Chapter 18: Project Organization +- [ ] Chapter 19: Enums and Unions +- [ ] Chapter 20: Function Pointers +- [ ] Chapter 21: Standard Library +- [ ] Chapter 22: File I/O +- [ ] Chapter 23: Command-Line Arguments +- [ ] Chapter 24: Building Complete Programs +- [ ] Built a complete Clay application +- [ ] Read and understood clay.h + +--- + +## 💬 Tips for Success + +1. **Type every example** - Don't just read, code! +2. **Experiment** - Modify examples to see what happens +3. **Read clay.h** - Study professional code +4. **Complete exercises** - Practice makes perfect +5. **Debug your errors** - Learn from mistakes +6. **Build projects** - Apply what you learn +7. **Ask questions** - Join C programming communities +8. **Be patient** - C takes time to master + +--- + +## 🚀 Next Steps After This Guide + +1. **Build projects** - Create your own applications +2. **Study data structures** - Implement lists, trees, hash tables +3. **Learn algorithms** - Sorting, searching, graph algorithms +4. **Explore systems programming** - OS concepts, networking +5. **Contribute to open source** - Read and improve real projects +6. **Specialize** - Embedded systems, game dev, or systems programming + +--- + +## 📜 License + +This educational content is provided for learning purposes. +Clay library: MIT License - see Clay repository for details. + +--- + +## 🎉 Happy Coding! + +Welcome to the world of C programming! With dedication and practice, you'll master one of the most powerful and influential programming languages ever created. + +**Remember:** Every expert was once a beginner. Start with Chapter 1 and work your way through. You've got this! 🚀 + +--- + +*"C is quirky, flawed, and an enormous success." - Dennis Ritchie*