From c737f8ab0f7c6247269b1685d951ea543a577a05 Mon Sep 17 00:00:00 2001 From: my name Date: Sat, 30 May 2026 17:57:52 +0200 Subject: [PATCH] struct practice --- qscr/c/gai/fixedynarr.c | 40 +++++++++++++ qscr/c/gai/g4_l_ass.md | 122 ++++++++++++++++++++++++++++++++++++++++ qscr/c/stringsort.c | 10 +++- 3 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 qscr/c/gai/fixedynarr.c create mode 100644 qscr/c/gai/g4_l_ass.md diff --git a/qscr/c/gai/fixedynarr.c b/qscr/c/gai/fixedynarr.c new file mode 100644 index 0000000..ea4387d --- /dev/null +++ b/qscr/c/gai/fixedynarr.c @@ -0,0 +1,40 @@ + +#include +#include +#include +#include +struct IntArray{ + int *data; + size_t length; +}; + +void readintarray(struct IntArray *input) { + printf("inputlength:%zu\n", input->length); + for (int i = 0; i < input->length; i++) { + printf("digit:%d = %d\n", i, input->data[i]); + } +} + +int main() { + srand(time(NULL)); + printf("how many numbers?\n"); + int length; + scanf("%d", &length); + + struct IntArray *myintarray = malloc(sizeof(struct IntArray)); /* allocate memory for struct */ + int *myarray = malloc(sizeof(int) * length); /* allocate memory for array that the struct points to */ + + myintarray->data = myarray; /* make sure the pointer in the struct points to the array */ + myintarray->length = length; //forgot to actually assign a value to the struct + for (int i = 0; i < length; i++) { + myintarray->data[i] = rand() % 10; + printf("number:%d = %d\n",i,myintarray->data[i]); + } + + readintarray(myintarray); + + free(myintarray->data); + free(myintarray); + + return 0; +} diff --git a/qscr/c/gai/g4_l_ass.md b/qscr/c/gai/g4_l_ass.md new file mode 100644 index 0000000..6a89993 --- /dev/null +++ b/qscr/c/gai/g4_l_ass.md @@ -0,0 +1,122 @@ +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 +#include +#include + +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. diff --git a/qscr/c/stringsort.c b/qscr/c/stringsort.c index 7ca0d43..d2957e7 100644 --- a/qscr/c/stringsort.c +++ b/qscr/c/stringsort.c @@ -22,7 +22,10 @@ okay dit werkt nu omzetten naar strings /* return 1 if word1 < word 2*/ int compareword(char word1[], char word2[]) { for (int i = 0; i < WORDLENGTH; i++) { - if (word1[i] < word2[i]) { + if (word1[i] == word2[i]) { + //it should continue + } + else if (word1[i] < word2[i]) { printf("%s is larger than %s\n", word1, word2); return 1; } @@ -33,7 +36,6 @@ int compareword(char word1[], char word2[]) { return 0; } - /* eerst gewone bubblesort weer doen */ int mybubblesort(char inputarr[WORDS][WORDLENGTH]) { for (int i = 0; i < WORDS - 1; i++) { // voor elk woord @@ -60,9 +62,11 @@ int mybubblesort(char inputarr[WORDS][WORDLENGTH]) { int main() { - char mytest[16][64] = {"pear", "watermelon", "apple", "banana", "cantaloupe", "Elephant", "Zebra"}; + char mytest[16][64] = {"pear", "watermelon", "aap", "apple", "banana", "cantaloupe", "Elephant", "Zebra"}; srand(time(NULL)); mybubblesort(mytest); return 0; } + +