Project 2 is gonna involve linked lists, so this lab is a way for you to refresh yourself. Please make sure you understand this stuff thoroughly.
Crash course on malloc and free
Well learn about the heap in detail on Wednesday/Thursday. But you can get started on the lab now. Right? 🙂
malloc is like Cs new. It allocates space on the heap, and gives you a pointer to that space.
But C has no garbage collection, so every piece of memory you malloc, you must ultimately free.
Using malloc is straightforward: you tell it how many bytes you need, and it returns a pointer to a brand new piece of memory that is at least that big:
// one int is sizeof(int).// multiply that by 10, and you have room for an array of 10 ints.int* array = malloc(sizeof(int) * 10);
When youre done with a piece of memory, just pass the pointer to free:
free(array);
The lab
Here is the Node struct that you will be using:
typedef struct Node { int value; struct Node* next;} Node;
Here are the functions you will implement:
- Node* create_node(int value)
- it will malloc a Node, set its value to value, set its next to NULL, and return it.
- to malloc an instance Node, you need to allocate sizeof(Node) bytes.
- you can directly assign the result of malloc into a Node* variable.
- it will malloc a Node, set its value to value, set its next to NULL, and return it.
- void list_print(Node* head)
- head points to the head of a linked list.
- it will print the values of all the items in the list in this format: 5 -> 8 -> 2 -> 1
- Node* list_append(Node* head, int value)
- head points to the head of a linked list.
- it will go to the end of the linked list, use create_node(value), and put that new node at the end of the linked list.
- then it will return that new node.
- Node* list_prepend(Node* head, int value)
- head points to the head of a linked list.
- it will use create_node(value), make that node point to head, and return that new node.
- important: this function should return the new head of the list, not the old one.
- void list_free(Node* head)
- head points to the head of a linked list, or NULL.
- if head is NULL, do nothing.
- otherwise, free all the nodes in the list.
- do not free a node before you get its next field.
- Node* list_remove(Node* head, int value)
- head points to the head of a linked list.
- it will search for a node whose value == value.
- if it finds that node, it will remove it from the list and free it.
- there are special cases for removing the head and tail!
- if it doesnt find that node, nothing happens.
- if it finds that node, it will remove it from the list and free it.
- it will return the head of the list (which may have changed or become NULL!)
Hints:
Read these. Its not cheating, its important information.
- Dont write everything at once and then test it. Write one function, test that, and repeat.
- for loops fit together with linked lists very nicely.
- Write list_print as soon as you can, so you can test your code easier.
- Dont worry about head == NULL for anything other than list_free.
- For list_remove, when you are iterating over the list, dont move your pointer too far ahead
- (You have to know the previous node to remove a node.)
main
Heres a small driver I wrote. (You can put all your code in one lab3.c file.) Feel free to comment stuff out, add more stuff etc. to test your code more thoroughly.
int main() { // The comments at the ends of the lines show what list_print should output. Node* head = create_node(1); list_print(head); // 1 Node* end = list_append(head, 2); list_print(head); // 1 -> 2 end->next = create_node(3); list_print(head); // 1 -> 2 -> 3 head = list_prepend(head, 0); list_print(head); // 0 -> 1 -> 2 -> 3 list_append(head, 4); list_print(head); // 0 -> 1 -> 2 -> 3 -> 4 list_append(head, 5); list_print(head); // 0 -> 1 -> 2 -> 3 -> 4 -> 5 head = list_remove(head, 5); list_print(head); // 0 -> 1 -> 2 -> 3 -> 4 head = list_remove(head, 3); list_print(head); // 0 -> 1 -> 2 -> 4 head = list_remove(head, 0); list_print(head); // 1 -> 2 -> 4 list_free(head); return 0;}
valgrind
valgrind is a helpful tool. It can analyze your programs memory accesses, heap allocations, frees etc. at runtime to make sure youre not doing anything weird. It can help you find memory leaks, array-out-of-bounds errors, buffer overflows, double-frees, using freed heap memory etc
To use it, you just put valgrind before the program you want to run:
valgrind ./lab3
It will print lines that look like ==12345== that will point out issues with your program as it runs.
Common issues:
- Invalid read/write of size n
- you are trying to access an invalid pointer.
- keep reading: it will tell you where the read/write happens. Like, the file and line!
- LEAK SUMMARY
- you have a memory leak.
- basically, the problem is in list_free.
- it says Rerun with leak-check=full to see details of leaked memory but if you do that, it just shows where the memory was allocated, which isnt too useful for you.
- Invalid free() / delete / delete[] / realloc()
- you are trying to call free() on something that you arent allowed to.
- like something that you already freed.
- or a pointer that doesnt point to the heap.
- keep reading the error!!!

![[Solved] CS0449 Lab 3-linked lists and the heap](https://assignmentchef.com/wp-content/uploads/2022/08/downloadzip.jpg)

![[Solved] CS0449 Lab 8- Basic multithreading](https://assignmentchef.com/wp-content/uploads/2022/08/downloadzip-1200x1200.jpg)
Reviews
There are no reviews yet.