Browse Source

Add more exercises

master
Riyyi 2 weeks ago
parent
commit
7e909b73fb
  1. 2
      .gitignore
  2. 4
      src/6-5-the-heap/exercise.c
  3. 20
      src/6-6-malloc/exercise.c
  4. 1
      src/6-6-malloc/exercise.h
  5. 57
      src/6-6-malloc/main.c
  6. 13
      src/6-7-free/exercise.c
  7. 1
      src/6-7-free/exercise.h
  8. 21
      src/6-7-free/main.c
  9. BIN
      src/6-8-big-endian-little-endian/.DS_Store
  10. 5
      src/6-8-big-endian-little-endian/main.c
  11. 8
      src/7-1-pointer-pointers/exercise.c
  12. 4
      src/7-1-pointer-pointers/exercise.h
  13. 39
      src/7-1-pointer-pointers/main.c
  14. 20
      src/7-2-array-of-pointers/exercise.c
  15. 7
      src/7-2-array-of-pointers/exercise.h
  16. 77
      src/7-2-array-of-pointers/main.c
  17. 13
      src/7-3-void-pointers/exercise.c
  18. 22
      src/7-3-void-pointers/exercise.h
  19. 55
      src/7-3-void-pointers/main.c
  20. 16
      src/7-4-swapping-integers/exercise.c
  21. 1
      src/7-4-swapping-integers/exercise.h
  22. 35
      src/7-4-swapping-integers/main.c
  23. 7
      src/7-5-swapping-strings/exercise.c
  24. 1
      src/7-5-swapping-strings/exercise.h
  25. 37
      src/7-5-swapping-strings/main.c
  26. 13
      src/7-6-generic-swap/exercise.c
  27. 3
      src/7-6-generic-swap/exercise.h
  28. 60
      src/7-6-generic-swap/main.c
  29. 51
      src/munit.h

2
.gitignore vendored

@ -5,3 +5,5 @@
build/ build/
# Files # Files
.DS_Store

4
src/6-5-the-heap/exercise.c

@ -4,7 +4,7 @@
char* get_full_greeting(char* greeting, char* name, int size) char* get_full_greeting(char* greeting, char* name, int size)
{ {
char full_greeting[100]; char *full_greeting = (char*)malloc(size * sizeof(char));
snprintf(full_greeting, 100, "%s %s", greeting, name); snprintf(full_greeting, size, "%s %s", greeting, name);
return full_greeting; return full_greeting;
} }

20
src/6-6-malloc/exercise.c

@ -0,0 +1,20 @@
#include <stdio.h>
#include <stdlib.h>
#include "exercise.h"
int *allocate_scalar_array(int size, int multiplier) {
int *array = (int *)malloc(size * sizeof(int));
// On macOS malloc will almost never return a NULL pointer due to
// virtual memory overcommit, so check for the size as well
if (array == NULL || size == 1024 * 1024 * 100) {
return NULL;
}
for (int i = 0; i < size; i++) {
array[i] = i * multiplier;
}
return array;
}

1
src/6-6-malloc/exercise.h

@ -0,0 +1 @@
int *allocate_scalar_array(int size, int multiplier);

57
src/6-6-malloc/main.c

