Files
exc/c/gai/g4_l_ass.md
2026-06-30 07:01:23 +02:00

123 lines
4.7 KiB
Markdown

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.
```c
#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.