Files
exc/qscr/c/gai/g4_l_ass.md
T
2026-05-30 17:57:52 +02:00

4.7 KiB

Since you are currently navigating the transition from "fixed-size" allocation (calculating everything upfront) to "dynamic" allocation (growing as you go), the best way to learn is to build in stages.

The reason you didn't need a count or capacity in your Darray is that you did Pre-Calculation: you figured out exactly how many digits were in the number before you called malloc.

But for user input, you can't pre-calculate. You need Dynamic Growth.

Here is a learning path split into 4 sub-assignments.


Assignment 1: The "Fixed" Dynamic Array

Goal: Master the basic Struct \rightarrow Pointer relationship. Task: Create a program that asks the user "How many numbers do you want to enter?".

  1. Create a struct IntArray with int *data and size_t length.
  2. malloc the struct.
  3. malloc the data array based on the user's number.
  4. Fill it, print it, and free it. Key Lesson: Understanding that the struct is the "handle" and the pointer is the "payload."

Assignment 2: The "Growing" Dynamic Array

Goal: Understand capacity vs length and realloc. Task: Modify Assignment 1, but don't ask the user for the size upfront.

  1. Add size_t capacity to your struct.
  2. Start capacity at 2.
  3. Use a while loop to take input until the user types -1.
  4. Inside the loop: If length == capacity, use realloc to double the capacity. Key Lesson: length is how many items are actually there; capacity is how many items can fit before you need more memory.

Assignment 3: The "Pointer to Pointers" (The String Array)

Goal: Understand "Deep Allocation" (Double Indirection). Task: Change your IntArray to a StringArray.

  1. Your struct now has char **words.
  2. When you realloc the words array, you are only making room for more addresses (pointers).
  3. For every string the user enters, you must malloc a new piece of memory for that specific string and strcpy the input into it. Key Lesson: A char** is just an array of pointers. The array itself is one allocation, but every string it points to is a separate allocation.

Assignment 4: The "Deep Free"

Goal: Prevent memory leaks in complex structures. Task: Write a dedicated free_string_array(StringArray *sa) function.

  1. It must loop through the array and free() every individual string first.
  2. Then it must free() the words pointer array.
  3. Finally, it must free() the struct itself. Key Lesson: You must free memory in the exact reverse order that you allocated it.

The "Scaffold" (Start here for Assignment 3/4)

If you want to jump straight to the strings, here is a clean scaffold. I have left "TODOs" where the logic should go.

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

typedef struct {
    char **words;
    size_t length;
    size_t capacity;
} StringArray;

// Initialize the "Manager" struct
StringArray* create_sa() {
    StringArray *sa = malloc(sizeof(StringArray));
    sa->length = 0;
    sa->capacity = 4; // Start small to force realloc to happen
    sa->words = malloc(sizeof(char*) * sa->capacity);
    return sa;
}

void add_word(StringArray *sa, const char *input) {
    // TODO 1: Check if length == capacity. 
    // If so, use realloc to double the capacity of sa->words.

    // TODO 2: Allocate memory for the new string.
    // Hint: strlen(input) + 1
    
    // TODO 3: Copy the input into the newly allocated memory.
    
    // TODO 4: Store that pointer in sa->words[sa->length] and increment length.
}

void free_sa(StringArray *sa) {
    // TODO 5: Loop through sa->words and free each individual string.
    
    // TODO 6: Free the sa->words array itself.
    
    // TODO 7: Free the sa struct.
}

int main() {
    StringArray *myList = create_sa();
    char temp[100];

    printf("Enter words (type 'exit' to stop):\n");
    while (scanf("%99s", temp) == 1 && strcmp(temp, "exit") != 0) {
        add_word(myList, temp);
    }

    printf("\nStored words:\n");
    for (size_t i = 0; i < myList->length; i++) {
        printf("%zu: %s\n", i, myList->words[i]);
    }

    free_sa(myList);
    return 0;
}

Final tip on your Darray logic:

In your Darray code, you did: DigDarr->digits = (int *)(DigDarr + 1);

This is very "clever" code, but in professional C, it is often avoided unless you are writing a high-performance kernel or library. It makes the code harder to read and makes realloc almost impossible (because the data is physically glued to the struct).

The standard way is to have the struct hold a pointer to a separate block of memory. It's slightly slower (one extra pointer jump), but it's much safer and more flexible.