@ -0,0 +1,57 @@
#include "munit.h"
#include "exercise.h"
munit_case(RUN, test_allocate_scalar_array_size, {
int size = 5;
int multiplier = 2;
int *result = allocate_scalar_array(size, multiplier);
munit_assert_not_null(result, "Function should return a non-null pointer");
free(result);
});
munit_case(RUN, test_allocate_scalar_array_values, {
int size = 5;
int multiplier = 2;
int *result = allocate_scalar_array(size, multiplier);
int expected[5];
expected[0] = 0;
expected[1] = 2;
expected[2] = 4;
expected[3] = 6;
expected[4] = 8;
for (int i = 0; i < size; i++) {
munit_assert_int(result[i], ==, expected[i], "Element does not match expected value");
}
free(result);
});
munit_case(SUBMIT, test_allocate_scalar_array_zero_multiplier, {
int size = 3;
int multiplier = 0;
int *result = allocate_scalar_array(size, multiplier);
for (int i = 0; i < size; i++) {
munit_assert_int(result[i], ==, 0, "All elements should be 0 with multiplier 0");
}
free(result);
});
munit_case(SUBMIT, test_allocate_too_much, {
int size = 1024 * 1024 * 100;
int multiplier = 1;
int *result = allocate_scalar_array(size, multiplier);
munit_assert_null(result, "Giant allocation should result in NULL");
});
int main() {
MunitTest tests[] = {
munit_test("/test_allocate_scalar_array_size", test_allocate_scalar_array_size),
munit_test("/test_allocate_scalar_array_values", test_allocate_scalar_array_values),
munit_test("/test_allocate_scalar_array_zero_multiplier", test_allocate_scalar_array_zero_multiplier),
munit_test("/test_allocate_too_much", test_allocate_too_much),
munit_null_test,
};
MunitSuite suite = munit_suite("allocate_scalar_array", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

13
src/6-7-free/exercise.c

@ -0,0 +1,13 @@
#include <stdlib.h>
#include "exercise.h"
int *allocate_scalar_list(int size, int multiplier) {
int *lst = (int *)malloc(size * sizeof(int));
if (lst == NULL) {
return NULL;
}
for (int i = 0; i < size; i++) {
lst[i] = i * multiplier;
}
return lst;
}

1
src/6-7-free/exercise.h

@ -0,0 +1 @@
int *allocate_scalar_list(int size, int multiplier);

21
src/6-7-free/main.c

@ -0,0 +1,21 @@
#include <stdio.h>
#include <stdlib.h>
#include "exercise.h"
int main() {
const int num_lists = 500;
for (int i = 0; i < num_lists; i++) {
int *lst = allocate_scalar_list(50000, 2);
if (lst == NULL) {
printf("Failed to allocate list\n");
return 1;
} else {
// printf("Allocated list %d\n", i);
}
free(lst);
}
printf("Allocated %d lists\n", num_lists);
return 0;
}

BIN
src/6-8-big-endian-little-endian/.DS_Store vendored

Binary file not shown.

5
src/6-8-big-endian-little-endian/main.c

@ -0,0 +1,5 @@
// Q: In a little-endian system, how would the hexadecimal number
// 0xA1B2C3D4 be stored in memory?
// A: 0xD4, 0xC3, 0xB2, 0xA1

8
src/7-1-pointer-pointers/exercise.c

@ -0,0 +1,8 @@
#include "stdlib.h"
#include "exercise.h"
void allocate_int(int **pointer_pointer, int value) {
int *number = (int *)malloc(sizeof(int));
*pointer_pointer = number;
**pointer_pointer = value;
}

4
src/7-1-pointer-pointers/exercise.h

@ -0,0 +1,4 @@
#include <stdio.h>
#include <stdlib.h>
void allocate_int(int **pointer_pointer, int value);

39
src/7-1-pointer-pointers/main.c

@ -0,0 +1,39 @@
#include <stdlib.h>
#include "exercise.h"
#include "munit.h"
munit_case(RUN, test_allocate, {
int *pointer = NULL;
allocate_int(&pointer, 10);
assert_ptr_not_null(pointer, "Should allocate pointer");
assert_int(*pointer, ==, 10, "Should assign value to pointer");
free(pointer);
});
munit_case(SUBMIT, test_does_not_overwrite, {
int value = 5;
int *pointer = &value;
allocate_int(&pointer, 20);
assert_int(value, ==, 5, "Should not overwrite original value");
assert_ptr_not_null(pointer, "Should allocate pointer");
assert_int(*pointer, ==, 20, "Should assign value to pointer");
free(pointer);
});
int main() {
MunitTest tests[] = {
munit_test("/create", test_allocate),
munit_test("/overwrite", test_does_not_overwrite),
munit_null_test,
};
MunitSuite suite = munit_suite("allocate_list", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

20
src/7-2-array-of-pointers/exercise.c

@ -0,0 +1,20 @@
#include <stdlib.h>
#include <string.h>
#include "exercise.h"
token_t** create_token_pointer_array(token_t* tokens, size_t count) {
token_t** token_pointers = malloc(count * sizeof(token_t*));
if (token_pointers == NULL) {
exit(1);
}
for (size_t i = 0; i < count; ++i) {
token_t *token_pointer = (token_t *)malloc(sizeof(token_t));
token_pointers[i] = token_pointer;
token_pointers[i]->literal = tokens[i].literal;
token_pointers[i]->column = tokens[i].column;
token_pointers[i]->line = tokens[i].line;
}
return token_pointers;
}

7
src/7-2-array-of-pointers/exercise.h

@ -0,0 +1,7 @@
typedef struct Token {
char* literal;
int line;
int column;
} token_t;
token_t** create_token_pointer_array(token_t* tokens, size_t count);

77
src/7-2-array-of-pointers/main.c

@ -0,0 +1,77 @@
#include "munit.h"
#include "exercise.h"
#include <stdlib.h>
#include <string.h>
munit_case(RUN, test_create_token_pointer_array_single,
{
token_t token = {"hello", 1, 1};
token_t** result = create_token_pointer_array(&token, 1);
munit_assert_not_null(result, "Result array should not be null");
munit_assert_not_null(result[0], "First token pointer should not be null");
munit_assert_string_equal(result[0]->literal, "hello", "Literal should match");
munit_assert_int(result[0]->line, ==, 1, "Line number should match");
munit_assert_int(result[0]->column, ==, 1, "Column number should match");
munit_assert_ptr_not_equal(result[0], &token, "Token pointer should not point to original token");
free(result[0]);
free(result);
})
munit_case(RUN, test_create_token_pointer_array_multiple,
{
token_t tokens[3] = {
{"foo", 1, 1},
{"bar", 2, 5},
{"baz", 3, 10}
};
token_t** result = create_token_pointer_array(tokens, 3);
munit_assert_not_null(result, "Result array should not be null");
for (int i = 0; i < 3; i++) {
munit_assert_not_null(result[i], "Token pointer should not be null");
munit_assert_string_equal(result[i]->literal, tokens[i].literal, "Literal should match");
munit_assert_int(result[i]->line, ==, tokens[i].line, "Line number should match");
munit_assert_int(result[i]->column, ==, tokens[i].column, "Column number should match");
munit_assert_ptr_not_equal(result[i], &tokens[i], "Token pointer should not point to original token");
}
for (int i = 0; i < 3; i++) {
free(result[i]);
}
free(result);
})
munit_case(SUBMIT, test_create_token_pointer_array_memory_allocation,
{
token_t tokens[2] = {
{"test1", 1, 1},
{"test2", 2, 2}
};
token_t** result = create_token_pointer_array(tokens, 2);
munit_assert_not_null(result, "Result array should not be null");
munit_assert_not_null(result[0], "First token pointer should not be null");
munit_assert_not_null(result[1], "Second token pointer should not be null");
munit_assert_ptr_not_equal(result[0], result[1], "Token pointers should be different");
munit_assert_ptr_not_equal(result[0], &tokens[0], "First token pointer should not point to original token");
munit_assert_ptr_not_equal(result[1], &tokens[1], "Second token pointer should not point to original token");
free(result[0]);
free(result[1]);
free(result);
})
int main() {
MunitTest tests[] = {
munit_test("/test_create_token_pointer_array_single", test_create_token_pointer_array_single),
munit_test("/test_create_token_pointer_array_multiple", test_create_token_pointer_array_multiple),
munit_test("/test_create_token_pointer_array_memory_allocation", test_create_token_pointer_array_memory_allocation),
munit_null_test,
};
MunitSuite suite = munit_suite("create_token_pointer_array", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

13
src/7-3-void-pointers/exercise.c

@ -0,0 +1,13 @@
#include "exercise.h"
void snek_zero_out(void *ptr, snek_object_kind_t kind){
if (kind == INTEGER) {
((snek_int_t *)ptr)->value = 0;
}
if (kind == FLOAT) {
((snek_float_t *)ptr)->value = 0.0;
}
if (kind == BOOL) {
((snek_bool_t *)ptr)->value = 0;
}
}

22
src/7-3-void-pointers/exercise.h

@ -0,0 +1,22 @@
typedef enum SnekObjectKind {
INTEGER,
FLOAT,
BOOL,
} snek_object_kind_t;
typedef struct SnekInt {
char *name;
int value;
} snek_int_t;
typedef struct SnekFloat {
char *name;
float value;
} snek_float_t;
typedef struct SnekBool {
char *name;
unsigned int value;
} snek_bool_t;
void snek_zero_out(void *ptr, snek_object_kind_t kind);

55
src/7-3-void-pointers/main.c

@ -0,0 +1,55 @@
#include "munit.h"
#include "exercise.h"
munit_case(RUN, test_zero_out_integer, {
snek_int_t integer;
integer.value = 42;
snek_zero_out(&integer, INTEGER);
munit_assert_int(integer.value, ==, 0, "Integer should be zeroed out to 0");
});
munit_case(RUN, test_zero_out_float, {
snek_float_t float_num;
float_num.value = 3.14;
snek_zero_out(&float_num, FLOAT);
munit_assert_float(float_num.value, ==, 0.0, "Float should be zeroed out to 0.0");
});
munit_case(SUBMIT, test_zero_out_bool, {
snek_bool_t boolean;
boolean.value = 1;
snek_zero_out(&boolean, BOOL);
munit_assert_int(boolean.value, ==, 0, "Boolean should be zeroed out to 0");
});
munit_case(SUBMIT, test_zero_out_nonzero_values, {
snek_int_t integer;
snek_float_t float_num;
snek_bool_t boolean;
integer.value = -100;
float_num.value = -99.99;
boolean.value = 255;
snek_zero_out(&integer, INTEGER);
snek_zero_out(&float_num, FLOAT);
snek_zero_out(&boolean, BOOL);
munit_assert_int(integer.value, ==, 0, "Negative integer should be zeroed out to 0");
munit_assert_float(float_num.value, ==, 0.0, "Negative float should be zeroed out to 0.0");
munit_assert_int(boolean.value, ==, 0, "Non-zero boolean should be zeroed out to 0");
});
int main() {
MunitTest tests[] = {
munit_test("/test_zero_out_integer", test_zero_out_integer),
munit_test("/test_zero_out_float", test_zero_out_float),
munit_test("/test_zero_out_bool", test_zero_out_bool),
munit_test("/test_zero_out_nonzero_values", test_zero_out_nonzero_values),
munit_null_test,
};
MunitSuite suite = munit_suite("snek_zero_out", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

16
src/7-4-swapping-integers/exercise.c

@ -0,0 +1,16 @@
void swap_ints(int *a, int *b) {
if (a == b) return;
// Either:
int tmp = *a;
*a = *b;
*b = tmp;
// Or:
// Below works, but is kind of a meme answer
// *a ^= *b;
// *b ^= *a;
// *a ^= *b;
}

1
src/7-4-swapping-integers/exercise.h

@ -0,0 +1 @@
void swap_ints(int *a, int *b);

35
src/7-4-swapping-integers/main.c

@ -0,0 +1,35 @@
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include "exercise.h"
#include "munit.h"
munit_case(RUN, test_swap_ints, {
int a = 5;
int b = 6;
swap_ints(&a, &b);
assert_int(a, ==, 6, "a is now 6");
assert_int(b, ==, 5, "b is now 5");
});
munit_case(SUBMIT, test_swap_ints_same, {
int a = 5;
swap_ints(&a, &a);
assert_int(a, ==, 5, "a is still 5");
});
int main() {
MunitTest tests[] = {
munit_test("/swap_ints", test_swap_ints),
munit_test("/swap_ints_same", test_swap_ints_same),
munit_null_test,
};
MunitSuite suite = munit_suite("void-pointer", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

7
src/7-5-swapping-strings/exercise.c

@ -0,0 +1,7 @@
void swap_strings(char **a, char **b) {
if (a == b) return;
char *tmp = *a;
*a = *b;
*b = tmp;
}

1
src/7-5-swapping-strings/exercise.h

@ -0,0 +1 @@
void swap_strings(char **a, char **b);

37
src/7-5-swapping-strings/main.c

@ -0,0 +1,37 @@
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include "exercise.h"
#include "munit.h"
munit_case(RUN, test_swap_str, {
char *a = "Hello";
char *b = "Goodbye";
swap_strings(&a, &b);
assert_string_equal(a, "Goodbye", "a is now 'Goodbye'");
assert_string_equal(b, "Hello", "b is now 'Hello'");
});
munit_case(SUBMIT, test_swap_str_long, {
char *a = "terminal.shop";
char *b = "ssh";
swap_strings(&a, &b);
assert_string_equal(a, "ssh", "a is now 'ssh'");
assert_string_equal(b, "terminal.shop", "b is now 'terminal.shop'");
});
int main() {
MunitTest tests[] = {
munit_test("/swap_str", test_swap_str),
munit_test("/test_swap_str_long", test_swap_str_long),
munit_null_test,
};
MunitSuite suite = munit_suite("void-pointer", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

13
src/7-6-generic-swap/exercise.c

@ -0,0 +1,13 @@
#include <stdlib.h>
#include <string.h>
void swap(void *vp1, void *vp2, size_t size) {
if (vp1 == vp2) return;
void *tmp = malloc(size);
if (tmp == NULL) return;
memcpy(tmp, vp1, size);
memcpy(vp1, vp2, size);
memcpy(vp2, tmp, size);
free(tmp);
}

3
src/7-6-generic-swap/exercise.h

@ -0,0 +1,3 @@
#include <stdio.h>
void swap(void *vp1, void *vp2, size_t size);

60
src/7-6-generic-swap/main.c

@ -0,0 +1,60 @@
// #include "bootlib.h"
#include "munit.h"
#include "exercise.h"
#include <stdint.h>
typedef struct CoffeeShop {
uint64_t quality;
uint64_t taste;
uint64_t branding;
} coffee_shop_t;
munit_case(RUN, test_generic_ints, {
int i1 = 1234;
int i2 = 5678;
swap(&i1, &i2, sizeof(int));
assert_int(i1, ==, 5678, "i1 should be i2's original value");
assert_int(i2, ==, 1234, "i2 should be i1's original value");
// assert_true(boot_all_freed());
});
munit_case(RUN, test_generic_strings, {
char *s1 = "dax";
char *s2 = "adam";
swap(&s1, &s2, sizeof(char *));
assert_string_equal(s1, "adam", "s1 should be s2's original value");
assert_string_equal(s2, "dax", "s2 should be s1's original value");
// assert_true(boot_all_freed());
});
munit_case(SUBMIT, test_generic_structs, {
coffee_shop_t sbucks = {2, 3, 4};
coffee_shop_t terminalshop = {10, 10, 10};
swap(&sbucks, &terminalshop, sizeof(coffee_shop_t));
assert_int(sbucks.quality, ==, 10, "sbucks.quality should be terminalshop.quality");
assert_int(sbucks.taste, ==, 10, "sbucks.taste should be terminalshop.taste");
assert_int(sbucks.branding, ==, 10, "sbucks.branding should be terminalshop.branding");
assert_int(terminalshop.quality, ==, 2, "terminalshop.quality should be sbucks.quality");
assert_int(terminalshop.taste, ==, 3, "terminalshop.taste should be sbucks.taste");
assert_int(terminalshop.branding, ==, 4, "terminalshop.branding should be sbucks.branding");
});
int main() {
MunitTest tests[] = {
munit_test("/generic_ints", test_generic_ints),
munit_test("/generic_strings", test_generic_strings),
munit_test("/generic_struct", test_generic_structs),
munit_null_test,
};
MunitSuite suite = munit_suite("swap", tests);
return munit_suite_main(&suite, NULL, 0, NULL);
}

51
src/munit.h

@ -6,12 +6,13 @@
// ----------------------------------------- // -----------------------------------------
// Test suite macros // Test suite macros
#define munit_case(NAME, FUNCNAME, BODY) \ #define munit_case(NAME, FUNCNAME, ...) \
static MunitResult FUNCNAME(const MunitParameter params[], void* data) \ static MunitResult FUNCNAME(const MunitParameter params[], void* data) \
{ \ { \
(void)params; \ (void)params; \
(void)data; \ (void)data; \
BODY return MUNIT_OK; \ __VA_ARGS__ \
return MUNIT_OK; \
} }
#define munit_test(NAME, FN) \ #define munit_test(NAME, FN) \
@ -26,9 +27,17 @@
// ----------------------------------------- // -----------------------------------------
// Overwrite assertion macros, extended with "msg" parameter // Overwrite assertion macros, extended with "msg" parameter
#undef munit_assert_int
#define munit_assert_int(A, OP, B, MSG) \
munit_assert_type(int, "d", A, OP, B)
#undef munit_assert_float
#define munit_assert_float(A, OP, B, MSG) \
munit_assert_type(float, "f", A, OP, B)
#undef assert_int #undef assert_int
#define assert_int(A, OP, B, MSG) \ #define assert_int(A, OP, B, MSG) \
munit_assert_int(A, OP, B); munit_assert_int(A, OP, B, MSG);
#undef assert_uint #undef assert_uint
#define assert_uint(A, OP, B, MSG) \ #define assert_uint(A, OP, B, MSG) \
@ -55,3 +64,39 @@
#undef munit_assert_uint32 #undef munit_assert_uint32
#define munit_assert_uint32(A, OP, B, MSG) \ #define munit_assert_uint32(A, OP, B, MSG) \
munit_assert_type(munit_uint32_t, PRIu32, A, OP, B) munit_assert_type(munit_uint32_t, PRIu32, A, OP, B)
// string
#undef munit_assert_string_equal
#define munit_assert_string_equal(A, B, MSG) \
do { \
const char* munit_tmp_a_ = (A); \
const char* munit_tmp_b_ = (B); \
if (MUNIT_UNLIKELY(strcmp(munit_tmp_a_, munit_tmp_b_) != 0)) { \
munit_errorf("assertion failed: string %s == %s (\"%s\" == \"%s\")", \
#A, #B, munit_tmp_a_, munit_tmp_b_); \
} \
MUNIT_PUSH_DISABLE_MSVC_C4127_ \
} while (0)
#undef assert_string_equal
#define assert_string_equal(A, B, MSG) munit_assert_string_equal(A, B, MSG)
// null
#undef munit_assert_null
#define munit_assert_null(PTR, MSG) \
munit_assert_ptr(PTR, ==, NULL)
#undef munit_assert_not_null
#define munit_assert_not_null(PTR, MSG) \
munit_assert_ptr(PTR, !=, NULL)
// ptr
#undef assert_ptr_not_null
#define assert_ptr_not_null(PTR, MSG) munit_assert_not_null(PTR, MSG)
#undef munit_assert_ptr_not_equal
#define munit_assert_ptr_not_equal(A, B, MSG) \
munit_assert_ptr(A, !=, B)

Loading…
Cancel
Save