Browse Source

Add more exercises

master
Riyyi 1 week ago
parent
commit
4e6cd60609
  1. 207
      README.org
  2. BIN
      bootdev-c.png
  3. 39
      src/8-1-low-level-stack/main.c
  4. 18
      src/8-1-low-level-stack/snekstack.c
  5. 9
      src/8-1-low-level-stack/snekstack.h
  6. 88
      src/8-2-stack-push/main.c
  7. 38
      src/8-2-stack-push/snekstack.c
  8. 10
      src/8-2-stack-push/snekstack.h
  9. 121
      src/8-3-stack-pop/main.c
  10. 46
      src/8-3-stack-pop/snekstack.c
  11. 11
      src/8-3-stack-pop/snekstack.h
  12. 88
      src/8-4-stack-free/main.c
  13. 59
      src/8-4-stack-free/snekstack.c
  14. 12
      src/8-4-stack-free/snekstack.h
  15. 10
      src/8-5-dangerous-push/exercise.c
  16. 3
      src/8-5-dangerous-push/exercise.h
  17. 33
      src/8-5-dangerous-push/main.c
  18. 58
      src/8-5-dangerous-push/snekstack.c
  19. 14
      src/8-5-dangerous-push/snekstack.h
  20. 20
      src/8-6-multiple-types/exercise.c
  21. 3
      src/8-6-multiple-types/exercise.h
  22. 34
      src/8-6-multiple-types/main.c
  23. 58
      src/8-6-multiple-types/snekstack.c
  24. 14
      src/8-6-multiple-types/snekstack.h
  25. 16
      src/munit.h

207
README.org

@ -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
bootdev-c.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

39
src/8-1-low-level-stack/main.c

@ -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
src/8-1-low-level-stack/snekstack.c

@ -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
src/8-1-low-level-stack/snekstack.h

@ -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
src/8-2-stack-push/main.c

@ -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
src/8-2-stack-push/snekstack.c

@ -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
src/8-2-stack-push/snekstack.h

@ -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
src/8-3-stack-pop/main.c

@ -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
src/8-3-stack-pop/snekstack.c

@ -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
src/8-3-stack-pop/snekstack.h

@ -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
src/8-4-stack-free/main.c

@ -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
src/8-4-stack-free/snekstack.c

@ -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
src/8-4-stack-free/snekstack.h

@ -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
src/8-5-dangerous-push/exercise.c

@ -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
src/8-5-dangerous-push/exercise.h

@ -0,0 +1,3 @@
#include "snekstack.h"
void scary_double_push(my_stack_t *s);

33
src/8-5-dangerous-push/main.c

@ -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
src/8-5-dangerous-push/snekstack.c

@ -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
src/8-5-dangerous-push/snekstack.h

@ -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
src/8-6-multiple-types/exercise.c

@ -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
src/8-6-multiple-types/exercise.h

@ -0,0 +1,3 @@
#include "snekstack.h"
void stack_push_multiple_types(my_stack_t *s);

34
src/8-6-multiple-types/main.c

@ -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
src/8-6-multiple-types/snekstack.c

@ -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
src/8-6-multiple-types/snekstack.h

@ -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);

16
src/munit.h

@ -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)

Loading…
Cancel
Save