struct practice
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
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;
|
||||
}
|
||||
@@ -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 <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.
|
||||
Reference in New Issue
Block a user