25 changed files with 1006 additions and 3 deletions
@ -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 |
After Width: | Height: | Size: 311 KiB |
@ -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); |
||||
} |
@ -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; |
||||
} |
@ -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); |
@ -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); |
||||
} |
@ -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; |
||||
} |
@ -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); |
@ -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); |
||||
} |
@ -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; |
||||
} |
@ -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); |
@ -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); |
||||
} |
@ -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; |
||||
} |
@ -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); |
@ -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); |
||||
} |
@ -0,0 +1,3 @@
|
||||
#include "snekstack.h" |
||||
|
||||
void scary_double_push(my_stack_t *s); |
@ -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); |
||||
} |
@ -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; |
||||
} |
@ -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); |
@ -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); |
||||
} |
@ -0,0 +1,3 @@
|
||||
#include "snekstack.h" |
||||
|
||||
void stack_push_multiple_types(my_stack_t *s); |
@ -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); |
||||
} |
@ -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; |
||||
} |
@ -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); |
Loading…
Reference in new issue