Structured Bottom Up - kevshouse/exam_quest GitHub Wiki

Continuing our structured revision plan, let's build upon the helper functions and implement the remaining assignments. I'll provide strategies and code templates that reuse helpers where possible, avoiding malloc and adhering to allowed functions.

Additional Helper Functions Implement these to support more complex assignments:

ft_putnbr (Number Printing)

Purpose: Output integers for fizzbuzz without printf

Allowed: write

Strategy:

void ft_putnbr(int n) {
    if (n >= 10) ft_putnbr(n / 10);
    char digit = '0' + (n % 10);
    write(1, &digit, 1);
}

char_to_upper/lower (Case Conversion)

Purpose: Simplify ulstr logic

Strategy:

char char_to_upper(char c) {
    return ('a' <= c && c <= 'z') ? c - 32 : c;
}
char char_to_lower(char c) {
    return ('A' <= c && c <= 'Z') ? c + 32 : c;
}

Step 5: Remaining Assignments

  1. search_and_replace Helpers: Direct character replacement

Logic:

int main(int ac, char **av) {
    if (ac != 4 || av[2][1] || av[3][1]) { // Verify single-char args
        write(1, "\n", 1); return 0;
    }
    char find = av[2][0];
    char replace = av[3][0];
    for (int i = 0; av[1][i]; i++) {
        char c = (av[1][i] == find) ? replace : av[1][i];
        write(1, &c, 1);
    }
    write(1, "\n", 1);
}
  1. rot_13 (ROT13 Cipher) Helpers: char_rot13 from earlier

Logic:

int main(int ac, char **av) {
    if (ac != 2) { write(1, "\n", 1); return 0; }
    for (int i = 0; av[1][i]; i++) {
        char c = char_rot13(av[1][i]);
        write(1, &c, 1);
    }
    write(1, "\n", 1);
}
  1. ulstr (Case Reversal) Helpers: char_to_upper, char_to_lower

Optimization: Single pass with ternary logic

Logic:

int main(int ac, char **av) {
    if (ac != 2) { write(1, "\n", 1); return 0; }
    for (int i = 0; av[1][i]; i++) {
        char c = av[1][i];
        if ('a' <= c && c <= 'z') c = char_to_upper(c);
        else if ('A' <= c && c <= 'Z') c = char_to_lower(c);
        write(1, &c, 1);
    }
    write(1, "\n", 1);
}

Step 6: Edge Case Testing Plan Test each assignment with these scenarios:

Assignment Test Cases first_word "", " ", " single ", "\tmultiple\twords", "!@#" fizzbuzz Numbers 1, 3, 5, 15, 100; Verify "fizz", "buzz", "fizzbuzz" transitions repeat_alpha "", "a", "A", "ab!", "z", "Hello!" rev_print "", "a", "abc", " space ", "😊" (multi-byte chars) rotone/rot_13 "", "z", "Z", "a b", "Hello123!" search_replace "./prog" (no args), "./prog str" (2 args), "./prog str x y" (4 args) ulstr "", "aBc", "!@#", "MixED" Step 7: Optimization Strategies Loop Fusion: Combine operations in single passes Example: In ulstr, convert case while writing instead of separate steps

// Instead of:
//   convert_case(buffer); then write(buffer);
// Do:
for (i=0; str[i]; i++) {
    c = convert_and_output(str[i]); // Immediate write
}

Branch Reduction: Minimize conditionals in hot paths For fizzbuzz:

for (int i = 1; i <= 100; i++) {
    int m3 = (i % 3 == 0);
    int m5 = (i % 5 == 0);
    if (m3 && m5) ft_putstr("fizzbuzz");
    else if (m3) ft_putstr("fizz");
    else if (m5) ft_putstr("buzz");
    else ft_putnbr(i);
    write(1, "\n", 1);
}
Stack Allocation Only: Never use heap memory
// GOOD: char buffer[100]; (if bounded)
// BAD: malloc(sizeof(char) * (len + 1));
Pointer Arithmetic: Faster than indexing
// In rev_print:
char *end = str;
while (*end) end++;  // Find string end
while (end-- > str) write(1, end, 1); // Reverse output

Step 8: Revision Workflow Daily Practice:

Morning: Reimplement 2 core helpers from memory

Afternoon: Build 1 complex assignment using helpers

Evening: Test edge cases and compare with exam examples

Progression Path:

Diagram

graph TD
  A[Core Helpers] --> B[ft_putstr/ft_strlen]
  A --> C[ft_swap/ft_strcpy]
  A --> D[char_rotone/rot13]
  B --> E[first_word/rev_print]
  C --> F[search_replace]
  D --> G[rotone/rot_13]
  E --> H[repeat_alpha/ulstr]
  D --> I[fizzbuzz]

Speed Drills:

  • Time yourself implementing:

  • Basic helpers: ≤ 5 minutes each

  • Simple assignments: ≤ 15 minutes

  • Complex assignments: ≤ 25 minutes

  • Gradually reduce time targets by 20% each week

Key Insights

  • Pattern Recognition: Most string problems follow similar patterns:

  • Skip delimiters → Process token → Handle edges

  • Transform character → Output result

  • Validate input → Process data → Format output

  • Avoid Over-Engineering:

  • For Level 0, direct solutions are better than abstracted ones

  • Example: first_word doesn't need strtok-style tokenization

42 Exam Constraints:

  • Zero heap allocation

  • Minimal external dependencies

  • Strict output formatting

  • No error messages beyond newlines

This approach builds muscle memory for fundamental operations while teaching you to compose solutions from reliable components. The helper functions become your "standard library" for exam problems.