Add more exercises

This commit is contained in:
Riyyi
2025-09-01 12:35:21 +02:00
parent 7e909b73fb
commit 4e6cd60609
25 changed files with 1006 additions and 3 deletions
+207
View File
@@ -0,0 +1,207 @@
#+TITLE: Learn Memory Management in C
#+AUTHOR: Riyyi
#+LANGUAGE: en
#+OPTIONS: toc:nil
Completed course from
[[https://www.boot.dev/courses/learn-memory-management-c][boot.dev]].
The exercises from the course have been worked out in this repo.
This is my way of having the "certificate" for free.
If you're reading this with the intention of completing the exercises yourself,
just remove the directories from the =src= directory and recreate the directory
with the files from the exercise. Alternatively, just remove the file the
exercise is asking you to modify as you go.
Note:
- In chapter 6 exercise 6, macOS malloc will almost never return a NULL pointer
due to virtual memory overcommit, so you should check for
=size \=\= 1024 * 1024 * 100)= instead of =array \=\= NULL=
- In chapter 8, I renamed =stack_t= to =my_stack_t= due to =std= naming conflict
on macOS
** Build instructions
Compiling and running all the tests can be done with the following commands:
#+BEGIN_SRC sh
$ mkdir build
$ cd build
$ cmake ..
$ make run
#+END_SRC
** Output
The first the 3 chapters of the course can be done interactively on the website.
[[./bootdev-c.png]]
Successful output of all the tests:
#+BEGIN_SRC sh
$ make run 12:25PM
[ 3%] Built target munit
[ 8%] Built target 8-6-multiple-types
[ 11%] Built target 4-1-enums
[ 14%] Built target 4-2-non-default-values
[ 17%] Built target 4-3-switch-case
[ 20%] Built target 4-4-sizeof-enum
[ 24%] Built target 5-1-union
[ 26%] Built target 5-2-memory-layout
[ 29%] Built target 5-3-5-4-union-size
[ 32%] Built target 5-5-helper-fields
[ 34%] Built target 6-1-the-stack
[ 37%] Built target 6-2-why-a-stack
[ 39%] Built target 6-3-stack-overflow
[ 42%] Built target 6-4-pointers-to-the-stack
[ 46%] Built target 6-5-the-heap
[ 50%] Built target 6-6-malloc
[ 53%] Built target 6-7-free
[ 56%] Built target 6-8-big-endian-little-endian
[ 60%] Built target 7-1-pointer-pointers
[ 64%] Built target 7-2-array-of-pointers
[ 67%] Built target 7-3-void-pointers
[ 71%] Built target 7-4-swapping-integers
[ 75%] Built target 7-5-swapping-strings
[ 79%] Built target 7-6-generic-swap
[ 83%] Built target 8-1-low-level-stack
[ 87%] Built target 8-2-stack-push
[ 91%] Built target 8-3-stack-pop
[ 94%] Built target 8-4-stack-free
[100%] Built target 8-5-dangerous-push
Running test suite with seed 0x039ca6b1...
colors/are_defined [ OK ] [ 0.00000100 / 0.00000200 CPU ]
colors/are_defined_correctly [ OK ] [ 0.00000100 / 0.00000100 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xbf68f4fa...
colors/defined [ OK ] [ 0.00000100 / 0.00000100 CPU ]
colors/defined_vscode [ OK ] [ 0.00000100 / 0.00000000 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x40b17fef...
http/switch_enum [ OK ] [ 0.00000100 / 0.00000200 CPU ]
http/switch_enum_default [ OK ] [ 0.00000100 / 0.00000000 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped.
The size of BigNumbers is 8 bytes
The size of HttpErrorCode is 4 bytes
Running test suite with seed 0xde548fa9...
format/integer [ OK ] [ 0.00000200 / 0.00000200 CPU ]
format/string [ OK ] [ 0.00000100 / 0.00000100 CPU ]
format/integer_nvim [ OK ] [ 0.00000100 / 0.00000200 CPU ]
format/string_nvim [ OK ] [ 0.00000200 / 0.00000200 CPU ]
4 of 4 (100%) tests successful, 0 (0%) test skipped.
value (set): -420
err (unset): 4294966876
value (unset): -1
err (set): 4294967295
Running test suite with seed 0xa7197940...
PacketHeader/test_packet_header_size [ OK ] [ 0.00000100 / 0.00000200 CPU ]
PacketHeader/test_tcp_header_fields [ OK ] [ 0.00000100 / 0.00000100 CPU ]
PacketHeader/test_field_raw_size [ OK ] [ 0.00000000 / 0.00000100 CPU ]
PacketHeader/test_field_to_raw_consistency[ OK ] [ 0.00000100 / 0.00000100 CPU ]
4 of 4 (100%) tests successful, 0 (0%) test skipped.
--------------------------------- Stack pointer offset: 0 bytes
---------------------------------
Dark mode?
---------------------------------
Stack pointer offset: 0 bytes
---------------------------------
More like...
---------------------------------
Stack pointer offset: 0 bytes
---------------------------------
dark roast.
Running test suite with seed 0x7dcfad3b...
/example/compare [ OK ] [ 0.00000100 / 0.00000000 CPU ]
/example/rand [ OK ] [ 0.00000100 / 0.00000000 CPU ]
/example/parameters
foo=one, bar=red [ OK ] [ 0.00000200 / 0.00000200 CPU ]
foo=one, bar=green [ OK ] [ 0.00000200 / 0.00000300 CPU ]
foo=one, bar=blue [ OK ] [ 0.00000200 / 0.00000200 CPU ]
foo=two, bar=red [ OK ] [ 0.00000100 / 0.00000200 CPU ]
foo=two, bar=green [ OK ] [ 0.00000200 / 0.00000200 CPU ] foo=two, bar=blue [ OK ] [ 0.00000200 / 0.00000200 CPU ]
foo=three, bar=red [ OK ] [ 0.00000100 / 0.00000200 CPU ]
foo=three, bar=green [ OK ] [ 0.00000200 / 0.00000100 CPU ]
foo=three, bar=blue [ OK ] [ 0.00000100 / 0.00000200 CPU ]
11 of 11 (100%) tests successful, 0 (0%) test skipped.
Size of pool: 10240
Initial string: snek
c1: 10, 20
c2: 30, 40
c3: 50, 60 Running test suite with seed 0x53c7e720...
get_full_greeting/test_basic_greeting[ OK ] [ 0.00000200 / 0.00000300 CPU ]
get_full_greeting/test_short_buffer [ OK ] [ 0.00000200 / 0.00000200 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xee42ee28...
allocate_scalar_array/test_allocate_scalar_array_size[ OK ] [ 0.00000100 / 0.00000200 CPU ]
allocate_scalar_array/test_allocate_scalar_array_values[ OK ] [ 0.00000200 / 0.00000100 CPU ]
allocate_scalar_array/test_allocate_scalar_array_zero_multiplier[ OK ] [ 0.00000200 / 0.00000100 CPU ]
allocate_scalar_array/test_allocate_too_much[ OK ] [ 0.00001000 / 0.00000900 CPU ]
4 of 4 (100%) tests successful, 0 (0%) test skipped. Allocated 500 lists
Running test suite with seed 0x9d78388e...
/example/compare [ OK ] [ 0.00000100 / 0.00000200 CPU ]
/example/rand [ OK ] [ 0.00000100 / 0.00000200 CPU ]
/example/parameters
foo=one, bar=red [ OK ] [ 0.00000200 / 0.00000200 CPU ]
foo=one, bar=green [ OK ] [ 0.00000100 / 0.00000200 CPU ]
foo=one, bar=blue [ OK ] [ 0.00000200 / 0.00000100 CPU ]
foo=two, bar=red [ OK ] [ 0.00000200 / 0.00000200 CPU ]
foo=two, bar=green [ OK ] [ 0.00000200 / 0.00000000 CPU ] foo=two, bar=blue [ OK ] [ 0.00000200 / 0.00000100 CPU ]
foo=three, bar=red [ OK ] [ 0.00000100 / 0.00000100 CPU ]
foo=three, bar=green [ OK ] [ 0.00000200 / 0.00000200 CPU ]
foo=three, bar=blue [ OK ] [ 0.00000200 / 0.00000200 CPU ]
11 of 11 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x07fdd526...
allocate_list/create [ OK ] [ 0.00000100 / 0.00000000 CPU ]
allocate_list/overwrite [ OK ] [ 0.00000100 / 0.00000100 CPU ] 2 of 2 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xf26a30e1...
create_token_pointer_array/test_create_token_pointer_array_single[ OK ] [ 0.00000200 / 0.00000200 CPU ]
create_token_pointer_array/test_create_token_pointer_array_multiple[ OK ] [ 0.00000300 / 0.00000200 CPU ]
create_token_pointer_array/test_create_token_pointer_array_memory_allocation[ OK ] [ 0.00000200 / 0.00000300 CPU ]
3 of 3 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x4c18af41...
snek_zero_out/test_zero_out_integer [ OK ] [ 0.00000100 / 0.00000100 CPU ]
snek_zero_out/test_zero_out_float [ OK ] [ 0.00000100 / 0.00000200 CPU ]
snek_zero_out/test_zero_out_bool [ OK ] [ 0.00000100 / 0.00000000 CPU ] snek_zero_out/test_zero_out_nonzero_values[ OK ] [ 0.00000100 / 0.00000200 CPU ]
4 of 4 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xb0750720...
void-pointer/swap_ints [ OK ] [ 0.00000100 / 0.00000100 CPU ]
void-pointer/swap_ints_same [ OK ] [ 0.00000100 / 0.00000100 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xc10a0ca0...
void-pointer/swap_str [ OK ] [ 0.00000100 / 0.00000100 CPU ]
void-pointer/test_swap_str_long [ OK ] [ 0.00000100 / 0.00000100 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped. Running test suite with seed 0xa27e09af...
swap/generic_ints [ OK ] [ 0.00000200 / 0.00000200 CPU ]
swap/generic_strings [ OK ] [ 0.00000200 / 0.00000100 CPU ]
swap/generic_struct [ OK ] [ 0.00000200 / 0.00000200 CPU ]
3 of 3 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xd1be93bf...
snekstack/create_stack_small [ OK ] [ 0.00000100 / 0.00000000 CPU ]
snekstack/create_stack_large [ OK ] [ 0.00000100 / 0.00000200 CPU ]
2 of 2 (100%) tests successful, 0 (0%) test skipped. Running test suite with seed 0x92735306...
snekstack/create_stack [ OK ] [ 0.00000200 / 0.00000100 CPU ]
snekstack/push_stack [ OK ] [ 0.00000100 / 0.00000200 CPU ]
snekstack/push_double_capacity [ OK ] [ 0.00000200 / 0.00000200 CPU ]
3 of 3 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xd641eade...
snekstack/create_stack [ OK ] [ 0.00000200 / 0.00000200 CPU ]
snekstack/push_stack [ OK ] [ 0.00000200 / 0.00000200 CPU ]
snekstack/pop_stack [ OK ] [ 0.00000200 / 0.00000100 CPU ]
snekstack/pop_stack_empty [ OK ] [ 0.00000200 / 0.00000100 CPU ]
4 of 4 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0xd1d1136d...
snekstack/create_stack [ OK ] [ 0.00000200 / 0.00000100 CPU ]
snekstack/push_stack [ OK ] [ 0.00000200 / 0.00000200 CPU ]
snekstack/pop_stack [ OK ] [ 0.00000200 / 0.00000200 CPU ]
3 of 3 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x5493a18d...
snekstack/heterogenous_stack [ OK ] [ 0.00000100 / 0.00000200 CPU ]
1 of 1 (100%) tests successful, 0 (0%) test skipped.
Running test suite with seed 0x0dc3c3f9...
snekstack/multiple_types_stack [ OK ] [ 0.00000300 / 0.00000200 CPU ]
1 of 1 (100%) tests successful, 0 (0%) test skipped.
[100%] Built target run
#+END_SRC
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

+39
View File
@@ -0,0 +1,39 @@
// #include "bootlib.h"
#include "munit.h"
#include "snekstack.h"
munit_case(RUN, create_stack_small, {
my_stack_t *s = stack_new(3);
assert_int(s->capacity, ==, 3, "Sets capacity to 3");
assert_int(s->count, ==, 0, "No elements in the stack yet");
assert_ptr_not_null(s->data, "Allocates the stack data");
free(s->data);
free(s);
// assert(boot_all_freed());
});
munit_case(SUBMIT, create_stack_large, {
my_stack_t *s = stack_new(100);
assert_int(s->capacity, ==, 100, "Sets capacity to 100");
assert_int(s->count, ==, 0, "No elements in the stack yet");
assert_ptr_not_null(s->data, "Allocates the stack data");
free(s->data);
free(s);
// assert(boot_all_freed());
});
int main() {
MunitTest tests[] = {
munit_test("/create_stack_small", create_stack_small),
munit_test("/create_stack_large", create_stack_large),
munit_null_test,
};
MunitSuite suite = munit_suite("snekstack", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}
+18
View File
@@ -0,0 +1,18 @@
#include <stdlib.h>
#include "snekstack.h"
my_stack_t *stack_new(size_t capacity)
{
my_stack_t *stack = (my_stack_t *)malloc(sizeof(my_stack_t));
if (stack == NULL) return NULL;
stack->count = 0;
stack->capacity = capacity;
stack->data = malloc(sizeof(void*) * capacity);
if (stack->data == NULL) {
free(stack);
return NULL;
}
return stack;
}
+9
View File
@@ -0,0 +1,9 @@
#include <stddef.h>
typedef struct Stack {
size_t count;
size_t capacity;
void **data;
} my_stack_t; // NOTE: renamed due to std naming conflict on macOS
my_stack_t *stack_new(size_t capacity);
+88
View File
@@ -0,0 +1,88 @@
// #include "bootlib.h"
#include "munit.h"
#include "snekstack.h"
munit_case(RUN, create_stack, {
my_stack_t *s = stack_new(10);
assert_int(s->capacity, ==, 10, "Sets capacity to 10");
assert_int(s->count, ==, 0, "No elements in the stack yet");
assert_ptr_not_null(s->data, "Allocates the stack data");
// Clean up our allocated data.
free(s->data);
free(s);
// Should be nothing left that is allocated.
// assert(boot_all_freed());
});
munit_case(RUN, push_stack, {
my_stack_t *s = stack_new(2);
assert_ptr_not_null(s, "Must allocate a new stack");
assert_int(s->capacity, ==, 2, "Sets capacity to 2");
assert_int(s->count, ==, 0, "No elements in the stack yet");
assert_ptr_not_null(s->data, "Allocates the stack data");
int a = 1;
stack_push(s, &a);
stack_push(s, &a);
assert_int(s->capacity, ==, 2, "Sets capacity to 2");
assert_int(s->count, ==, 2, "2 elements in the stack");
assert_ptr_equal(s->data[0], &a, "element inserted into stack");
// Clean up our allocated data.
free(s->data);
free(s);
// Should be nothing left that is allocated.
// assert(boot_all_freed());
});
munit_case(SUBMIT, push_double_capacity, {
my_stack_t *s = stack_new(2);
assert_ptr_not_null(s, "Must allocate a new stack");
assert_int(s->capacity, ==, 2, "Sets capacity to 2");
assert_int(s->count, ==, 0, "No elements in the stack yet");
assert_ptr_not_null(s->data, "Allocates the stack data");
int a = 1;
stack_push(s, &a);
stack_push(s, &a);
assert_int(s->capacity, ==, 2, "Sets capacity to 2");
assert_int(s->count, ==, 2, "2 elements in the stack");
stack_push(s, &a);
assert_int(s->capacity, ==, 4, "Capacity is doubled");
assert_int(s->count, ==, 3, "3 elements in the stack");
// Should reallocate memory.
// assert_int_equal(boot_realloc_count(), 1, "Must reallocate memory for stack");
// Clean up our allocated data.
free(s->data);
free(s);
// Should be nothing left that is allocated.
// assert(boot_all_freed());
});
int main() {
MunitTest tests[] = {
munit_test("/create_stack", create_stack),
munit_test("/push_stack", push_stack),
munit_test("/push_double_capacity", push_double_capacity),
munit_null_test,
};
MunitSuite suite = munit_suite("snekstack", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}
+38
View File
@@ -0,0 +1,38 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include "snekstack.h"
void stack_push(my_stack_t *stack, void *obj) {
if (stack->count >= stack->capacity) {
void **data = realloc(stack->data, sizeof(void *) * stack->capacity * 2);
if (data == NULL) return;
stack->data = data;
stack->capacity *= 2;
}
stack->data[stack->count] = obj;
stack->count++;
}
// don't touch below this line
my_stack_t *stack_new(size_t capacity) {
my_stack_t *stack = malloc(sizeof(my_stack_t));
if (stack == NULL) {
return NULL;
}
stack->count = 0;
stack->capacity = capacity;
stack->data = malloc(stack->capacity * sizeof(void *));
if (stack->data == NULL) {
free(stack);
return NULL;
}
return stack;
}
+10
View File
@@ -0,0 +1,10 @@
#include <stddef.h>
typedef struct Stack {
size_t count;
size_t capacity;
void **data;
} my_stack_t; // NOTE: renamed due to std naming conflict on macOS
my_stack_t *stack_new(size_t capacity);
void stack_push(my_stack_t *stack, void *obj);
+121
View File
@@ -0,0 +1,121 @@
// #include "bootlib.h"
#include "munit.h"
#include "snekstack.h"
munit_case(RUN, pop_stack, {
my_stack_t *s = stack_new(2);
assert_ptr_not_null(s, "Must allocate a new stack");
assert_int(s->capacity, ==, 2, "Sets capacity to 2");
assert_int(s->count, ==, 0, "No elements in the stack yet");
assert_ptr_not_null(s->data, "Allocates the stack data");
int one = 1;
int two = 2;
int three = 3;
stack_push(s, &one);
stack_push(s, &two);
assert_int(s->capacity, ==, 2, "Sets capacity to 2");
assert_int(s->count, ==, 2, "2 elements in the stack");
stack_push(s, &three);
assert_int(s->capacity, ==, 4, "Capacity is doubled");
assert_int(s->count, ==, 3, "3 elements in the stack");
int *popped = stack_pop(s);
assert_int(*popped, ==, three, "Should pop the last element");
popped = stack_pop(s);
assert_int(*popped, ==, two, "Should pop the last element");
popped = stack_pop(s);
assert_int(*popped, ==, one, "Should pop the only remaining element");
popped = stack_pop(s);
assert_null(popped, "No remaining elements");
// Clean up our allocated data.
free(s->data);
free(s);
// Should be nothing left that is allocated.
// assert(boot_all_freed());
});
munit_case(SUBMIT, pop_stack_empty, {
my_stack_t *s = stack_new(2);
assert_ptr_not_null(s, "Must allocate a new stack");
assert_int(s->capacity, ==, 2, "Sets capacity to 2");
assert_int(s->count, ==, 0, "No elements in the stack yet");
assert_ptr_not_null(s->data, "Allocates the stack data");
int *popped = stack_pop(s);
assert_null(popped, "Should return null when popping an empty stack");
// Clean up our allocated data.
free(s->data);
free(s);
// Should be nothing left that is allocated.
// assert(boot_all_freed());
});
munit_case(RUN, push_stack, {
my_stack_t *s = stack_new(2);
assert_ptr_not_null(s, "Must allocate a new stack");
assert_int(s->capacity, ==, 2, "Sets capacity to 2");
assert_int(s->count, ==, 0, "No elements in the stack yet");
assert_ptr_not_null(s->data, "Allocates the stack data");
int a = 1;
stack_push(s, &a);
stack_push(s, &a);
assert_int(s->capacity, ==, 2, "Sets capacity to 2");
assert_int(s->count, ==, 2, "2 elements in the stack");
stack_push(s, &a);
assert_int(s->capacity, ==, 4, "Capacity is doubled");
assert_int(s->count, ==, 3, "3 elements in the stack");
// Clean up our allocated data.
free(s->data);
free(s);
// Should be nothing left that is allocated.
// assert(boot_all_freed());
});
munit_case(RUN, create_stack, {
my_stack_t *s = stack_new(10);
assert_int(s->capacity, ==, 10, "Sets capacity to 10");
assert_int(s->count, ==, 0, "No elements in the stack yet");
assert_ptr_not_null(s->data, "Allocates the stack data");
// Clean up our allocated data.
free(s->data);
free(s);
// Should be nothing left that is allocated.
// assert(boot_all_freed());
});
int main() {
MunitTest tests[] = {
munit_test("/create_stack", create_stack),
munit_test("/push_stack", push_stack),
munit_test("/pop_stack", pop_stack),
munit_test("/pop_stack_empty", pop_stack_empty),
munit_null_test,
};
MunitSuite suite = munit_suite("snekstack", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}
+46
View File
@@ -0,0 +1,46 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include "snekstack.h"
void *stack_pop(my_stack_t *stack) {
if (stack->count == 0) return NULL;
stack->count--;
return stack->data[stack->count];
}
// don't touch below this line'
void stack_push(my_stack_t *stack, void *obj) {
if (stack->count == stack->capacity) {
stack->capacity *= 2;
void **temp = realloc(stack->data, stack->capacity * sizeof(void *));
if (temp == NULL) {
stack->capacity /= 2;
exit(1);
}
stack->data = temp;
}
stack->data[stack->count] = obj;
stack->count++;
return;
}
my_stack_t *stack_new(size_t capacity) {
my_stack_t *stack = malloc(sizeof(my_stack_t));
if (stack == NULL) {
return NULL;
}
stack->count = 0;
stack->capacity = capacity;
stack->data = malloc(stack->capacity * sizeof(void *));
if (stack->data == NULL) {
free(stack);
return NULL;
}
return stack;
}
+11
View File
@@ -0,0 +1,11 @@
#include <stddef.h>
typedef struct Stack {
size_t count;
size_t capacity;
void **data;
} my_stack_t; // NOTE: renamed due to std naming conflict on macOS
my_stack_t *stack_new(size_t capacity);
void stack_push(my_stack_t *stack, void *obj);
void *stack_pop(my_stack_t *stack);
+88
View File
@@ -0,0 +1,88 @@
// #include "bootlib.h"
#include "munit.h"
#include "snekstack.h"
munit_case(RUN, pop_stack, {
my_stack_t *s = stack_new(2);
assert_ptr_not_null(s, "Must allocate a new stack");
assert_int(s->capacity, ==, 2, "Sets capacity to 2");
assert_int(s->count, ==, 0, "No elements in the stack yet");
assert_ptr_not_null(s->data, "Allocates the stack data");
int one = 1;
int two = 2;
int three = 3;
stack_push(s, &one);
stack_push(s, &two);
assert_int(s->capacity, ==, 2, "Sets capacity to 2");
assert_int(s->count, ==, 2, "2 elements in the stack");
stack_push(s, &three);
assert_int(s->capacity, ==, 4, "Capacity is doubled");
assert_int(s->count, ==, 3, "3 elements in the stack");
int *popped = stack_pop(s);
assert_int(*popped, ==, three, "Should pop the last element");
popped = stack_pop(s);
assert_int(*popped, ==, two, "Should pop the last element");
popped = stack_pop(s);
assert_int(*popped, ==, one, "Should pop the only remaining element");
popped = stack_pop(s);
assert_null(popped, "No remaining elements");
stack_free(s);
// assert(boot_all_freed());
});
munit_case(RUN, push_stack, {
my_stack_t *s = stack_new(2);
assert_ptr_not_null(s, "Must allocate a new stack");
assert_int(s->capacity, ==, 2, "Sets capacity to 2");
assert_int(s->count, ==, 0, "No elements in the stack yet");
assert_ptr_not_null(s->data, "Allocates the stack data");
int a = 1;
stack_push(s, &a);
stack_push(s, &a);
assert_int(s->capacity, ==, 2, "Sets capacity to 2");
assert_int(s->count, ==, 2, "2 elements in the stack");
stack_push(s, &a);
assert_int(s->capacity, ==, 4, "Capacity is doubled");
assert_int(s->count, ==, 3, "3 elements in the stack");
stack_free(s);
// assert(boot_all_freed());
});
munit_case(RUN, create_stack, {
my_stack_t *s = stack_new(10);
assert_int(s->capacity, ==, 10, "Sets capacity to 10");
assert_int(s->count, ==, 0, "No elements in the stack yet");
assert_ptr_not_null(s->data, "Allocates the stack data");
stack_free(s);
// assert(boot_all_freed());
});
int main() {
MunitTest tests[] = {
munit_test("/create_stack", create_stack),
munit_test("/push_stack", push_stack),
munit_test("/pop_stack", pop_stack),
munit_null_test,
};
MunitSuite suite = munit_suite("snekstack", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}
+59
View File
@@ -0,0 +1,59 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include "snekstack.h"
void stack_free(my_stack_t *stack) {
if (stack == NULL) return;
if (stack->data != NULL) {
free(stack->data);
stack->data = NULL;
}
free(stack);
}
// don't touch below this line
void *stack_pop(my_stack_t *stack) {
if (stack->count == 0) {
return NULL;
}
stack->count--;
return stack->data[stack->count];
}
void stack_push(my_stack_t *stack, void *obj) {
if (stack->count == stack->capacity) {
stack->capacity *= 2;
void **temp = realloc(stack->data, stack->capacity * sizeof(void *));
if (temp == NULL) {
stack->capacity /= 2;
exit(1);
}
stack->data = temp;
}
stack->data[stack->count] = obj;
stack->count++;
return;
}
my_stack_t *stack_new(size_t capacity) {
my_stack_t *stack = malloc(sizeof(my_stack_t));
if (stack == NULL) {
return NULL;
}
stack->count = 0;
stack->capacity = capacity;
stack->data = malloc(stack->capacity * sizeof(void *));
if (stack->data == NULL) {
free(stack);
return NULL;
}
return stack;
}
+12
View File
@@ -0,0 +1,12 @@
#include <stddef.h>
typedef struct Stack {
size_t count;
size_t capacity;
void **data;
} my_stack_t; // NOTE: renamed due to std naming conflict on macOS
my_stack_t *stack_new(size_t capacity);
void stack_push(my_stack_t *stack, void *obj);
void *stack_pop(my_stack_t *stack);
void stack_free(my_stack_t *stack);
+10
View File
@@ -0,0 +1,10 @@
#include "snekstack.h"
#include "stdlib.h"
void scary_double_push(my_stack_t *s) {
stack_push(s, (void *)1337);
int *number = malloc(sizeof(int));
if (number == NULL) return;
*number = 1024;
stack_push(s, number);
}
+3
View File
@@ -0,0 +1,3 @@
#include "snekstack.h"
void scary_double_push(my_stack_t *s);
+33
View File
@@ -0,0 +1,33 @@
#include "exercise.h"
// #include "bootlib.h"
#include "munit.h"
#include "snekstack.h"
munit_case(RUN, heterogenous_stack, {
my_stack_t *s = stack_new(2);
assert_ptr_not_null(s, "Must allocate a new stack");
scary_double_push(s);
assert_int(s->count, ==, 2, "Should have two items in the stack");
int value = (int)s->data[0];
assert_int(value, ==, 1337, "Zero item should be 1337");
int *pointer = s->data[1];
assert_int(*pointer, ==, 1024, "Top item should be 1024");
free(pointer);
stack_free(s);
});
int main() {
MunitTest tests[] = {
munit_test("/heterogenous_stack", heterogenous_stack),
munit_null_test,
};
MunitSuite suite = munit_suite("snekstack", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}
+58
View File
@@ -0,0 +1,58 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include "snekstack.h"
void stack_free(my_stack_t *stack) {
if (stack == NULL) {
return;
}
if (stack->data != NULL) {
free(stack->data);
}
free(stack);
}
void *stack_pop(my_stack_t *stack) {
if (stack->count == 0) {
return NULL;
}
stack->count--;
return stack->data[stack->count];
}
void stack_push(my_stack_t *stack, void *obj) {
if (stack->count == stack->capacity) {
stack->capacity *= 2;
void **temp = realloc(stack->data, stack->capacity * sizeof(void *));
if (temp == NULL) {
stack->capacity /= 2;
exit(1);
}
stack->data = temp;
}
stack->data[stack->count] = obj;
stack->count++;
return;
}
my_stack_t *stack_new(size_t capacity) {
my_stack_t *stack = malloc(sizeof(my_stack_t));
if (stack == NULL) {
return NULL;
}
stack->count = 0;
stack->capacity = capacity;
stack->data = malloc(stack->capacity * sizeof(void *));
if (stack->data == NULL) {
free(stack);
return NULL;
}
return stack;
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <stddef.h>
typedef struct Stack {
size_t count;
size_t capacity;
void **data;
} my_stack_t; // NOTE: renamed due to std naming conflict on macOS
my_stack_t *stack_new(size_t capacity);
void stack_push(my_stack_t *stack, void *obj);
void *stack_pop(my_stack_t *stack);
void stack_free(my_stack_t *stack);
+20
View File
@@ -0,0 +1,20 @@
#include <stdlib.h>
#include <string.h>
#include "snekstack.h"
void stack_push_multiple_types(my_stack_t *s)
{
float *pi = (float *)malloc(sizeof(float));
if (pi == NULL) return;
*pi = 3.14;
stack_push(s, pi);
const char *text = "Sneklang is blazingly slow!";
char *str = (char *)malloc(sizeof(char) * strlen(text));
if (str == NULL) return;
strcpy(str, text);
stack_push(s, str);
}
+3
View File
@@ -0,0 +1,3 @@
#include "snekstack.h"
void stack_push_multiple_types(my_stack_t *s);
+34
View File
@@ -0,0 +1,34 @@
#include "exercise.h"
// #include "bootlib.h"
#include "munit.h"
#include "snekstack.h"
munit_case(RUN, multiple_types_stack, {
my_stack_t *s = stack_new(4);
assert_ptr_not_null(s, "Must allocate a new stack");
stack_push_multiple_types(s);
assert_int(s->count, ==, 2, "Should have two items in the stack");
float *f = s->data[0];
assert_float(*f, ==, 3.14, "Float is equal");
char *string = s->data[1];
assert_string_equal(string, "Sneklang is blazingly slow!", "char* is equal");
free(f);
free(string);
stack_free(s);
});
int main() {
MunitTest tests[] = {
munit_test("/multiple_types_stack", multiple_types_stack),
munit_null_test,
};
MunitSuite suite = munit_suite("snekstack", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}
+58
View File
@@ -0,0 +1,58 @@
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include "snekstack.h"
void stack_free(my_stack_t *stack) {
if (stack == NULL) {
return;
}
if (stack->data != NULL) {
free(stack->data);
}
free(stack);
}
void *stack_pop(my_stack_t *stack) {
if (stack->count == 0) {
return NULL;
}
stack->count--;
return stack->data[stack->count];
}
void stack_push(my_stack_t *stack, void *obj) {
if (stack->count == stack->capacity) {
stack->capacity *= 2;
void **temp = realloc(stack->data, stack->capacity * sizeof(void *));
if (temp == NULL) {
stack->capacity /= 2;
exit(1);
}
stack->data = temp;
}
stack->data[stack->count] = obj;
stack->count++;
return;
}
my_stack_t *stack_new(size_t capacity) {
my_stack_t *stack = malloc(sizeof(my_stack_t));
if (stack == NULL) {
return NULL;
}
stack->count = 0;
stack->capacity = capacity;
stack->data = malloc(stack->capacity * sizeof(void *));
if (stack->data == NULL) {
free(stack);
return NULL;
}
return stack;
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
#include <stddef.h>
typedef struct Stack {
size_t count;
size_t capacity;
void **data;
} my_stack_t; // NOTE: renamed due to std naming conflict on macOS
my_stack_t *stack_new(size_t capacity);
void stack_push(my_stack_t *stack, void *obj);
void *stack_pop(my_stack_t *stack);
void stack_free(my_stack_t *stack);
+13 -3
View File
@@ -43,6 +43,10 @@
#define assert_uint(A, OP, B, MSG) \
munit_assert_uint(A, OP, B);
#undef assert_float
#define assert_float(A, OP, B, MSG) \
munit_assert_float(A, OP, B, MSG);
#undef assert_double
#define assert_double(A, OP, B, MSG) \
munit_assert_double(A, OP, B);
@@ -92,11 +96,17 @@
#define munit_assert_not_null(PTR, MSG) \
munit_assert_ptr(PTR, !=, NULL)
// ptr
#undef assert_null
#define assert_null(PTR, MSG) munit_assert_null(PTR, MSG)
#undef assert_ptr_not_null
#define assert_ptr_not_null(PTR, MSG) munit_assert_not_null(PTR, MSG)
// ptr
#undef munit_assert_ptr_not_equal
#define munit_assert_ptr_not_equal(A, B, MSG) \
munit_assert_ptr(A, !=, B)
#undef assert_ptr_not_null
#define assert_ptr_not_null(PTR, MSG) munit_assert_not_null(PTR, MSG)
#undef assert_ptr_equal
#define assert_ptr_equal(A, B, MSG) munit_assert_ptr_equal(A, B)