Compare commits
47 Commits
2342d9b7f6
...
master
Author | SHA1 | Date | |
---|---|---|---|
f4acc1434a | |||
67b2d3ec40 | |||
9a3d216a65 | |||
10f4f8572d | |||
3a3d50b0a5 | |||
7b92456167 | |||
07eb95fb58 | |||
916c67f31e | |||
dd929471f2 | |||
c1a62521c4 | |||
0333652fdc | |||
c6d39e8702 | |||
064f3d27a9 | |||
33cc1343cb | |||
77a8072c73 | |||
215629a19c | |||
8ebb596c9f | |||
e988624f95 | |||
3795a5b605 | |||
c9ddb8b3ce | |||
9cc619e37f | |||
9e85bd36df | |||
e45819d3ef | |||
29905d7894 | |||
5a35db2396 | |||
b200831b51 | |||
d3002514a5 | |||
7cf02bc336 | |||
002ce9c313 | |||
4f882b01cc | |||
9901680424 | |||
6c5e61efe9 | |||
01fcdc8566 | |||
01365f370b | |||
f8574c2f4e | |||
03ab0349a3 | |||
04f1f5e23b | |||
e357f5c26a | |||
ccb96a4f2a | |||
46d0fa38b2 | |||
021b014151 | |||
01dd79be15 | |||
4cf3fb610a | |||
58d81e96a6 | |||
6e9a77168e | |||
69ffe15ed6 | |||
9542b0bf09 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,4 +2,7 @@ core
|
||||
*.out
|
||||
*_test.sh
|
||||
test/
|
||||
test-framework/
|
||||
users/
|
||||
.exercism
|
||||
.projectile
|
||||
|
@@ -1 +1 @@
|
||||
My solutions to some [exercism](https://exercism.io/) exercises.
|
||||
My solutions to some [exercism](https://exercism.org/) exercises.
|
||||
|
51
c/allergies/GNUmakefile
Normal file
51
c/allergies/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o tests.out $(LIBS)
|
68
c/allergies/README.md
Normal file
68
c/allergies/README.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# Allergies
|
||||
|
||||
Given a person's allergy score, determine whether or not they're allergic to a given item, and their full list of allergies.
|
||||
|
||||
An allergy test produces a single numeric score which contains the
|
||||
information about all the allergies the person has (that they were
|
||||
tested for).
|
||||
|
||||
The list of items (and their value) that were tested are:
|
||||
|
||||
* eggs (1)
|
||||
* peanuts (2)
|
||||
* shellfish (4)
|
||||
* strawberries (8)
|
||||
* tomatoes (16)
|
||||
* chocolate (32)
|
||||
* pollen (64)
|
||||
* cats (128)
|
||||
|
||||
So if Tom is allergic to peanuts and chocolate, he gets a score of 34.
|
||||
|
||||
Now, given just that score of 34, your program should be able to say:
|
||||
|
||||
- Whether Tom is allergic to any one of those allergens listed above.
|
||||
- All the allergens Tom is allergic to.
|
||||
|
||||
Note: a given score may include allergens **not** listed above (i.e.
|
||||
allergens that score 256, 512, 1024, etc.). Your program should
|
||||
ignore those components of the score. For example, if the allergy
|
||||
score is 257, your program should only report the eggs (1) allergy.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
Jumpstart Lab Warm-up [http://jumpstartlab.com](http://jumpstartlab.com)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/allergies/makefile
Normal file
37
c/allergies/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
20
c/allergies/src/allergies.c
Normal file
20
c/allergies/src/allergies.c
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "allergies.h"
|
||||
|
||||
#ifdef USE_ALLERGIC_TO_FUNCTION
|
||||
bool is_allergic_to(const allergen_t all, const uint32_t val)
|
||||
{
|
||||
return !!(val & (1 << all));
|
||||
}
|
||||
#endif
|
||||
|
||||
allergen_list_t get_allergens(uint32_t val)
|
||||
{
|
||||
allergen_list_t list = { .count = 0 };
|
||||
allergen_t i;
|
||||
|
||||
for (i=0; i<ALLERGEN_COUNT; ++i) {
|
||||
list.allergens[i] = is_allergic_to(i, val);
|
||||
list.count += list.allergens[i];
|
||||
}
|
||||
return list;
|
||||
}
|
46
c/allergies/src/allergies.h
Normal file
46
c/allergies/src/allergies.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef ALLERGIES_H
|
||||
#define ALLERGIES_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum {
|
||||
ALLERGEN_EGGS = 0,
|
||||
ALLERGEN_PEANUTS,
|
||||
ALLERGEN_SHELLFISH,
|
||||
ALLERGEN_STRAWBERRIES,
|
||||
ALLERGEN_TOMATOES,
|
||||
ALLERGEN_CHOCOLATE,
|
||||
ALLERGEN_POLLEN,
|
||||
ALLERGEN_CATS,
|
||||
ALLERGEN_COUNT,
|
||||
} allergen_t;
|
||||
|
||||
typedef struct {
|
||||
int count;
|
||||
bool allergens[ALLERGEN_COUNT];
|
||||
} allergen_list_t;
|
||||
|
||||
// We can choose macro or function
|
||||
#ifdef USE_ALLERGIC_TO_FUNCTION
|
||||
bool is_allergic_to(const allergen_t allergen, const uint32_t value);
|
||||
#else
|
||||
#define is_allergic_to(allerg, val) (!!((val) & (1 << (allerg))))
|
||||
#endif
|
||||
|
||||
allergen_list_t get_allergens(uint32_t value);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
51
c/beer-song/GNUmakefile
Normal file
51
c/beer-song/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o test.out
|
359
c/beer-song/README.md
Normal file
359
c/beer-song/README.md
Normal file
@@ -0,0 +1,359 @@
|
||||
# Beer Song
|
||||
|
||||
Recite the lyrics to that beloved classic, that field-trip favorite: 99 Bottles of Beer on the Wall.
|
||||
|
||||
Note that not all verses are identical.
|
||||
|
||||
```text
|
||||
99 bottles of beer on the wall, 99 bottles of beer.
|
||||
Take one down and pass it around, 98 bottles of beer on the wall.
|
||||
|
||||
98 bottles of beer on the wall, 98 bottles of beer.
|
||||
Take one down and pass it around, 97 bottles of beer on the wall.
|
||||
|
||||
97 bottles of beer on the wall, 97 bottles of beer.
|
||||
Take one down and pass it around, 96 bottles of beer on the wall.
|
||||
|
||||
96 bottles of beer on the wall, 96 bottles of beer.
|
||||
Take one down and pass it around, 95 bottles of beer on the wall.
|
||||
|
||||
95 bottles of beer on the wall, 95 bottles of beer.
|
||||
Take one down and pass it around, 94 bottles of beer on the wall.
|
||||
|
||||
94 bottles of beer on the wall, 94 bottles of beer.
|
||||
Take one down and pass it around, 93 bottles of beer on the wall.
|
||||
|
||||
93 bottles of beer on the wall, 93 bottles of beer.
|
||||
Take one down and pass it around, 92 bottles of beer on the wall.
|
||||
|
||||
92 bottles of beer on the wall, 92 bottles of beer.
|
||||
Take one down and pass it around, 91 bottles of beer on the wall.
|
||||
|
||||
91 bottles of beer on the wall, 91 bottles of beer.
|
||||
Take one down and pass it around, 90 bottles of beer on the wall.
|
||||
|
||||
90 bottles of beer on the wall, 90 bottles of beer.
|
||||
Take one down and pass it around, 89 bottles of beer on the wall.
|
||||
|
||||
89 bottles of beer on the wall, 89 bottles of beer.
|
||||
Take one down and pass it around, 88 bottles of beer on the wall.
|
||||
|
||||
88 bottles of beer on the wall, 88 bottles of beer.
|
||||
Take one down and pass it around, 87 bottles of beer on the wall.
|
||||
|
||||
87 bottles of beer on the wall, 87 bottles of beer.
|
||||
Take one down and pass it around, 86 bottles of beer on the wall.
|
||||
|
||||
86 bottles of beer on the wall, 86 bottles of beer.
|
||||
Take one down and pass it around, 85 bottles of beer on the wall.
|
||||
|
||||
85 bottles of beer on the wall, 85 bottles of beer.
|
||||
Take one down and pass it around, 84 bottles of beer on the wall.
|
||||
|
||||
84 bottles of beer on the wall, 84 bottles of beer.
|
||||
Take one down and pass it around, 83 bottles of beer on the wall.
|
||||
|
||||
83 bottles of beer on the wall, 83 bottles of beer.
|
||||
Take one down and pass it around, 82 bottles of beer on the wall.
|
||||
|
||||
82 bottles of beer on the wall, 82 bottles of beer.
|
||||
Take one down and pass it around, 81 bottles of beer on the wall.
|
||||
|
||||
81 bottles of beer on the wall, 81 bottles of beer.
|
||||
Take one down and pass it around, 80 bottles of beer on the wall.
|
||||
|
||||
80 bottles of beer on the wall, 80 bottles of beer.
|
||||
Take one down and pass it around, 79 bottles of beer on the wall.
|
||||
|
||||
79 bottles of beer on the wall, 79 bottles of beer.
|
||||
Take one down and pass it around, 78 bottles of beer on the wall.
|
||||
|
||||
78 bottles of beer on the wall, 78 bottles of beer.
|
||||
Take one down and pass it around, 77 bottles of beer on the wall.
|
||||
|
||||
77 bottles of beer on the wall, 77 bottles of beer.
|
||||
Take one down and pass it around, 76 bottles of beer on the wall.
|
||||
|
||||
76 bottles of beer on the wall, 76 bottles of beer.
|
||||
Take one down and pass it around, 75 bottles of beer on the wall.
|
||||
|
||||
75 bottles of beer on the wall, 75 bottles of beer.
|
||||
Take one down and pass it around, 74 bottles of beer on the wall.
|
||||
|
||||
74 bottles of beer on the wall, 74 bottles of beer.
|
||||
Take one down and pass it around, 73 bottles of beer on the wall.
|
||||
|
||||
73 bottles of beer on the wall, 73 bottles of beer.
|
||||
Take one down and pass it around, 72 bottles of beer on the wall.
|
||||
|
||||
72 bottles of beer on the wall, 72 bottles of beer.
|
||||
Take one down and pass it around, 71 bottles of beer on the wall.
|
||||
|
||||
71 bottles of beer on the wall, 71 bottles of beer.
|
||||
Take one down and pass it around, 70 bottles of beer on the wall.
|
||||
|
||||
70 bottles of beer on the wall, 70 bottles of beer.
|
||||
Take one down and pass it around, 69 bottles of beer on the wall.
|
||||
|
||||
69 bottles of beer on the wall, 69 bottles of beer.
|
||||
Take one down and pass it around, 68 bottles of beer on the wall.
|
||||
|
||||
68 bottles of beer on the wall, 68 bottles of beer.
|
||||
Take one down and pass it around, 67 bottles of beer on the wall.
|
||||
|
||||
67 bottles of beer on the wall, 67 bottles of beer.
|
||||
Take one down and pass it around, 66 bottles of beer on the wall.
|
||||
|
||||
66 bottles of beer on the wall, 66 bottles of beer.
|
||||
Take one down and pass it around, 65 bottles of beer on the wall.
|
||||
|
||||
65 bottles of beer on the wall, 65 bottles of beer.
|
||||
Take one down and pass it around, 64 bottles of beer on the wall.
|
||||
|
||||
64 bottles of beer on the wall, 64 bottles of beer.
|
||||
Take one down and pass it around, 63 bottles of beer on the wall.
|
||||
|
||||
63 bottles of beer on the wall, 63 bottles of beer.
|
||||
Take one down and pass it around, 62 bottles of beer on the wall.
|
||||
|
||||
62 bottles of beer on the wall, 62 bottles of beer.
|
||||
Take one down and pass it around, 61 bottles of beer on the wall.
|
||||
|
||||
61 bottles of beer on the wall, 61 bottles of beer.
|
||||
Take one down and pass it around, 60 bottles of beer on the wall.
|
||||
|
||||
60 bottles of beer on the wall, 60 bottles of beer.
|
||||
Take one down and pass it around, 59 bottles of beer on the wall.
|
||||
|
||||
59 bottles of beer on the wall, 59 bottles of beer.
|
||||
Take one down and pass it around, 58 bottles of beer on the wall.
|
||||
|
||||
58 bottles of beer on the wall, 58 bottles of beer.
|
||||
Take one down and pass it around, 57 bottles of beer on the wall.
|
||||
|
||||
57 bottles of beer on the wall, 57 bottles of beer.
|
||||
Take one down and pass it around, 56 bottles of beer on the wall.
|
||||
|
||||
56 bottles of beer on the wall, 56 bottles of beer.
|
||||
Take one down and pass it around, 55 bottles of beer on the wall.
|
||||
|
||||
55 bottles of beer on the wall, 55 bottles of beer.
|
||||
Take one down and pass it around, 54 bottles of beer on the wall.
|
||||
|
||||
54 bottles of beer on the wall, 54 bottles of beer.
|
||||
Take one down and pass it around, 53 bottles of beer on the wall.
|
||||
|
||||
53 bottles of beer on the wall, 53 bottles of beer.
|
||||
Take one down and pass it around, 52 bottles of beer on the wall.
|
||||
|
||||
52 bottles of beer on the wall, 52 bottles of beer.
|
||||
Take one down and pass it around, 51 bottles of beer on the wall.
|
||||
|
||||
51 bottles of beer on the wall, 51 bottles of beer.
|
||||
Take one down and pass it around, 50 bottles of beer on the wall.
|
||||
|
||||
50 bottles of beer on the wall, 50 bottles of beer.
|
||||
Take one down and pass it around, 49 bottles of beer on the wall.
|
||||
|
||||
49 bottles of beer on the wall, 49 bottles of beer.
|
||||
Take one down and pass it around, 48 bottles of beer on the wall.
|
||||
|
||||
48 bottles of beer on the wall, 48 bottles of beer.
|
||||
Take one down and pass it around, 47 bottles of beer on the wall.
|
||||
|
||||
47 bottles of beer on the wall, 47 bottles of beer.
|
||||
Take one down and pass it around, 46 bottles of beer on the wall.
|
||||
|
||||
46 bottles of beer on the wall, 46 bottles of beer.
|
||||
Take one down and pass it around, 45 bottles of beer on the wall.
|
||||
|
||||
45 bottles of beer on the wall, 45 bottles of beer.
|
||||
Take one down and pass it around, 44 bottles of beer on the wall.
|
||||
|
||||
44 bottles of beer on the wall, 44 bottles of beer.
|
||||
Take one down and pass it around, 43 bottles of beer on the wall.
|
||||
|
||||
43 bottles of beer on the wall, 43 bottles of beer.
|
||||
Take one down and pass it around, 42 bottles of beer on the wall.
|
||||
|
||||
42 bottles of beer on the wall, 42 bottles of beer.
|
||||
Take one down and pass it around, 41 bottles of beer on the wall.
|
||||
|
||||
41 bottles of beer on the wall, 41 bottles of beer.
|
||||
Take one down and pass it around, 40 bottles of beer on the wall.
|
||||
|
||||
40 bottles of beer on the wall, 40 bottles of beer.
|
||||
Take one down and pass it around, 39 bottles of beer on the wall.
|
||||
|
||||
39 bottles of beer on the wall, 39 bottles of beer.
|
||||
Take one down and pass it around, 38 bottles of beer on the wall.
|
||||
|
||||
38 bottles of beer on the wall, 38 bottles of beer.
|
||||
Take one down and pass it around, 37 bottles of beer on the wall.
|
||||
|
||||
37 bottles of beer on the wall, 37 bottles of beer.
|
||||
Take one down and pass it around, 36 bottles of beer on the wall.
|
||||
|
||||
36 bottles of beer on the wall, 36 bottles of beer.
|
||||
Take one down and pass it around, 35 bottles of beer on the wall.
|
||||
|
||||
35 bottles of beer on the wall, 35 bottles of beer.
|
||||
Take one down and pass it around, 34 bottles of beer on the wall.
|
||||
|
||||
34 bottles of beer on the wall, 34 bottles of beer.
|
||||
Take one down and pass it around, 33 bottles of beer on the wall.
|
||||
|
||||
33 bottles of beer on the wall, 33 bottles of beer.
|
||||
Take one down and pass it around, 32 bottles of beer on the wall.
|
||||
|
||||
32 bottles of beer on the wall, 32 bottles of beer.
|
||||
Take one down and pass it around, 31 bottles of beer on the wall.
|
||||
|
||||
31 bottles of beer on the wall, 31 bottles of beer.
|
||||
Take one down and pass it around, 30 bottles of beer on the wall.
|
||||
|
||||
30 bottles of beer on the wall, 30 bottles of beer.
|
||||
Take one down and pass it around, 29 bottles of beer on the wall.
|
||||
|
||||
29 bottles of beer on the wall, 29 bottles of beer.
|
||||
Take one down and pass it around, 28 bottles of beer on the wall.
|
||||
|
||||
28 bottles of beer on the wall, 28 bottles of beer.
|
||||
Take one down and pass it around, 27 bottles of beer on the wall.
|
||||
|
||||
27 bottles of beer on the wall, 27 bottles of beer.
|
||||
Take one down and pass it around, 26 bottles of beer on the wall.
|
||||
|
||||
26 bottles of beer on the wall, 26 bottles of beer.
|
||||
Take one down and pass it around, 25 bottles of beer on the wall.
|
||||
|
||||
25 bottles of beer on the wall, 25 bottles of beer.
|
||||
Take one down and pass it around, 24 bottles of beer on the wall.
|
||||
|
||||
24 bottles of beer on the wall, 24 bottles of beer.
|
||||
Take one down and pass it around, 23 bottles of beer on the wall.
|
||||
|
||||
23 bottles of beer on the wall, 23 bottles of beer.
|
||||
Take one down and pass it around, 22 bottles of beer on the wall.
|
||||
|
||||
22 bottles of beer on the wall, 22 bottles of beer.
|
||||
Take one down and pass it around, 21 bottles of beer on the wall.
|
||||
|
||||
21 bottles of beer on the wall, 21 bottles of beer.
|
||||
Take one down and pass it around, 20 bottles of beer on the wall.
|
||||
|
||||
20 bottles of beer on the wall, 20 bottles of beer.
|
||||
Take one down and pass it around, 19 bottles of beer on the wall.
|
||||
|
||||
19 bottles of beer on the wall, 19 bottles of beer.
|
||||
Take one down and pass it around, 18 bottles of beer on the wall.
|
||||
|
||||
18 bottles of beer on the wall, 18 bottles of beer.
|
||||
Take one down and pass it around, 17 bottles of beer on the wall.
|
||||
|
||||
17 bottles of beer on the wall, 17 bottles of beer.
|
||||
Take one down and pass it around, 16 bottles of beer on the wall.
|
||||
|
||||
16 bottles of beer on the wall, 16 bottles of beer.
|
||||
Take one down and pass it around, 15 bottles of beer on the wall.
|
||||
|
||||
15 bottles of beer on the wall, 15 bottles of beer.
|
||||
Take one down and pass it around, 14 bottles of beer on the wall.
|
||||
|
||||
14 bottles of beer on the wall, 14 bottles of beer.
|
||||
Take one down and pass it around, 13 bottles of beer on the wall.
|
||||
|
||||
13 bottles of beer on the wall, 13 bottles of beer.
|
||||
Take one down and pass it around, 12 bottles of beer on the wall.
|
||||
|
||||
12 bottles of beer on the wall, 12 bottles of beer.
|
||||
Take one down and pass it around, 11 bottles of beer on the wall.
|
||||
|
||||
11 bottles of beer on the wall, 11 bottles of beer.
|
||||
Take one down and pass it around, 10 bottles of beer on the wall.
|
||||
|
||||
10 bottles of beer on the wall, 10 bottles of beer.
|
||||
Take one down and pass it around, 9 bottles of beer on the wall.
|
||||
|
||||
9 bottles of beer on the wall, 9 bottles of beer.
|
||||
Take one down and pass it around, 8 bottles of beer on the wall.
|
||||
|
||||
8 bottles of beer on the wall, 8 bottles of beer.
|
||||
Take one down and pass it around, 7 bottles of beer on the wall.
|
||||
|
||||
7 bottles of beer on the wall, 7 bottles of beer.
|
||||
Take one down and pass it around, 6 bottles of beer on the wall.
|
||||
|
||||
6 bottles of beer on the wall, 6 bottles of beer.
|
||||
Take one down and pass it around, 5 bottles of beer on the wall.
|
||||
|
||||
5 bottles of beer on the wall, 5 bottles of beer.
|
||||
Take one down and pass it around, 4 bottles of beer on the wall.
|
||||
|
||||
4 bottles of beer on the wall, 4 bottles of beer.
|
||||
Take one down and pass it around, 3 bottles of beer on the wall.
|
||||
|
||||
3 bottles of beer on the wall, 3 bottles of beer.
|
||||
Take one down and pass it around, 2 bottles of beer on the wall.
|
||||
|
||||
2 bottles of beer on the wall, 2 bottles of beer.
|
||||
Take one down and pass it around, 1 bottle of beer on the wall.
|
||||
|
||||
1 bottle of beer on the wall, 1 bottle of beer.
|
||||
Take it down and pass it around, no more bottles of beer on the wall.
|
||||
|
||||
No more bottles of beer on the wall, no more bottles of beer.
|
||||
Go to the store and buy some more, 99 bottles of beer on the wall.
|
||||
```
|
||||
|
||||
## For bonus points
|
||||
|
||||
Did you get the tests passing and the code clean? If you want to, these
|
||||
are some additional things you could try:
|
||||
|
||||
* Remove as much duplication as you possibly can.
|
||||
* Optimize for readability, even if it means introducing duplication.
|
||||
* If you've removed all the duplication, do you have a lot of
|
||||
conditionals? Try replacing the conditionals with polymorphism, if it
|
||||
applies in this language. How readable is it?
|
||||
|
||||
Then please share your thoughts in a comment on the submission. Did this
|
||||
experiment make the code better? Worse? Did you learn anything from it?
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
Learn to Program by Chris Pine [http://pine.fm/LearnToProgram/?Chapter=06](http://pine.fm/LearnToProgram/?Chapter=06)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/beer-song/makefile
Normal file
37
c/beer-song/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
44
c/beer-song/src/beer_song.c
Normal file
44
c/beer-song/src/beer_song.c
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "beer_song.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static char *fmt1="%s bottle%s of beer on the wall, %s bottle%s of beer.\n" \
|
||||
"Take %s down and pass it around, %s bottle%s of beer on the wall.\n%s";
|
||||
static char *fmt2="%s bottle%s of beer on the wall, %s bottle%s of beer.\n" \
|
||||
"%sGo to the store and buy some more, %s bottle%s of beer on the wall.\n%s";
|
||||
|
||||
void recite(unsigned int start, unsigned int down, char *buffer)
|
||||
{
|
||||
char n1[16], n2[16];
|
||||
char *p=buffer;
|
||||
|
||||
while (down--) {
|
||||
sprintf(n1, "%d", start);
|
||||
sprintf(n2, "%d", start>1? start-1: 99);
|
||||
|
||||
p+=sprintf(p, start? fmt1: fmt2,
|
||||
start? n1: "No more", start==1? "": "s", start? n1: "no more",
|
||||
start==1? "": "s",
|
||||
start==1? "it": start? "one": "", start-1? n2: "no more",
|
||||
start==2? "": "s", down? "\n": "");
|
||||
start=start? start-1: 99;
|
||||
}
|
||||
}
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1;
|
||||
unsigned i, j;
|
||||
char buffer[1024];
|
||||
|
||||
for (; arg<ac-1; ++arg, ++arg) {
|
||||
i=atoi(av[arg]);
|
||||
j=atoi(av[arg+1]);
|
||||
recite(i, j, buffer);
|
||||
printf("recite(%d, %d):\n%s", i, j, buffer);
|
||||
}
|
||||
}
|
||||
#endif
|
18
c/beer-song/src/beer_song.h
Normal file
18
c/beer-song/src/beer_song.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef BEER_SONG_H
|
||||
#define BEER_SONG_H
|
||||
|
||||
void recite(unsigned int start_bottles, unsigned int take_down, char *buffer);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
51
c/binary-search/GNUmakefile
Normal file
51
c/binary-search/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o test.out
|
73
c/binary-search/README.md
Normal file
73
c/binary-search/README.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Binary Search
|
||||
|
||||
Implement a binary search algorithm.
|
||||
|
||||
Searching a sorted collection is a common task. A dictionary is a sorted
|
||||
list of word definitions. Given a word, one can find its definition. A
|
||||
telephone book is a sorted list of people's names, addresses, and
|
||||
telephone numbers. Knowing someone's name allows one to quickly find
|
||||
their telephone number and address.
|
||||
|
||||
If the list to be searched contains more than a few items (a dozen, say)
|
||||
a binary search will require far fewer comparisons than a linear search,
|
||||
but it imposes the requirement that the list be sorted.
|
||||
|
||||
In computer science, a binary search or half-interval search algorithm
|
||||
finds the position of a specified input value (the search "key") within
|
||||
an array sorted by key value.
|
||||
|
||||
In each step, the algorithm compares the search key value with the key
|
||||
value of the middle element of the array.
|
||||
|
||||
If the keys match, then a matching element has been found and its index,
|
||||
or position, is returned.
|
||||
|
||||
Otherwise, if the search key is less than the middle element's key, then
|
||||
the algorithm repeats its action on the sub-array to the left of the
|
||||
middle element or, if the search key is greater, on the sub-array to the
|
||||
right.
|
||||
|
||||
If the remaining array to be searched is empty, then the key cannot be
|
||||
found in the array and a special "not found" indication is returned.
|
||||
|
||||
A binary search halves the number of items to check with each iteration,
|
||||
so locating an item (or determining its absence) takes logarithmic time.
|
||||
A binary search is a dichotomic divide and conquer search algorithm.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
Wikipedia [http://en.wikipedia.org/wiki/Binary_search_algorithm](http://en.wikipedia.org/wiki/Binary_search_algorithm)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/binary-search/makefile
Normal file
37
c/binary-search/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
37
c/binary-search/src/binary_search.c
Normal file
37
c/binary-search/src/binary_search.c
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "binary_search.h"
|
||||
|
||||
const int *binary_search(int v, const int *a, size_t size)
|
||||
{
|
||||
size_t lo, hi, i;
|
||||
|
||||
/* early exclude invalid/trivial result: NULL/empty array, value off bounds
|
||||
*/
|
||||
if (!size || !a || v < *a || v > *(a+size-1))
|
||||
return NULL;
|
||||
for (lo=0, hi=size-1, i=hi/2; lo<hi && a[i]!=v; i=lo+(hi-lo)/2) {
|
||||
if (a[i] < v)
|
||||
lo=i+1;
|
||||
else
|
||||
hi=i-1;
|
||||
}
|
||||
return a[i]==v? a+i: NULL;
|
||||
}
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1, *res;
|
||||
int i, array[] = {1, 2, 3, 4, 6, 7, 8, 9 };
|
||||
size_t size = sizeof(array) / sizeof(array[0]);
|
||||
|
||||
for (; arg<ac; ++arg) {
|
||||
i=atoi(av[arg]);
|
||||
res=binary_search(i, array, size);
|
||||
printf("binary_search(%d)=%ld\n", i,
|
||||
res? res-array: -1);
|
||||
}
|
||||
}
|
||||
#endif
|
21
c/binary-search/src/binary_search.h
Normal file
21
c/binary-search/src/binary_search.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef BINARY_SEARCH_H
|
||||
#define BINARY_SEARCH_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
const int *binary_search(int value, const int *arr, size_t length);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
51
c/bob/GNUmakefile
Normal file
51
c/bob/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o test.out
|
54
c/bob/README.md
Normal file
54
c/bob/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Bob
|
||||
|
||||
Bob is a lackadaisical teenager. In conversation, his responses are very limited.
|
||||
|
||||
Bob answers 'Sure.' if you ask him a question, such as "How are you?".
|
||||
|
||||
He answers 'Whoa, chill out!' if you YELL AT HIM (in all capitals).
|
||||
|
||||
He answers 'Calm down, I know what I'm doing!' if you yell a question at him.
|
||||
|
||||
He says 'Fine. Be that way!' if you address him without actually saying
|
||||
anything.
|
||||
|
||||
He answers 'Whatever.' to anything else.
|
||||
|
||||
Bob's conversational partner is a purist when it comes to written communication and always follows normal rules regarding sentence punctuation in English.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
Inspired by the 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. [http://pine.fm/LearnToProgram/?Chapter=06](http://pine.fm/LearnToProgram/?Chapter=06)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/bob/makefile
Normal file
37
c/bob/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
40
c/bob/src/bob.c
Normal file
40
c/bob/src/bob.c
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <ctype.h>
|
||||
#include "bob.h"
|
||||
|
||||
char*answers[] = {
|
||||
"Whatever.",
|
||||
"Sure.",
|
||||
"Whoa, chill out!",
|
||||
"Calm down, I know what I'm doing!",
|
||||
"Fine. Be that way!"
|
||||
};
|
||||
|
||||
char *hey_bob(char *w)
|
||||
{
|
||||
int yell=2, question=0, empty=4, text=0;
|
||||
for (;*w; w++) {
|
||||
if (!isspace(*w)) {
|
||||
empty=0;
|
||||
if (isalpha(*w)) text=2;
|
||||
if (islower (*w)) yell=0;
|
||||
question=*w=='?'? 1: 0;
|
||||
}
|
||||
}
|
||||
return answers[(text&yell)|question|empty];
|
||||
}
|
||||
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
#include <stdio.h>
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1;
|
||||
|
||||
for (; arg<ac; ++arg) {
|
||||
printf("bob(%s)=%s\n", av[arg], hey_bob(av[arg]));
|
||||
}
|
||||
}
|
||||
#endif
|
18
c/bob/src/bob.h
Normal file
18
c/bob/src/bob.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef BOB_H
|
||||
#define BOB_H
|
||||
|
||||
char *hey_bob(char *greeting);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
51
c/circular-buffer/GNUmakefile
Normal file
51
c/circular-buffer/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o tests.out $(LIBS)
|
89
c/circular-buffer/README.md
Normal file
89
c/circular-buffer/README.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# Circular Buffer
|
||||
|
||||
A circular buffer, cyclic buffer or ring buffer is a data structure that
|
||||
uses a single, fixed-size buffer as if it were connected end-to-end.
|
||||
|
||||
A circular buffer first starts empty and of some predefined length. For
|
||||
example, this is a 7-element buffer:
|
||||
|
||||
[ ][ ][ ][ ][ ][ ][ ]
|
||||
|
||||
Assume that a 1 is written into the middle of the buffer (exact starting
|
||||
location does not matter in a circular buffer):
|
||||
|
||||
[ ][ ][ ][1][ ][ ][ ]
|
||||
|
||||
Then assume that two more elements are added — 2 & 3 — which get
|
||||
appended after the 1:
|
||||
|
||||
[ ][ ][ ][1][2][3][ ]
|
||||
|
||||
If two elements are then removed from the buffer, the oldest values
|
||||
inside the buffer are removed. The two elements removed, in this case,
|
||||
are 1 & 2, leaving the buffer with just a 3:
|
||||
|
||||
[ ][ ][ ][ ][ ][3][ ]
|
||||
|
||||
If the buffer has 7 elements then it is completely full:
|
||||
|
||||
[6][7][8][9][3][4][5]
|
||||
|
||||
When the buffer is full an error will be raised, alerting the client
|
||||
that further writes are blocked until a slot becomes free.
|
||||
|
||||
When the buffer is full, the client can opt to overwrite the oldest
|
||||
data with a forced write. In this case, two more elements — A & B —
|
||||
are added and they overwrite the 3 & 4:
|
||||
|
||||
[6][7][8][9][A][B][5]
|
||||
|
||||
3 & 4 have been replaced by A & B making 5 now the oldest data in the
|
||||
buffer. Finally, if two elements are removed then what would be
|
||||
returned is 5 & 6 yielding the buffer:
|
||||
|
||||
[ ][7][8][9][A][B][ ]
|
||||
|
||||
Because there is space available, if the client again uses overwrite
|
||||
to store C & D then the space where 5 & 6 were stored previously will
|
||||
be used not the location of 7 & 8. 7 is still the oldest element and
|
||||
the buffer is once again full.
|
||||
|
||||
[D][7][8][9][A][B][C]
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
Wikipedia [http://en.wikipedia.org/wiki/Circular_buffer](http://en.wikipedia.org/wiki/Circular_buffer)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/circular-buffer/makefile
Normal file
37
c/circular-buffer/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
75
c/circular-buffer/src/circular_buffer.c
Normal file
75
c/circular-buffer/src/circular_buffer.c
Normal file
@@ -0,0 +1,75 @@
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "circular_buffer.h"
|
||||
|
||||
#define INC(v, size) {if (++v==size) v=0;}
|
||||
|
||||
circular_buffer_t *new_circular_buffer(size_t size)
|
||||
{
|
||||
circular_buffer_t *head = NULL;
|
||||
|
||||
if (size > 0) {
|
||||
if ((head=malloc(sizeof(*head)))) {
|
||||
clear_buffer(head);
|
||||
head->size = size;
|
||||
/* we could have only 1 alloc, I just prefer this double alloc
|
||||
*/
|
||||
if (!(head->buf = calloc(size, sizeof(buffer_value_t)))) {
|
||||
free(head);
|
||||
head = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return head;
|
||||
}
|
||||
|
||||
int do_write(circular_buffer_t *b, buffer_value_t v, int f)
|
||||
{
|
||||
if (!f && b->used == b->size) {
|
||||
errno = ENOBUFS;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
b->buf[b->head] = v;
|
||||
INC(b->head, b->size);
|
||||
if (f && b->used == b->size) /* overwrite and full */
|
||||
INC(b->tail, b->size);
|
||||
if (b->used < b->size) /* normal write */
|
||||
b->used++;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int read(circular_buffer_t *b, buffer_value_t *p)
|
||||
{
|
||||
if (!b->used) {
|
||||
errno = ENODATA;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
b->used--;
|
||||
*p = b->buf[b->tail];
|
||||
INC(b->tail, b->size);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int clear_buffer(circular_buffer_t *b)
|
||||
{
|
||||
b->head = 0;
|
||||
b->tail = 0;
|
||||
b->used = 0;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void delete_buffer(circular_buffer_t *b) {
|
||||
free(b->buf);
|
||||
free(b);
|
||||
}
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
/* not done for circular buffer : simple exercise, with difficult testing */
|
||||
}
|
||||
#endif
|
41
c/circular-buffer/src/circular_buffer.h
Normal file
41
c/circular-buffer/src/circular_buffer.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef CIRCULAR_BUFFER_H
|
||||
#define CIRCULAR_BUFFER_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef char buffer_value_t;
|
||||
|
||||
/* used and tail are redundant, but allow easier code (and maybe easier
|
||||
* to read ?).
|
||||
*/
|
||||
typedef struct circular_buffer {
|
||||
int head;
|
||||
int tail;
|
||||
int used;
|
||||
int size;
|
||||
buffer_value_t *buf;
|
||||
} circular_buffer_t;
|
||||
|
||||
extern circular_buffer_t *new_circular_buffer(size_t size);
|
||||
extern int do_write(circular_buffer_t *buffer, buffer_value_t value, int force);
|
||||
extern int read(circular_buffer_t *buffer, buffer_value_t *retval);
|
||||
extern int clear_buffer(circular_buffer_t *buffer);
|
||||
extern void delete_buffer(circular_buffer_t *buffer);
|
||||
|
||||
#define write(buffer, value) do_write((buffer), (value), 0)
|
||||
#define overwrite(buffer, value) do_write((buffer), (value), 1)
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
51
c/complex-numbers/GNUmakefile
Normal file
51
c/complex-numbers/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o test.out
|
67
c/complex-numbers/README.md
Normal file
67
c/complex-numbers/README.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Complex Numbers
|
||||
|
||||
A complex number is a number in the form `a + b * i` where `a` and `b` are real and `i` satisfies `i^2 = -1`.
|
||||
|
||||
`a` is called the real part and `b` is called the imaginary part of `z`.
|
||||
The conjugate of the number `a + b * i` is the number `a - b * i`.
|
||||
The absolute value of a complex number `z = a + b * i` is a real number `|z| = sqrt(a^2 + b^2)`. The square of the absolute value `|z|^2` is the result of multiplication of `z` by its complex conjugate.
|
||||
|
||||
The sum/difference of two complex numbers involves adding/subtracting their real and imaginary parts separately:
|
||||
`(a + i * b) + (c + i * d) = (a + c) + (b + d) * i`,
|
||||
`(a + i * b) - (c + i * d) = (a - c) + (b - d) * i`.
|
||||
|
||||
Multiplication result is by definition
|
||||
`(a + i * b) * (c + i * d) = (a * c - b * d) + (b * c + a * d) * i`.
|
||||
|
||||
The reciprocal of a non-zero complex number is
|
||||
`1 / (a + i * b) = a/(a^2 + b^2) - b/(a^2 + b^2) * i`.
|
||||
|
||||
Dividing a complex number `a + i * b` by another `c + i * d` gives:
|
||||
`(a + i * b) / (c + i * d) = (a * c + b * d)/(c^2 + d^2) + (b * c - a * d)/(c^2 + d^2) * i`.
|
||||
|
||||
Raising e to a complex exponent can be expressed as `e^(a + i * b) = e^a * e^(i * b)`, the last term of which is given by Euler's formula `e^(i * b) = cos(b) + i * sin(b)`.
|
||||
|
||||
Implement the following operations:
|
||||
- addition, subtraction, multiplication and division of two complex numbers,
|
||||
- conjugate, absolute value, exponent of a given complex number.
|
||||
|
||||
|
||||
Assume the programming language you are using does not have an implementation of complex numbers.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
Wikipedia [https://en.wikipedia.org/wiki/Complex_number](https://en.wikipedia.org/wiki/Complex_number)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
38
c/complex-numbers/makefile
Normal file
38
c/complex-numbers/makefile
Normal file
@@ -0,0 +1,38 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
CFLAGS += -DUNITY_INCLUDE_DOUBLE
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
96
c/complex-numbers/src/complex_numbers.c
Normal file
96
c/complex-numbers/src/complex_numbers.c
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "complex_numbers.h"
|
||||
|
||||
#ifdef USE_COMPLEX_FUNCTIONS
|
||||
|
||||
complex_t c_add(complex_t a, complex_t b)
|
||||
{
|
||||
return (complex_t) {
|
||||
.real = a.real+b.real,
|
||||
.imag = a.imag+b.imag
|
||||
};
|
||||
}
|
||||
|
||||
complex_t c_sub(complex_t a, complex_t b)
|
||||
{
|
||||
return (complex_t) {
|
||||
.real = a.real-b.real,
|
||||
.imag = a.imag-b.imag
|
||||
};
|
||||
}
|
||||
|
||||
complex_t c_mul(complex_t a, complex_t b)
|
||||
{
|
||||
return (complex_t) {
|
||||
.real = a.real*b.real - a.imag*b.imag,
|
||||
.imag = a.imag*b.real + a.real*b.imag,
|
||||
};
|
||||
}
|
||||
|
||||
complex_t c_div(complex_t a, complex_t b)
|
||||
{
|
||||
double d = b.real*b.real + b.imag*b.imag;
|
||||
return (complex_t) {
|
||||
.real = (a.real*b.real + a.imag*b.imag)/d,
|
||||
.imag = (a.imag*b.real - a.real*b.imag)/d
|
||||
};
|
||||
}
|
||||
|
||||
double c_abs(complex_t x)
|
||||
{
|
||||
return sqrt(x.real*x.real + x.imag*x.imag);
|
||||
}
|
||||
|
||||
complex_t c_conjugate(complex_t x)
|
||||
{
|
||||
return (complex_t) {
|
||||
.real = x.real,
|
||||
.imag = -x.imag
|
||||
};
|
||||
}
|
||||
|
||||
double c_real(complex_t x)
|
||||
{
|
||||
return x.real;
|
||||
}
|
||||
|
||||
double c_imag(complex_t x)
|
||||
{
|
||||
return x.imag;
|
||||
}
|
||||
|
||||
complex_t c_exp(complex_t x)
|
||||
{
|
||||
return (complex_t) {
|
||||
.real = exp(x.real)*cos(x.imag),
|
||||
.imag = exp(x.real)*sin(x.imag)
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1;
|
||||
complex_t c1, c2, c3;
|
||||
|
||||
for (; arg<ac-3; ++arg, ++arg) {
|
||||
c1.real=atof(av[arg]);
|
||||
c1.imag=atof(av[arg+1]);
|
||||
|
||||
c2.real=atof(av[arg+2]);
|
||||
c2.imag=atof(av[arg+3]);
|
||||
c3 = c_add(c1, c2);
|
||||
printf("(%f + %fi) + (%f + %fi) = (%f + %fi)\n",
|
||||
c1.real, c1.imag,
|
||||
c2.real, c2.imag,
|
||||
c3.real, c3.imag);
|
||||
}
|
||||
}
|
||||
#endif
|
70
c/complex-numbers/src/complex_numbers.h
Normal file
70
c/complex-numbers/src/complex_numbers.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef _COMPLEX_NUMBERS_H_
|
||||
#define _COMPLEX_NUMBERS_H_
|
||||
#include <math.h>
|
||||
|
||||
typedef struct {
|
||||
double real;
|
||||
double imag;
|
||||
} complex_t;
|
||||
|
||||
/* default is to use macros */
|
||||
#ifdef USE_COMPLEX_FUNCTIONS
|
||||
|
||||
complex_t c_add(complex_t a, complex_t b);
|
||||
complex_t c_sub(complex_t a, complex_t b);
|
||||
complex_t c_mul(complex_t a, complex_t b);
|
||||
complex_t c_div(complex_t a, complex_t b);
|
||||
double c_abs(complex_t x);
|
||||
complex_t c_conjugate(complex_t x);
|
||||
double c_real(complex_t x);
|
||||
double c_imag(complex_t x);
|
||||
complex_t c_exp(complex_t x);
|
||||
|
||||
#else
|
||||
|
||||
#define c_add(a,b) (complex_t) { \
|
||||
(a).real+(b).real, \
|
||||
(a).imag+(b).imag }
|
||||
|
||||
#define c_sub(a,b) (complex_t) { \
|
||||
(a).real-(b).real, \
|
||||
(a).imag-(b).imag }
|
||||
|
||||
#define c_mul(a,b) (complex_t) { \
|
||||
(a).real*(b).real - (a).imag*(b).imag, \
|
||||
(a).imag*(b).real + (a).real*(b).imag }
|
||||
|
||||
#define c_div(a,b) (complex_t) { \
|
||||
((a).real*(b).real + (a).imag*(b).imag)/ \
|
||||
((b).real*(b).real + (b).imag*(b).imag), \
|
||||
((a).imag*(b).real - (a).real*(b).imag)/ \
|
||||
((b).real*(b).real + (b).imag*(b).imag) }
|
||||
|
||||
#define c_exp(x) (complex_t) { \
|
||||
exp((x).real) * cos((x).imag), \
|
||||
exp((x).real) * sin((x).imag) }
|
||||
|
||||
#define c_abs(x) { sqrt((x).real*(x).real + (x).imag*(x).imag) }
|
||||
|
||||
#define c_conjugate(x) (complex_t){ (x).real, -(x).imag }
|
||||
|
||||
#define c_real(x) (x).real
|
||||
|
||||
#define c_imag(x) (x).imag
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
51
c/grade-school/GNUmakefile
Normal file
51
c/grade-school/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o test.out
|
76
c/grade-school/README.md
Normal file
76
c/grade-school/README.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Grade School
|
||||
|
||||
Given students' names along with the grade that they are in, create a roster
|
||||
for the school.
|
||||
|
||||
In the end, you should be able to:
|
||||
|
||||
- Add a student's name to the roster for a grade
|
||||
- "Add Jim to grade 2."
|
||||
- "OK."
|
||||
- Get a list of all students enrolled in a grade
|
||||
- "Which students are in grade 2?"
|
||||
- "We've only got Jim just now."
|
||||
- Get a sorted list of all students in all grades. Grades should sort
|
||||
as 1, 2, 3, etc., and students within a grade should be sorted
|
||||
alphabetically by name.
|
||||
- "Who all is enrolled in school right now?"
|
||||
- "Let me think. We have
|
||||
Anna, Barb, and Charlie in grade 1,
|
||||
Alex, Peter, and Zoe in grade 2
|
||||
and Jim in grade 5.
|
||||
So the answer is: Anna, Barb, Charlie, Alex, Peter, Zoe and Jim"
|
||||
|
||||
Note that all our students only have one name. (It's a small town, what
|
||||
do you want?)
|
||||
|
||||
## For bonus points
|
||||
|
||||
Did you get the tests passing and the code clean? If you want to, these
|
||||
are some additional things you could try:
|
||||
|
||||
- If you're working in a language with mutable data structures and your
|
||||
implementation allows outside code to mutate the school's internal DB
|
||||
directly, see if you can prevent this. Feel free to introduce additional
|
||||
tests.
|
||||
|
||||
Then please share your thoughts in a comment on the submission. Did this
|
||||
experiment make the code better? Worse? Did you learn anything from it?
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
A pairing session with Phil Battos at gSchool [http://gschool.it](http://gschool.it)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/grade-school/makefile
Normal file
37
c/grade-school/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
83
c/grade-school/src/grade_school.c
Normal file
83
c/grade-school/src/grade_school.c
Normal file
@@ -0,0 +1,83 @@
|
||||
#include "grade_school.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define STD(i) roster.students[i]
|
||||
#define NAME(i) roster.students[i].name
|
||||
#define GRADE(i) roster.students[i].grade
|
||||
|
||||
static roster_t roster;
|
||||
|
||||
void clear_roster()
|
||||
{
|
||||
roster.count=0;
|
||||
}
|
||||
|
||||
/* testing program expects bool here, but I prefer to return students count,
|
||||
* it makes more sense for me.
|
||||
*/
|
||||
int add_student(const char *s, const uint8_t g)
|
||||
{
|
||||
int c=roster.count, i;
|
||||
|
||||
if (c >= MAX_STUDENTS)
|
||||
return 0;
|
||||
// find correct place to insert name
|
||||
for (i=0; i<c && (GRADE(i)<g || (GRADE(i)==g && strcmp(s, NAME(i))>0)); ++i)
|
||||
;
|
||||
for (int j=c-1; j>=i; --j) /* move rest to right */
|
||||
STD(j+1)=STD(j);
|
||||
NAME(i)=s; /* insert new name */
|
||||
GRADE(i)=g;
|
||||
|
||||
return ++roster.count;
|
||||
}
|
||||
|
||||
/* to avoid this everytime, we could build up one roster per grade while
|
||||
* adding students, but really overkill here.
|
||||
*/
|
||||
roster_t get_grade(const uint8_t g)
|
||||
{
|
||||
roster_t r;
|
||||
unsigned i, j;
|
||||
|
||||
for (i=0, j=0; i<roster.count && GRADE(i)<=g; ++i) {
|
||||
if (GRADE(i)==g)
|
||||
r.students[j++]=STD(i);
|
||||
}
|
||||
r.count=j;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
roster_t get_roster()
|
||||
{
|
||||
return roster;
|
||||
}
|
||||
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
static void print_roster()
|
||||
{
|
||||
unsigned i;
|
||||
printf("======== roster size: %lu\n", roster.count);
|
||||
for (i=0; i<roster.count; ++i)
|
||||
printf("roster(%02d): [%d]%s\n", i, GRADE(i), NAME(i));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1;
|
||||
uint8_t i;
|
||||
|
||||
for (; arg<ac-1; ++arg, ++arg) {
|
||||
i=atoi(av[arg]);
|
||||
add_student(av[arg+1], i);
|
||||
}
|
||||
print_roster();
|
||||
}
|
||||
#endif
|
36
c/grade-school/src/grade_school.h
Normal file
36
c/grade-school/src/grade_school.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef GRADE_SCHOOL_H
|
||||
#define GRADE_SCHOOL_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAX_STUDENTS 20
|
||||
|
||||
typedef struct student_s {
|
||||
uint8_t grade;
|
||||
const char *name;
|
||||
} student_t;
|
||||
|
||||
typedef struct {
|
||||
size_t count;
|
||||
student_t students[MAX_STUDENTS];
|
||||
} roster_t;
|
||||
|
||||
void clear_roster(void);
|
||||
int add_student(const char *student, const uint8_t grade);
|
||||
roster_t get_grade(const uint8_t grade);
|
||||
roster_t get_roster(void);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -1,14 +1,5 @@
|
||||
#include "hamming.h"
|
||||
|
||||
/* Note: For explanation on section below, see 'GNUfilename' included in
|
||||
* link below :
|
||||
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
/* test does not include invalid input, but it should, as the subject is
|
||||
* about DNA sequence, not ASCII chars sequence :-)
|
||||
* exercism test needs only:
|
||||
@@ -16,22 +7,25 @@
|
||||
*/
|
||||
#define V(p) (*(p)=='A' || *(p)=='C' || *(p)=='G' || *(p)=='T')
|
||||
|
||||
int compute(const char *lhs, const char *rhs)
|
||||
int compute(const char *l, const char *r)
|
||||
{
|
||||
int res=0;
|
||||
const char *l=lhs, *r=rhs;
|
||||
|
||||
if (!l || !r)
|
||||
return -1;
|
||||
for (; V(l) && V(r); ++l, ++r) {
|
||||
for (; V(l) && V(r); ++l, ++r)
|
||||
if (*l != *r)
|
||||
res++;
|
||||
}
|
||||
return *r || *l? -1: res;
|
||||
return *l || *r? -1: res;
|
||||
}
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
if (ac==3) {
|
||||
|
@@ -3,9 +3,8 @@
|
||||
|
||||
int compute(const char *lhs, const char *rhs);
|
||||
|
||||
/* Note: For explanation on section below, see 'GNUfilename' included in
|
||||
* link below :
|
||||
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
|
51
c/leap/GNUmakefile
Normal file
51
c/leap/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o test.out
|
62
c/leap/README.md
Normal file
62
c/leap/README.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Leap
|
||||
|
||||
Given a year, report if it is a leap year.
|
||||
|
||||
The tricky thing here is that a leap year in the Gregorian calendar occurs:
|
||||
|
||||
```text
|
||||
on every year that is evenly divisible by 4
|
||||
except every year that is evenly divisible by 100
|
||||
unless the year is also evenly divisible by 400
|
||||
```
|
||||
|
||||
For example, 1997 is not a leap year, but 1996 is. 1900 is not a leap
|
||||
year, but 2000 is.
|
||||
|
||||
## Notes
|
||||
|
||||
Though our exercise adopts some very simple rules, there is more to
|
||||
learn!
|
||||
|
||||
For a delightful, four minute explanation of the whole leap year
|
||||
phenomenon, go watch [this youtube video][video].
|
||||
|
||||
[video]: http://www.youtube.com/watch?v=xX96xng7sAE
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
JavaRanch Cattle Drive, exercise 3 [http://www.javaranch.com/leap.jsp](http://www.javaranch.com/leap.jsp)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/leap/makefile
Normal file
37
c/leap/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
24
c/leap/src/leap.c
Normal file
24
c/leap/src/leap.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "leap.h"
|
||||
|
||||
/* already dont in meetup exercise */
|
||||
bool leap_year(int y)
|
||||
{
|
||||
return ((y % 4) ||
|
||||
(y % 400 && !(y % 100)))? false: true;
|
||||
}
|
||||
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1, i;
|
||||
|
||||
for (; arg<ac; ++arg) {
|
||||
i=atoi(av[arg]);
|
||||
printf("leap_year(%d)=%d\n", i, leap_year(i));
|
||||
}
|
||||
}
|
||||
#endif
|
20
c/leap/src/leap.h
Normal file
20
c/leap/src/leap.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef LEAP_H
|
||||
#define LEAP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool leap_year(int year);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
56
c/linked-list/GNUmakefile
Normal file
56
c/linked-list/GNUmakefile
Normal file
@@ -0,0 +1,56 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# 1) copy it into exercise directory
|
||||
# 2) add ex.h to exercise include file
|
||||
# 3) add ex.c to exercise source code, and create a suitable main function
|
||||
# 4) use make with one of the following targets :
|
||||
# all: compile and run all predefined tests.
|
||||
# nowarn: compile with no -Werror, and run all predefined tests
|
||||
# debug: compile with -DDEBUG and run all predefined tests
|
||||
# mem: perform memcheck with all tests enabled
|
||||
# unit: build standalone (unit) bimary
|
||||
# unitnowarn: build standalone (unit) binary with -Werror disabled
|
||||
# unitdebug: build standalone binary with -DDEBUG
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all nowarn debug mem unit unitnowarn unitdebug standalone
|
||||
|
||||
default: all
|
||||
|
||||
ALLSOURCES:=$(wildcard ./*.c)
|
||||
TESTSOURCES:=$(wildcard ./test_*.c)
|
||||
SRC:=$(filter-out $(TESTSOURCES),$(ALLSOURCES))
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
nowarn: CFLAGS:=$(filter-out -Werror,$(CFLAGS))
|
||||
nowarn: clean all
|
||||
|
||||
debug: CFLAGS+=-DDEBUG
|
||||
debug: all
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unitnowarn: CFLAGS:=$(filter-out -Werror,$(CFLAGS))
|
||||
unitnowarn: clean unit
|
||||
|
||||
unitdebug: CFLAGS+=-DDEBUG
|
||||
unitdebug: clean unit
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: *.c *.h
|
||||
$(CC) $(CFLAGS) $(SRC) -o tests.out $(LIBS)
|
63
c/linked-list/HELP.md
Normal file
63
c/linked-list/HELP.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test` task.
|
||||
|
||||
```console
|
||||
$ make test
|
||||
```
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the test to fail.
|
||||
Then write just enough code to get the test to pass.
|
||||
Once you've done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your implementation for readability and expressiveness and then go on to the next test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own low-level algorithms or facilities by hand.
|
||||
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit linked_list.c linked_list.h` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [C track's documentation](https://exercism.org/docs/tracks/c)
|
||||
- [Exercism's support channel on gitter](https://gitter.im/exercism/support)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
Make sure you have read the "Guides" section of the [C track][c-track] on the Exercism site.
|
||||
This covers the basic information on setting up the development environment expected by the exercises.
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
|
||||
If you are struggling with a particular exercise, it is possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
## Resources
|
||||
|
||||
To get help if having trouble, you can use the following resources:
|
||||
|
||||
- [StackOverflow][] can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
- [CPPReference][] can be used to look up information on C concepts, operators, types, standard library functions and more.
|
||||
- [TutorialsPoint][] has similar content as CPPReference in its C programming section.
|
||||
- [The C Programming][K&R] book by K&R is the original source of the language and is still useful today.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[stackoverflow]: http://stackoverflow.com/questions/tagged/c
|
||||
[cppreference]: https://en.cppreference.com/w/c
|
||||
[tutorialspoint]: https://www.tutorialspoint.com/cprogramming/
|
||||
[K&R]: https://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628/
|
50
c/linked-list/README.md
Normal file
50
c/linked-list/README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Linked List
|
||||
|
||||
Welcome to Linked List on Exercism's C Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
Implement a doubly linked list.
|
||||
|
||||
Like an array, a linked list is a simple linear data structure. Several
|
||||
common data types can be implemented using linked lists, like queues,
|
||||
stacks, and associative arrays.
|
||||
|
||||
A linked list is a collection of data elements called *nodes*. In a
|
||||
*singly linked list* each node holds a value and a link to the next node.
|
||||
In a *doubly linked list* each node also holds a link to the previous
|
||||
node.
|
||||
|
||||
You will write an implementation of a doubly linked list. Implement a
|
||||
Node to hold a value and pointers to the next and previous nodes. Then
|
||||
implement a List which holds references to the first and last node and
|
||||
offers an array-like interface for adding and removing items:
|
||||
|
||||
* `push` (*insert value at back*);
|
||||
* `pop` (*remove value at back*);
|
||||
* `shift` (*remove value at front*).
|
||||
* `unshift` (*insert value at front*);
|
||||
|
||||
To keep your implementation simple, the tests will not cover error
|
||||
conditions. Specifically: `pop` or `shift` will never be called on an
|
||||
empty list.
|
||||
|
||||
If you want to know more about linked lists, check [Wikipedia](https://en.wikipedia.org/wiki/Linked_list).
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @wolf99
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @patricksjackson
|
||||
- @QLaille
|
||||
- @ryanplusplus
|
||||
- @siebenschlaefer
|
||||
|
||||
### Based on
|
||||
|
||||
Classic computer science topic
|
45
c/linked-list/br-common.h
Normal file
45
c/linked-list/br-common.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef __BR_COMMON_H
|
||||
#define __BR_COMMON_H
|
||||
|
||||
/* ${LINUX_SRC}/include/linux/compiler_attributes.h, around line 30
|
||||
*
|
||||
* __has_attribute is supported on gcc >= 5, clang >= 2.9 and icc >= 17.
|
||||
* For other compilers, simple implementation (for __falltrough__ only)
|
||||
*/
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) __GCC4_has_attribute_##x
|
||||
# define __GCC4_has_attribute___assume_aligned__ (__GNUC_MINOR__ >= 9)
|
||||
# define __GCC4_has_attribute___copy__ 0
|
||||
# define __GCC4_has_attribute___designated_init__ 0
|
||||
# define __GCC4_has_attribute___externally_visible__ 1
|
||||
# define __GCC4_has_attribute___no_caller_saved_registers__ 0
|
||||
# define __GCC4_has_attribute___noclone__ 1
|
||||
# define __GCC4_has_attribute___nonstring__ 0
|
||||
# define __GCC4_has_attribute___no_sanitize_address__ (__GNUC_MINOR__ >= 8)
|
||||
# define __GCC4_has_attribute___no_sanitize_undefined__ (__GNUC_MINOR__ >= 9)
|
||||
# define __GCC4_has_attribute___fallthrough__ 0
|
||||
# define __GCC4_has_attribute___fallthrough__ 0
|
||||
#endif
|
||||
|
||||
/* ${LINUX_SRC}/include/linux/compiler_attributes.h, around line 200
|
||||
*/
|
||||
#if __has_attribute(__fallthrough__)
|
||||
# define fallthrough __attribute__((__fallthrough__))
|
||||
#else
|
||||
# define fallthrough do {} while (0) /* fallthrough */
|
||||
#endif
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef TESTALL
|
||||
# undef TEST_IGNORE
|
||||
# define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif /* __BR_COMMON_H */
|
138
c/linked-list/linked_list.c
Normal file
138
c/linked-list/linked_list.c
Normal file
@@ -0,0 +1,138 @@
|
||||
#include <malloc.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "linked_list.h"
|
||||
|
||||
/* How it works :
|
||||
*
|
||||
* The usual way to use linked lists is to have a list_head whith
|
||||
* 'next' pointing to first node, and 'prev' pointing to last node.
|
||||
* Each node has also 'prev' and 'next' pointers.
|
||||
*
|
||||
* Here, list_head points to the node own list_head structure,
|
||||
* and each node list_head points to next/previous node list_head.
|
||||
*
|
||||
* Advantage: We don't need to manipulate the pointers, all lists
|
||||
* use the same code, independently of the object (node) structure.
|
||||
*/
|
||||
struct list_node {
|
||||
ll_data_t data;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/* duplicate of list_head struct
|
||||
*/
|
||||
struct list {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
/* constructs a new (empty) list
|
||||
*/
|
||||
struct list *list_create()
|
||||
{
|
||||
struct list_head *list;
|
||||
|
||||
if (!(list=malloc(sizeof (*list))))
|
||||
return NULL;
|
||||
INIT_LIST_HEAD(list);
|
||||
return (struct list *) list;
|
||||
}
|
||||
|
||||
/* counts the items on a list
|
||||
*/
|
||||
size_t list_count(const struct list *list_head)
|
||||
{
|
||||
size_t len = 0;
|
||||
struct list_head *p;
|
||||
|
||||
list_for_each(p, (struct list_head *)list_head)
|
||||
len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* inserts item at back of a list
|
||||
*/
|
||||
void list_push(const struct list *list, const ll_data_t item_data)
|
||||
{
|
||||
struct list_node *p;
|
||||
|
||||
if ((p=malloc(sizeof(*p)))) {
|
||||
p->data = item_data;
|
||||
list_add_tail(&p->list, (struct list_head*)list);
|
||||
}
|
||||
}
|
||||
|
||||
/* deletes an element
|
||||
*/
|
||||
static ll_data_t _list_del(const struct list_head *list)
|
||||
{
|
||||
struct list_node *node;
|
||||
ll_data_t data;
|
||||
|
||||
node = list_entry(list, struct list_node, list);
|
||||
data = node->data;
|
||||
list_del(&node->list);
|
||||
free(node);
|
||||
return data;
|
||||
}
|
||||
|
||||
/* removes item from back of a list
|
||||
*/
|
||||
ll_data_t list_pop(const struct list *list)
|
||||
{
|
||||
return list_empty((struct list_head*)list) ? -1 : _list_del(list->prev);
|
||||
}
|
||||
|
||||
/* inserts item at front of a list
|
||||
*/
|
||||
void list_unshift(const struct list *list, const ll_data_t item_data)
|
||||
{
|
||||
struct list_node *p;
|
||||
|
||||
if ((p=malloc(sizeof(*p)))) {
|
||||
p->data = item_data;
|
||||
list_add(&p->list, (struct list_head*)list);
|
||||
}
|
||||
}
|
||||
|
||||
/* removes item from front of a list
|
||||
*/
|
||||
ll_data_t list_shift(const struct list *list)
|
||||
{
|
||||
return list_empty((struct list_head*)list) ? -1 : _list_del(list->next);
|
||||
}
|
||||
|
||||
/* finds a element that matches data
|
||||
*/
|
||||
static struct list_node *_node_find(const struct list *list, const ll_data_t data)
|
||||
{
|
||||
struct list_node *p;
|
||||
|
||||
list_for_each_entry(p, (struct list_head *)list, list) {
|
||||
if (p->data == data)
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* deletes a node that holds the matching data
|
||||
*/
|
||||
void list_delete(const struct list *list, const ll_data_t data)
|
||||
{
|
||||
struct list_node *p;
|
||||
|
||||
if ((p = _node_find(list, data)))
|
||||
_list_del(&p->list);
|
||||
}
|
||||
|
||||
/* destroys an entire list
|
||||
* list will be a dangling pointer after calling this method on it
|
||||
*/
|
||||
void list_destroy(struct list *list)
|
||||
{
|
||||
struct list_head *cur, *tmp;
|
||||
|
||||
list_for_each_safe(cur, tmp, (struct list_head *)list)
|
||||
_list_del(cur);
|
||||
free(list);
|
||||
}
|
36
c/linked-list/linked_list.h
Normal file
36
c/linked-list/linked_list.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef LINKED_LIST_H
|
||||
#define LINKED_LIST_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef int ll_data_t;
|
||||
struct list;
|
||||
|
||||
// constructs a new (empty) list
|
||||
struct list *list_create(void);
|
||||
|
||||
// counts the items on a list
|
||||
size_t list_count(const struct list *list);
|
||||
|
||||
// inserts item at back of a list
|
||||
void list_push(const struct list *list, const ll_data_t item_data);
|
||||
|
||||
// removes item from back of a list
|
||||
ll_data_t list_pop(const struct list *list);
|
||||
|
||||
// inserts item at front of a list
|
||||
void list_unshift(const struct list *list, const ll_data_t item_data);
|
||||
|
||||
// removes item from front of a list
|
||||
ll_data_t list_shift(const struct list *list);
|
||||
|
||||
// deletes a node that holds the matching data
|
||||
void list_delete(const struct list *list, const ll_data_t data);
|
||||
|
||||
// destroys an entire list
|
||||
// list will be a dangling pointer after calling this method on it
|
||||
void list_destroy(struct list *list);
|
||||
|
||||
#endif
|
||||
|
||||
#include "br-common.h"
|
229
c/linked-list/list.h
Normal file
229
c/linked-list/list.h
Normal file
@@ -0,0 +1,229 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
/* stripped down version of my adaptation of Linux kernel lists management :
|
||||
* https://github.com/braoult/Tools/blob/master/C/list.h
|
||||
*/
|
||||
#ifndef __LIST_H
|
||||
#define __LIST_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/************ originally in <include/linux/types.h> */
|
||||
struct list_head {
|
||||
struct list_head *next, *prev;
|
||||
};
|
||||
|
||||
/************ originally in <include/linux/poison.h> */
|
||||
#define LIST_POISON1 ((void *) 0x100)
|
||||
#define LIST_POISON2 ((void *) 0x122)
|
||||
|
||||
/************ originally in <include/linux/kernel.h> */
|
||||
#define container_of(ptr, type, member) \
|
||||
((type *)((char *)(ptr) - offsetof(type, member)))
|
||||
|
||||
/*
|
||||
* Circular doubly linked list implementation.
|
||||
*
|
||||
* Some of the internal functions ("__xxx") are useful when
|
||||
* manipulating whole lists rather than single entries, as
|
||||
* sometimes we already know the next/prev entries and we can
|
||||
* generate better code by using them directly rather than
|
||||
* using the generic single-entry routines.
|
||||
*/
|
||||
|
||||
/**
|
||||
* INIT_LIST_HEAD - Initialize a list_head structure
|
||||
* @list: list_head structure to be initialized.
|
||||
*
|
||||
* Initializes the list_head to point to itself. If it is a list header,
|
||||
* the result is an empty list.
|
||||
*/
|
||||
static inline void INIT_LIST_HEAD(struct list_head *list)
|
||||
{
|
||||
list->next = list;
|
||||
list->prev = list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert a new entry between two known consecutive entries.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next)
|
||||
{
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_add - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it after
|
||||
*
|
||||
* Insert a new entry after the specified head.
|
||||
* This is good for implementing stacks.
|
||||
*/
|
||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* list_add_tail - add a new entry
|
||||
* @new: new entry to be added
|
||||
* @head: list head to add it before
|
||||
*
|
||||
* Insert a new entry before the specified head.
|
||||
* This is useful for implementing queues.
|
||||
*/
|
||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
||||
{
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete a list entry by making the prev/next entries
|
||||
* point to each other.
|
||||
*
|
||||
* This is only for internal list manipulation where we know
|
||||
* the prev/next entries already!
|
||||
*/
|
||||
static inline void __list_del(struct list_head * prev, struct list_head * next)
|
||||
{
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
static inline void __list_del_entry(struct list_head *entry)
|
||||
{
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
/**
|
||||
* list_del - deletes entry from list.
|
||||
* @entry: the element to delete from the list.
|
||||
* Note: list_empty() on entry does not return true after this, the entry is
|
||||
* in an undefined state.
|
||||
*/
|
||||
static inline void list_del(struct list_head *entry)
|
||||
{
|
||||
__list_del_entry(entry);
|
||||
entry->next = LIST_POISON1;
|
||||
entry->prev = LIST_POISON2;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_empty - tests whether a list is empty
|
||||
* @head: the list to test.
|
||||
*/
|
||||
static inline int list_empty(const struct list_head *head)
|
||||
{
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
/**
|
||||
* list_entry - get the struct for this entry
|
||||
* @ptr: the &struct list_head pointer.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_entry(ptr, type, member) \
|
||||
container_of(ptr, type, member)
|
||||
|
||||
/**
|
||||
* list_first_entry - get the first element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Note, that list is expected to be not empty.
|
||||
*/
|
||||
#define list_first_entry(ptr, type, member) \
|
||||
list_entry((ptr)->next, type, member)
|
||||
|
||||
/**
|
||||
* list_last_entry - get the last element from a list
|
||||
* @ptr: the list head to take the element from.
|
||||
* @type: the type of the struct this is embedded in.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*
|
||||
* Note, that list is expected to be not empty.
|
||||
*/
|
||||
#define list_last_entry(ptr, type, member) \
|
||||
list_entry((ptr)->prev, type, member)
|
||||
|
||||
/**
|
||||
* list_next_entry - get the next element in list
|
||||
* @pos: the type * to cursor
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_next_entry(pos, member) \
|
||||
list_entry((pos)->member.next, __typeof__(*(pos)), member)
|
||||
|
||||
/**
|
||||
* list_prev_entry - get the prev element in list
|
||||
* @pos: the type * to cursor
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_prev_entry(pos, member) \
|
||||
list_entry((pos)->member.prev, __typeof__(*(pos)), member)
|
||||
|
||||
/**
|
||||
* list_for_each - iterate over a list
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
/**
|
||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||
* @pos: the &struct list_head to use as a loop cursor.
|
||||
* @n: another &struct list_head to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
*/
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
/**
|
||||
* list_entry_is_head - test if the entry points to the head of the list
|
||||
* @pos: the type * to cursor
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_entry_is_head(pos, head, member) \
|
||||
(&pos->member == (head))
|
||||
|
||||
/**
|
||||
* list_for_each_entry - iterate over list of given type
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = list_first_entry(head, __typeof__(*pos), member); \
|
||||
!list_entry_is_head(pos, head, member); \
|
||||
pos = list_next_entry(pos, member))
|
||||
|
||||
/**
|
||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
||||
* @pos: the type * to use as a loop cursor.
|
||||
* @n: another type * to use as temporary storage
|
||||
* @head: the head for your list.
|
||||
* @member: the name of the list_head within the struct.
|
||||
*/
|
||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
||||
for (pos = list_first_entry(head, __typeof__(*pos), member), \
|
||||
n = list_next_entry(pos, member); \
|
||||
!list_entry_is_head(pos, head, member); \
|
||||
pos = n, n = list_next_entry(n, member))
|
||||
|
||||
#endif /* __LIST_H */
|
37
c/linked-list/makefile
Normal file
37
c/linked-list/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: ./*.c ./*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) test-framework/unity.c ./*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: ./*.c ./*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) test-framework/unity.c ./*.c -o tests.out $(LIBS)
|
243
c/linked-list/test_linked_list.c
Normal file
243
c/linked-list/test_linked_list.c
Normal file
@@ -0,0 +1,243 @@
|
||||
#include <stddef.h>
|
||||
#include "test-framework/unity.h"
|
||||
#include "linked_list.h"
|
||||
|
||||
struct list *list = NULL;
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
list = list_create();
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
if (list) {
|
||||
list_destroy(list);
|
||||
list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_pop_gets_element_from_the_list(void)
|
||||
{
|
||||
list_push(list, 7);
|
||||
TEST_ASSERT_EQUAL(7, list_pop(list));
|
||||
}
|
||||
|
||||
static void test_push_pop_respectively_add_remove_at_the_end_of_the_list(void)
|
||||
{
|
||||
TEST_IGNORE(); // delete this line to run test
|
||||
list_push(list, 11);
|
||||
list_push(list, 13);
|
||||
TEST_ASSERT_EQUAL(13, list_pop(list));
|
||||
TEST_ASSERT_EQUAL(11, list_pop(list));
|
||||
}
|
||||
|
||||
static void test_shift_gets_an_element_from_the_list(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_push(list, 17);
|
||||
TEST_ASSERT_EQUAL(17, list_shift(list));
|
||||
}
|
||||
|
||||
static void test_shift_gets_first_element_from_the_list(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_push(list, 23);
|
||||
list_push(list, 5);
|
||||
TEST_ASSERT_EQUAL(23, list_shift(list));
|
||||
TEST_ASSERT_EQUAL(5, list_shift(list));
|
||||
}
|
||||
|
||||
static void test_unshift_adds_element_at_start_of_the_list(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_unshift(list, 23);
|
||||
list_unshift(list, 5);
|
||||
TEST_ASSERT_EQUAL(5, list_shift(list));
|
||||
TEST_ASSERT_EQUAL(23, list_shift(list));
|
||||
}
|
||||
|
||||
static void test_pop_push_shift_and_unshift_can_be_used_in_any_order(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_push(list, 1);
|
||||
list_push(list, 2);
|
||||
TEST_ASSERT_EQUAL(2, list_pop(list));
|
||||
list_push(list, 3);
|
||||
TEST_ASSERT_EQUAL(1, list_shift(list));
|
||||
list_unshift(list, 4);
|
||||
list_push(list, 5);
|
||||
TEST_ASSERT_EQUAL(4, list_shift(list));
|
||||
TEST_ASSERT_EQUAL(5, list_pop(list));
|
||||
TEST_ASSERT_EQUAL(3, list_shift(list));
|
||||
}
|
||||
|
||||
static void test_count_an_empty_list(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
TEST_ASSERT_EQUAL(0, list_count(list));
|
||||
}
|
||||
|
||||
static void test_count_a_list_with_items(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_push(list, 37);
|
||||
list_push(list, 1);
|
||||
TEST_ASSERT_EQUAL(2, list_count(list));
|
||||
}
|
||||
|
||||
static void test_count_is_correct_after_mutation(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_push(list, 31);
|
||||
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||
list_unshift(list, 43);
|
||||
TEST_ASSERT_EQUAL(2, list_count(list));
|
||||
list_shift(list);
|
||||
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||
list_pop(list);
|
||||
TEST_ASSERT_EQUAL(0, list_count(list));
|
||||
}
|
||||
|
||||
static void test_popping_to_empty_does_not_break_the_list(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_push(list, 41);
|
||||
list_push(list, 59);
|
||||
list_pop(list);
|
||||
list_pop(list);
|
||||
list_push(list, 47);
|
||||
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||
TEST_ASSERT_EQUAL(47, list_pop(list));
|
||||
}
|
||||
|
||||
static void test_shifting_to_empty_does_not_break_the_list(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_push(list, 41);
|
||||
list_push(list, 59);
|
||||
list_shift(list);
|
||||
list_shift(list);
|
||||
list_push(list, 47);
|
||||
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||
TEST_ASSERT_EQUAL(47, list_shift(list));
|
||||
}
|
||||
|
||||
static void test_deletes_the_only_element(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_push(list, 61);
|
||||
list_delete(list, 61);
|
||||
TEST_ASSERT_EQUAL(0, list_count(list));
|
||||
}
|
||||
|
||||
static void
|
||||
test_deletes_the_element_with_the_specified_value_from_the_list(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_push(list, 71);
|
||||
list_push(list, 83);
|
||||
list_push(list, 79);
|
||||
list_delete(list, 83);
|
||||
TEST_ASSERT_EQUAL(2, list_count(list));
|
||||
TEST_ASSERT_EQUAL(79, list_pop(list));
|
||||
TEST_ASSERT_EQUAL(71, list_shift(list));
|
||||
}
|
||||
|
||||
static void
|
||||
test_deletes_the_element_with_the_specified_value_from_the_list_reassigns_tail
|
||||
(void) {
|
||||
TEST_IGNORE();
|
||||
list_push(list, 71);
|
||||
list_push(list, 83);
|
||||
list_push(list, 79);
|
||||
list_delete(list, 83);
|
||||
TEST_ASSERT_EQUAL(2, list_count(list));
|
||||
TEST_ASSERT_EQUAL(79, list_pop(list));
|
||||
TEST_ASSERT_EQUAL(71, list_pop(list));
|
||||
}
|
||||
|
||||
static void
|
||||
test_deletes_the_element_with_the_specified_value_from_the_list_reassigns_head
|
||||
(void) {
|
||||
TEST_IGNORE();
|
||||
list_push(list, 71);
|
||||
list_push(list, 83);
|
||||
list_push(list, 79);
|
||||
list_delete(list, 83);
|
||||
TEST_ASSERT_EQUAL(2, list_count(list));
|
||||
TEST_ASSERT_EQUAL(71, list_shift(list));
|
||||
TEST_ASSERT_EQUAL(79, list_shift(list));
|
||||
}
|
||||
|
||||
static void test_deletes_the_first_of_two_elements(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_push(list, 97);
|
||||
list_push(list, 101);
|
||||
list_delete(list, 97);
|
||||
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||
TEST_ASSERT_EQUAL(101, list_pop(list));
|
||||
}
|
||||
|
||||
static void test_deletes_the_second_of_two_elements(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_push(list, 97);
|
||||
list_push(list, 101);
|
||||
list_delete(list, 101);
|
||||
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||
TEST_ASSERT_EQUAL(97, list_pop(list));
|
||||
}
|
||||
|
||||
static void
|
||||
test_delete_does_not_modify_the_list_if_the_element_is_not_found(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_push(list, 89);
|
||||
list_delete(list, 103);
|
||||
TEST_ASSERT_EQUAL(1, list_count(list));
|
||||
}
|
||||
|
||||
static void test_deletes_only_the_first_occurrence(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
list_push(list, 73);
|
||||
list_push(list, 9);
|
||||
list_push(list, 9);
|
||||
list_push(list, 107);
|
||||
list_delete(list, 9);
|
||||
TEST_ASSERT_EQUAL(3, list_count(list));
|
||||
TEST_ASSERT_EQUAL(107, list_pop(list));
|
||||
TEST_ASSERT_EQUAL(9, list_pop(list));
|
||||
TEST_ASSERT_EQUAL(73, list_pop(list));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UnityBegin("test_linked_list.c");
|
||||
|
||||
RUN_TEST(test_pop_gets_element_from_the_list);
|
||||
RUN_TEST(test_push_pop_respectively_add_remove_at_the_end_of_the_list);
|
||||
RUN_TEST(test_shift_gets_an_element_from_the_list);
|
||||
RUN_TEST(test_shift_gets_first_element_from_the_list);
|
||||
RUN_TEST(test_unshift_adds_element_at_start_of_the_list);
|
||||
RUN_TEST(test_pop_push_shift_and_unshift_can_be_used_in_any_order);
|
||||
RUN_TEST(test_count_an_empty_list);
|
||||
RUN_TEST(test_count_a_list_with_items);
|
||||
RUN_TEST(test_count_is_correct_after_mutation);
|
||||
RUN_TEST(test_popping_to_empty_does_not_break_the_list);
|
||||
RUN_TEST(test_shifting_to_empty_does_not_break_the_list);
|
||||
RUN_TEST(test_deletes_the_only_element);
|
||||
RUN_TEST(test_deletes_the_element_with_the_specified_value_from_the_list);
|
||||
RUN_TEST
|
||||
(test_deletes_the_element_with_the_specified_value_from_the_list_reassigns_tail);
|
||||
RUN_TEST
|
||||
(test_deletes_the_element_with_the_specified_value_from_the_list_reassigns_head);
|
||||
RUN_TEST(test_deletes_the_first_of_two_elements);
|
||||
RUN_TEST(test_deletes_the_second_of_two_elements);
|
||||
RUN_TEST(test_delete_does_not_modify_the_list_if_the_element_is_not_found);
|
||||
RUN_TEST(test_deletes_only_the_first_occurrence);
|
||||
|
||||
return UnityEnd();
|
||||
}
|
51
c/list-ops/GNUmakefile
Normal file
51
c/list-ops/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o tests.out $(LIBS)
|
54
c/list-ops/README.md
Normal file
54
c/list-ops/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# List Ops
|
||||
|
||||
Implement basic list operations.
|
||||
|
||||
In functional languages list operations like `length`, `map`, and
|
||||
`reduce` are very common. Implement a series of basic list operations,
|
||||
without using existing functions.
|
||||
|
||||
The precise number and names of the operations to be implemented will be
|
||||
track dependent to avoid conflicts with existing names, but the general
|
||||
operations you will implement include:
|
||||
|
||||
* `append` (*given two lists, add all items in the second list to the end of the first list*);
|
||||
* `concatenate` (*given a series of lists, combine all items in all lists into one flattened list*);
|
||||
* `filter` (*given a predicate and a list, return the list of all items for which `predicate(item)` is True*);
|
||||
* `length` (*given a list, return the total number of items within it*);
|
||||
* `map` (*given a function and a list, return the list of the results of applying `function(item)` on all items*);
|
||||
* `foldl` (*given a function, a list, and initial accumulator, fold (reduce) each item into the accumulator from the left using `function(accumulator, item)`*);
|
||||
* `foldr` (*given a function, a list, and an initial accumulator, fold (reduce) each item into the accumulator from the right using `function(item, accumulator)`*);
|
||||
* `reverse` (*given a list, return a list with all the original items, but in reversed order*);
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/list-ops/makefile
Normal file
37
c/list-ops/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
136
c/list-ops/src/list_ops.c
Normal file
136
c/list-ops/src/list_ops.c
Normal file
@@ -0,0 +1,136 @@
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "list_ops.h"
|
||||
|
||||
list_t *new_list(size_t len, list_element_t elts[])
|
||||
{
|
||||
list_t *list;
|
||||
|
||||
if (len > MAX_LIST_LENGTH ||
|
||||
!(list=malloc(sizeof(list_t) + len*sizeof(list_element_t))))
|
||||
return NULL;
|
||||
list->length = len;
|
||||
if (elts)
|
||||
memcpy(list->elements, elts, len * sizeof(list_element_t));
|
||||
return list;
|
||||
}
|
||||
|
||||
list_t *append_list(list_t *l1, list_t *l2)
|
||||
{
|
||||
list_t *l;
|
||||
size_t len=l1->length+l2->length;
|
||||
|
||||
if (!(l=new_list(len, NULL)))
|
||||
return NULL;
|
||||
memcpy(l->elements, l1->elements, l1->length * sizeof(list_element_t));
|
||||
memcpy(l->elements + l1->length, l2->elements,
|
||||
l2->length * sizeof(list_element_t));
|
||||
l->length=len;
|
||||
return l;
|
||||
}
|
||||
|
||||
list_t *filter_list(list_t * l, bool(*f) (list_element_t))
|
||||
{
|
||||
size_t p1, p2;
|
||||
list_t *list=new_list(l->length, NULL);
|
||||
|
||||
if (list) {
|
||||
for (p1=0, p2=0; p1 < l->length; ++p1) {
|
||||
if (f(l->elements[p1]))
|
||||
list->elements[p2++]=l->elements[p1];
|
||||
}
|
||||
}
|
||||
list->length=p2;
|
||||
return list;
|
||||
}
|
||||
|
||||
/* I don't like this function return value, and more generally using size_t
|
||||
* as list length.
|
||||
*/
|
||||
size_t length_list(list_t *l)
|
||||
{
|
||||
return l? l->length: INVALID_LENGTH;
|
||||
}
|
||||
|
||||
list_t *map_list(list_t * l, list_element_t(*map) (list_element_t))
|
||||
{
|
||||
size_t i;
|
||||
list_t *list=new_list(l->length, NULL);
|
||||
|
||||
if (list) {
|
||||
for (i=0; i < l->length; ++i)
|
||||
list->elements[i] = map(l->elements[i]);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
list_element_t foldl_list(list_t * l, list_element_t init,
|
||||
list_element_t(*f) (list_element_t, list_element_t))
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < l->length; ++i)
|
||||
init = f(l->elements[i], init);
|
||||
return init;
|
||||
}
|
||||
|
||||
list_element_t foldr_list(list_t * l, list_element_t init,
|
||||
list_element_t(*f) (list_element_t, list_element_t))
|
||||
{
|
||||
ptrdiff_t i;
|
||||
|
||||
for (i = l->length-1; i >= 0; --i)
|
||||
init = f(l->elements[i], init);
|
||||
return init;
|
||||
}
|
||||
|
||||
list_t *reverse_list(list_t * l)
|
||||
{
|
||||
size_t i;
|
||||
list_t *list=new_list(l->length, NULL);
|
||||
|
||||
if (list) {
|
||||
for (i=0; i < l->length; ++i)
|
||||
list->elements[l->length-i-1] = l->elements[i];
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
void delete_list(list_t * l)
|
||||
{
|
||||
free(l);
|
||||
}
|
||||
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
static void print_list(list_t *l)
|
||||
{
|
||||
printf("list (%lu) = ", l->length);
|
||||
for (size_t i=0; i<l->length; ++i)
|
||||
printf("%d ", l->elements[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1, i;
|
||||
list_t *l1=new_list(0, NULL);
|
||||
list_t *l2, *l3;
|
||||
|
||||
for (; arg<ac; ++arg) {
|
||||
i=atoi(av[arg]);
|
||||
l2 = new_list(1, (list_element_t[]){ i });
|
||||
l3 = append_list(l1, l2);
|
||||
delete_list(l2);
|
||||
delete_list(l1);
|
||||
l1=l3;
|
||||
}
|
||||
print_list(l1);
|
||||
delete_list(l1);
|
||||
}
|
||||
#endif
|
62
c/list-ops/src/list_ops.h
Normal file
62
c/list-ops/src/list_ops.h
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef LINKED_LIST_H
|
||||
#define LINKED_LIST_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef char list_element_t;
|
||||
typedef struct {
|
||||
size_t length;
|
||||
list_element_t elements[];
|
||||
} list_t;
|
||||
|
||||
#define MAX_LIST_LENGTH 1024
|
||||
#define INVALID_LENGTH (size_t)-1
|
||||
|
||||
// constructs a new list
|
||||
extern list_t *new_list(size_t length, list_element_t elements[]);
|
||||
|
||||
// append entries to a list and return the new list
|
||||
extern list_t *append_list(list_t * list1, list_t * list2);
|
||||
|
||||
// filter list returning only values that satisfy the filter function
|
||||
extern list_t *filter_list(list_t * list, bool(*filter) (list_element_t));
|
||||
|
||||
// returns the length of the list
|
||||
extern size_t length_list(list_t * list);
|
||||
|
||||
// return a list of elements whose values equal the list value transformed by
|
||||
// the mapping function
|
||||
extern list_t *map_list(list_t * list, list_element_t(*map) (list_element_t));
|
||||
|
||||
// folds (reduces) the given list from the left with a function
|
||||
extern list_element_t foldl_list(list_t * list, list_element_t initial,
|
||||
list_element_t(*foldl) (list_element_t,
|
||||
list_element_t));
|
||||
|
||||
// folds (reduces) the given list from the right with a function
|
||||
extern list_element_t foldr_list(list_t * list, list_element_t initial,
|
||||
list_element_t(*foldr) (list_element_t,
|
||||
list_element_t));
|
||||
|
||||
// reverse the elements of the list
|
||||
extern list_t *reverse_list(list_t * list);
|
||||
|
||||
// destroy the entire list
|
||||
// list will be a dangling pointer after calling this method on it
|
||||
extern void delete_list(list_t * list);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
51
c/nucleotide-count/GNUmakefile
Normal file
51
c/nucleotide-count/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o test.out
|
59
c/nucleotide-count/README.md
Normal file
59
c/nucleotide-count/README.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Nucleotide Count
|
||||
|
||||
Each of us inherits from our biological parents a set of chemical instructions known as DNA that influence how our bodies are constructed. All known life depends on DNA!
|
||||
|
||||
> Note: You do not need to understand anything about nucleotides or DNA to complete this exercise.
|
||||
|
||||
DNA is a long chain of other chemicals and the most important are the four nucleotides, adenine, cytosine, guanine and thymine. A single DNA chain can contain billions of these four nucleotides and the order in which they occur is important!
|
||||
We call the order of these nucleotides in a bit of DNA a "DNA sequence".
|
||||
|
||||
We represent a DNA sequence as an ordered collection of these four nucleotides and a common way to do that is with a string of characters such as "ATTACG" for a DNA sequence of 6 nucleotides.
|
||||
'A' for adenine, 'C' for cytosine, 'G' for guanine, and 'T' for thymine.
|
||||
|
||||
Given a string representing a DNA sequence, count how many of each nucleotide is present.
|
||||
If the string contains characters that aren't A, C, G, or T then it is invalid and you should signal an error.
|
||||
|
||||
For example:
|
||||
|
||||
```
|
||||
"GATTACA" -> 'A': 3, 'C': 1, 'G': 1, 'T': 2
|
||||
"INVALID" -> error
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
The Calculating DNA Nucleotides_problem at Rosalind [http://rosalind.info/problems/dna/](http://rosalind.info/problems/dna/)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/nucleotide-count/makefile
Normal file
37
c/nucleotide-count/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
68
c/nucleotide-count/src/nucleotide_count.c
Normal file
68
c/nucleotide-count/src/nucleotide_count.c
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "nucleotide_count.h"
|
||||
|
||||
typedef unsigned char uchar;
|
||||
|
||||
static int C[256] = {
|
||||
['A']=1, ['C']=2, ['G']=3, ['T']=4
|
||||
};
|
||||
|
||||
/* not in C99: we implement asprintf */
|
||||
static char *asprintf(const char *fmt, ...)
|
||||
{
|
||||
int n = 0;
|
||||
char *p = NULL;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf(p, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (n < 0 || !(p=malloc(n+1)))
|
||||
return NULL;
|
||||
|
||||
va_start(ap, fmt);
|
||||
n = vsnprintf(p, n+1, fmt, ap);
|
||||
va_end(ap);
|
||||
if (n < 0) {
|
||||
free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
char *count(const char *dna)
|
||||
{
|
||||
int res[4]={ 0 };
|
||||
|
||||
if (!dna)
|
||||
return NULL; /* should it be "" ? */
|
||||
|
||||
for (const uchar *p=(uchar *)dna; *p; ++p) {
|
||||
if (!C[*p])
|
||||
return asprintf("");
|
||||
res[C[*p]-1]++;
|
||||
}
|
||||
return asprintf("A:%d C:%d G:%d T:%d", res[0], res[1], res[2], res[3]);
|
||||
}
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1;
|
||||
char *p;
|
||||
|
||||
//printf("%s: %s\n", asprintf("%d %d %d %d %s", (long)av-(long)av, ac, arg, 1000, "foobar"));
|
||||
for (; arg<ac; ++arg) {
|
||||
p=count(av[arg]);
|
||||
printf("%s: [%s] len=%lu\n", av[arg], p, strlen(p));
|
||||
}
|
||||
}
|
||||
#endif
|
18
c/nucleotide-count/src/nucleotide_count.h
Normal file
18
c/nucleotide-count/src/nucleotide_count.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef _NUCLEOTIDE_COUNT_H
|
||||
#define _NUCLEOTIDE_COUNT_H
|
||||
|
||||
char *count(const char *dna_strand);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
56
c/phone-number/GNUmakefile
Normal file
56
c/phone-number/GNUmakefile
Normal file
@@ -0,0 +1,56 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# 1) copy it into exercise directory
|
||||
# 2) add ex.h to exercise include file
|
||||
# 3) add ex.c to exercise source code, and create a suitable main function
|
||||
# 4) use make with one of the following targets :
|
||||
# all: compile and run all predefined tests.
|
||||
# nowarn: compile with no -Werror, and run all predefined tests
|
||||
# debug: compile with -DDEBUG and run all predefined tests
|
||||
# mem: perform memcheck with all tests enabled
|
||||
# unit: build standalone (unit) bimary
|
||||
# unitnowarn: build standalone (unit) binary with -Werror disabled
|
||||
# unitdebug: build standalone binary with -DDEBUG
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all nowarn debug mem unit unitnowarn unitdebug standalone
|
||||
|
||||
default: all
|
||||
|
||||
ALLSOURCES:=$(wildcard ./*.c)
|
||||
TESTSOURCES:=$(wildcard ./test_*.c)
|
||||
SRC:=$(filter-out $(TESTSOURCES),$(ALLSOURCES))
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
nowarn: CFLAGS:=$(filter-out -Werror,$(CFLAGS))
|
||||
nowarn: clean all
|
||||
|
||||
debug: CFLAGS+=-DDEBUG
|
||||
debug: all
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unitnowarn: CFLAGS:=$(filter-out -Werror,$(CFLAGS))
|
||||
unitnowarn: clean unit
|
||||
|
||||
unitdebug: CFLAGS+=-DDEBUG
|
||||
unitdebug: clean unit
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: *.c *.h
|
||||
$(CC) $(CFLAGS) $(SRC) -o tests.out $(LIBS)
|
63
c/phone-number/HELP.md
Normal file
63
c/phone-number/HELP.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test` task.
|
||||
|
||||
```console
|
||||
$ make test
|
||||
```
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the test to fail.
|
||||
Then write just enough code to get the test to pass.
|
||||
Once you've done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your implementation for readability and expressiveness and then go on to the next test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own low-level algorithms or facilities by hand.
|
||||
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit phone_number.c phone_number.h` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [C track's documentation](https://exercism.org/docs/tracks/c)
|
||||
- [Exercism's support channel on gitter](https://gitter.im/exercism/support)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
Make sure you have read the "Guides" section of the [C track][c-track] on the Exercism site.
|
||||
This covers the basic information on setting up the development environment expected by the exercises.
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
|
||||
If you are struggling with a particular exercise, it is possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
## Resources
|
||||
|
||||
To get help if having trouble, you can use the following resources:
|
||||
|
||||
- [StackOverflow][] can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
- [CPPReference][] can be used to look up information on C concepts, operators, types, standard library functions and more.
|
||||
- [TutorialsPoint][] has similar content as CPPReference in its C programming section.
|
||||
- [The C Programming][K&R] book by K&R is the original source of the language and is still useful today.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[stackoverflow]: http://stackoverflow.com/questions/tagged/c
|
||||
[cppreference]: https://en.cppreference.com/w/c
|
||||
[tutorialspoint]: https://www.tutorialspoint.com/cprogramming/
|
||||
[K&R]: https://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628/
|
56
c/phone-number/README.md
Normal file
56
c/phone-number/README.md
Normal file
@@ -0,0 +1,56 @@
|
||||
# Phone Number
|
||||
|
||||
Welcome to Phone Number on Exercism's C Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
Clean up user-entered phone numbers so that they can be sent SMS messages.
|
||||
|
||||
The **North American Numbering Plan (NANP)** is a telephone numbering system used by many countries in North America like the United States, Canada or Bermuda. All NANP-countries share the same international country code: `1`.
|
||||
|
||||
NANP numbers are ten-digit numbers consisting of a three-digit Numbering Plan Area code, commonly known as *area code*, followed by a seven-digit local number. The first three digits of the local number represent the *exchange code*, followed by the unique four-digit number which is the *subscriber number*.
|
||||
|
||||
The format is usually represented as
|
||||
|
||||
```text
|
||||
(NXX)-NXX-XXXX
|
||||
```
|
||||
|
||||
where `N` is any digit from 2 through 9 and `X` is any digit from 0 through 9.
|
||||
|
||||
Your task is to clean up differently formatted telephone numbers by removing punctuation and the country code (1) if present.
|
||||
|
||||
For example, the inputs
|
||||
- `+1 (613)-995-0253`
|
||||
- `613-995-0253`
|
||||
- `1 613 995 0253`
|
||||
- `613.995.0253`
|
||||
|
||||
should all produce the output
|
||||
|
||||
`6139950253`
|
||||
|
||||
**Note:** As this exercise only deals with telephone numbers used in NANP-countries, only 1 is considered a valid country code.
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @RealBarrettBrown
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @bcc32
|
||||
- @Gamecock
|
||||
- @gea-migration
|
||||
- @h-3-0
|
||||
- @mikewalker
|
||||
- @patricksjackson
|
||||
- @QLaille
|
||||
- @ryanplusplus
|
||||
- @wolf99
|
||||
|
||||
### Based on
|
||||
|
||||
Event Manager by JumpstartLab - http://tutorials.jumpstartlab.com/projects/eventmanager.html
|
45
c/phone-number/br-common.h
Normal file
45
c/phone-number/br-common.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef __BR_COMMON_H
|
||||
#define __BR_COMMON_H
|
||||
|
||||
/* ${LINUX_SRC}/include/linux/compiler_attributes.h, around line 30
|
||||
*
|
||||
* __has_attribute is supported on gcc >= 5, clang >= 2.9 and icc >= 17.
|
||||
* For other compilers, simple implementation (for __falltrough__ only)
|
||||
*/
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) __GCC4_has_attribute_##x
|
||||
# define __GCC4_has_attribute___assume_aligned__ (__GNUC_MINOR__ >= 9)
|
||||
# define __GCC4_has_attribute___copy__ 0
|
||||
# define __GCC4_has_attribute___designated_init__ 0
|
||||
# define __GCC4_has_attribute___externally_visible__ 1
|
||||
# define __GCC4_has_attribute___no_caller_saved_registers__ 0
|
||||
# define __GCC4_has_attribute___noclone__ 1
|
||||
# define __GCC4_has_attribute___nonstring__ 0
|
||||
# define __GCC4_has_attribute___no_sanitize_address__ (__GNUC_MINOR__ >= 8)
|
||||
# define __GCC4_has_attribute___no_sanitize_undefined__ (__GNUC_MINOR__ >= 9)
|
||||
# define __GCC4_has_attribute___fallthrough__ 0
|
||||
# define __GCC4_has_attribute___fallthrough__ 0
|
||||
#endif
|
||||
|
||||
/* ${LINUX_SRC}/include/linux/compiler_attributes.h, around line 200
|
||||
*/
|
||||
#if __has_attribute(__fallthrough__)
|
||||
# define fallthrough __attribute__((__fallthrough__))
|
||||
#else
|
||||
# define fallthrough do {} while (0); /* fallthrough */
|
||||
#endif
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef TESTALL
|
||||
# undef TEST_IGNORE
|
||||
# define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif /* __BR_COMMON_H */
|
51
c/phone-number/makefile
Normal file
51
c/phone-number/makefile
Normal file
@@ -0,0 +1,51 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
# detect compiler.
|
||||
REALCC=$(realpath $(shell which $(CC)))
|
||||
CC_VERSION_TEXT=$(shell $(REALCC) --version 2>/dev/null | head -n 1)
|
||||
|
||||
# fix discrepancies in compilers warnings. Only gcc and clang for now.
|
||||
ifneq ($(findstring clang,$(CC_VERSION_TEXT)),)
|
||||
CFLAGS += -Wimplicit-fallthrough
|
||||
else
|
||||
ifneq ($(findstring gcc,$(CC_VERSION_TEXT)),)
|
||||
CFLAGS := $(filter-out -Wimplicit-fallthrough%,$(CFLAGS))
|
||||
CFLAGS += -Wimplicit-fallthrough=5
|
||||
endif
|
||||
endif
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: ./*.c ./*.h
|
||||
@echo Compiling $@
|
||||
$(CC) $(ASANFLAGS) $(CFLAGS) test-framework/unity.c ./*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: ./*.c ./*.h
|
||||
@echo Compiling $@
|
||||
$(CC) $(CFLAGS) test-framework/unity.c ./*.c -o tests.out $(LIBS)
|
91
c/phone-number/phone_number.c
Normal file
91
c/phone-number/phone_number.c
Normal file
@@ -0,0 +1,91 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "phone_number.h"
|
||||
|
||||
#define LEN_NUM 10
|
||||
#define LPAREN '('
|
||||
|
||||
/* this version is likely not very stable, due to poor scanf() capabilities
|
||||
* I made it to offer an option to traditional strtok() or manual string
|
||||
* parsing.
|
||||
* Examples:
|
||||
* (1 (222-333.4444
|
||||
* 1)))))) 222))) ...---... 333 ...---... 4444
|
||||
* are both valid here, when they surely should not :-)
|
||||
*/
|
||||
static char *scan="%m[+(0-9]%*[()-. ]%m[0-9]%*[)-. ]%m[0-9]%*[-. ]%m[0-9]";
|
||||
|
||||
char *phone_number_clean(const char *input)
|
||||
{
|
||||
char *sn[4];
|
||||
uint64_t num[4];
|
||||
uint64_t *p = &*num;
|
||||
int nmatch;
|
||||
char *res;
|
||||
|
||||
if (!(res = malloc(LEN_NUM+1)))
|
||||
return NULL;
|
||||
memset(res, '0', LEN_NUM);
|
||||
*(res+LEN_NUM) = 0;
|
||||
|
||||
nmatch = sscanf(input, scan, &sn[0], &sn[1], &sn[2], &sn[3]);
|
||||
|
||||
for (int i=0; i<nmatch; ++i) {
|
||||
*(p+i) = atol(*sn[i] == LPAREN? sn[i]+1: sn[i]);
|
||||
free(sn[i]); /* due to scanf %m */
|
||||
}
|
||||
|
||||
switch (nmatch) {
|
||||
case 2:
|
||||
/* maybe 2 could be valid, like 333 3334444 ?
|
||||
*/
|
||||
case 0:
|
||||
return res;
|
||||
case 1: /* full number */
|
||||
if (*p > 10000000000) /* 1 000 000 0000 */
|
||||
*p -= 10000000000;
|
||||
if (*p > 9999999999 || /* 999 999 9999 */
|
||||
*p < 2000000000) /* 200 000 0000 */
|
||||
return res;
|
||||
break;
|
||||
case 4: /* country code */
|
||||
if (*p != 1)
|
||||
return res;
|
||||
p++; /* go to area number */
|
||||
fallthrough; /* only gcc>=7 & clang>=12 */
|
||||
case 3: /* start with area number */
|
||||
if (*p < 200 || *p > 999 ||
|
||||
*(p+1) < 200 || *(p+1) > 999 ||
|
||||
*(p+2) > 9999)
|
||||
return res;
|
||||
break;
|
||||
}
|
||||
/* we don't care if some num has random value here (initialized), snprintf
|
||||
* will consume only what is needed to fill the number
|
||||
*/
|
||||
snprintf(res, LEN_NUM+1, "%ld%ld%ld", *p, *(p+1), *(p+2));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg;
|
||||
char *res;
|
||||
|
||||
for (arg=1; arg<ac; ++arg) {
|
||||
res=phone_number_clean(av[arg]);
|
||||
printf("orig = [%s]\n", av[arg]);
|
||||
printf("\t-> [%s]\n", res);
|
||||
free(res);
|
||||
}
|
||||
}
|
||||
#endif
|
10
c/phone-number/phone_number.h
Normal file
10
c/phone-number/phone_number.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef PHONE_NUMBER_H
|
||||
#define PHONE_NUMBER_H
|
||||
|
||||
#define NUMBER_LENGTH 10
|
||||
|
||||
char *phone_number_clean(const char *input);
|
||||
|
||||
#endif
|
||||
|
||||
#include "br-common.h"
|
246
c/phone-number/test_phone_number.c
Normal file
246
c/phone-number/test_phone_number.c
Normal file
@@ -0,0 +1,246 @@
|
||||
#include "test-framework/unity.h"
|
||||
#include "phone_number.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
static char *result = NULL;
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
free(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
static void test_cleans_the_number(void)
|
||||
{
|
||||
const char input[] = "(223) 456-7890";
|
||||
const char expected[] = "2234567890";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_cleans_numbers_with_dots(void)
|
||||
{
|
||||
TEST_IGNORE(); // delete this line to run test
|
||||
const char input[] = "223.456.7890";
|
||||
const char expected[] = "2234567890";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_cleans_numbers_with_multiple_spaces(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "223 456 7890 ";
|
||||
const char expected[] = "2234567890";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_when_9_digits(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "123456789";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_when_11_digits_does_not_start_with_a_1(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "22234567890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_valid_when_11_digits_and_starting_with_1(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "12234567890";
|
||||
const char expected[] = "2234567890";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void
|
||||
test_valid_when_11_digits_and_starting_with_1_even_with_punctuation(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "+1 (223) 456-7890";
|
||||
const char expected[] = "2234567890";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_when_more_than_11_digits(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "321234567890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_with_letters(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "123-abc-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_with_punctuations(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "123-@:!-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_if_area_code_starts_with_0(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "(023) 456-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_if_area_code_starts_with_1(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "(123) 456-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_if_exchange_code_starts_with_0(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "(223) 056-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void test_invalid_if_exchange_code_starts_with_1(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "(223) 156-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void
|
||||
test_invalid_if_area_code_starts_with_0_on_valid_11_digit_number(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "1 (023) 456-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void
|
||||
test_invalid_if_area_code_starts_with_1_on_valid_11_digit_number(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "1 (123) 456-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void
|
||||
test_invalid_if_exchange_code_starts_with_0_on_valid_11_digit_number(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "1 (223) 056-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
static void
|
||||
test_invalid_if_exchange_code_starts_with_1_on_valid_11_digit_number(void)
|
||||
{
|
||||
TEST_IGNORE();
|
||||
const char input[] = "1 (123) 156-7890";
|
||||
const char expected[] = "0000000000";
|
||||
|
||||
result = phone_number_clean(input);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UnityBegin("test_phone_number.c");
|
||||
|
||||
RUN_TEST(test_cleans_the_number);
|
||||
RUN_TEST(test_cleans_numbers_with_dots);
|
||||
RUN_TEST(test_cleans_numbers_with_multiple_spaces);
|
||||
RUN_TEST(test_invalid_when_9_digits);
|
||||
RUN_TEST(test_invalid_when_11_digits_does_not_start_with_a_1);
|
||||
RUN_TEST(test_valid_when_11_digits_and_starting_with_1);
|
||||
RUN_TEST
|
||||
(test_valid_when_11_digits_and_starting_with_1_even_with_punctuation);
|
||||
RUN_TEST(test_invalid_when_more_than_11_digits);
|
||||
RUN_TEST(test_invalid_with_letters);
|
||||
RUN_TEST(test_invalid_with_punctuations);
|
||||
RUN_TEST(test_invalid_if_area_code_starts_with_0);
|
||||
RUN_TEST(test_invalid_if_area_code_starts_with_1);
|
||||
RUN_TEST(test_invalid_if_exchange_code_starts_with_0);
|
||||
RUN_TEST(test_invalid_if_exchange_code_starts_with_1);
|
||||
RUN_TEST(test_invalid_if_area_code_starts_with_0_on_valid_11_digit_number);
|
||||
RUN_TEST(test_invalid_if_area_code_starts_with_1_on_valid_11_digit_number);
|
||||
RUN_TEST
|
||||
(test_invalid_if_exchange_code_starts_with_0_on_valid_11_digit_number);
|
||||
RUN_TEST
|
||||
(test_invalid_if_exchange_code_starts_with_1_on_valid_11_digit_number);
|
||||
|
||||
return UnityEnd();
|
||||
}
|
51
c/pythagorean-triplet/GNUmakefile
Normal file
51
c/pythagorean-triplet/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o tests.out $(LIBS)
|
62
c/pythagorean-triplet/README.md
Normal file
62
c/pythagorean-triplet/README.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Pythagorean Triplet
|
||||
|
||||
A Pythagorean triplet is a set of three natural numbers, {a, b, c}, for
|
||||
which,
|
||||
|
||||
```text
|
||||
a**2 + b**2 = c**2
|
||||
```
|
||||
|
||||
and such that,
|
||||
|
||||
```text
|
||||
a < b < c
|
||||
```
|
||||
|
||||
For example,
|
||||
|
||||
```text
|
||||
3**2 + 4**2 = 9 + 16 = 25 = 5**2.
|
||||
```
|
||||
|
||||
Given an input integer N, find all Pythagorean triplets for which `a + b + c = N`.
|
||||
|
||||
For example, with N = 1000, there is exactly one Pythagorean triplet for which `a + b + c = 1000`: `{200, 375, 425}`.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
Problem 9 at Project Euler [http://projecteuler.net/problem=9](http://projecteuler.net/problem=9)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/pythagorean-triplet/makefile
Normal file
37
c/pythagorean-triplet/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
89
c/pythagorean-triplet/src/pythagorean_triplet.c
Normal file
89
c/pythagorean-triplet/src/pythagorean_triplet.c
Normal file
@@ -0,0 +1,89 @@
|
||||
#include <malloc.h>
|
||||
|
||||
#include "pythagorean_triplet.h"
|
||||
|
||||
#define POOL_SIZE 10
|
||||
|
||||
/* V1: initial version
|
||||
* V2: cormetic changes
|
||||
* V3: add pool for realloc instead of single realloc
|
||||
*/
|
||||
void free_triplets(triplets_t *t)
|
||||
{
|
||||
free(t->triplets);
|
||||
free(t);
|
||||
}
|
||||
|
||||
static triplets_t *new_triplet()
|
||||
{
|
||||
triplets_t *t=malloc(sizeof(triplets_t));
|
||||
if (t) {
|
||||
t->count = 0;
|
||||
t->pool = 0;
|
||||
t->triplets = NULL;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
static triplets_t *add_triplet(triplets_t *t, const uint16_t a, const uint16_t b,
|
||||
const uint16_t c)
|
||||
{
|
||||
/* we may directly call add_triplet() without new_triplet. Not used here,
|
||||
* but could be useful if triplets_with_sum() would return NULL when no
|
||||
* solution found.
|
||||
*/
|
||||
if (! (t || (t = new_triplet())))
|
||||
return NULL;
|
||||
|
||||
if (t->count == t->pool) {
|
||||
t->pool += POOL_SIZE;
|
||||
if (!(t->triplets = realloc(t->triplets, sizeof(triplets_t) +
|
||||
t->pool * sizeof(triplet_t)))) {
|
||||
free(t);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
t->triplets[t->count] = (triplet_t) {a, b, c};
|
||||
t->count++;
|
||||
return t;
|
||||
}
|
||||
|
||||
/* algorithm from : https://stackoverflow.com/a/2818750/3079831
|
||||
*/
|
||||
triplets_t *triplets_with_sum(uint16_t sum)
|
||||
{
|
||||
int a, b, c;
|
||||
triplets_t *t;
|
||||
|
||||
if (!(t = new_triplet()))
|
||||
return NULL;
|
||||
if (sum%2)
|
||||
return t;
|
||||
|
||||
for (a = 1; a <= sum/3; a++) {
|
||||
for (b = a + 1; b <= sum/2; b++) {
|
||||
c = sum - a - b;
|
||||
if (a*a + b*b == c*c)
|
||||
if (!(t = add_triplet(t, a, b, c)))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1;
|
||||
resistor_band_t i[2];
|
||||
|
||||
for (; arg<ac-1; ++arg, ++arg) {
|
||||
*i=atoi(av[arg]);
|
||||
*(i+1)=atoi(av[arg+1]);
|
||||
printf("color(%d, %d)=%d\n", i[0], i[1], color_code(i));
|
||||
}
|
||||
}
|
||||
#endif
|
34
c/pythagorean-triplet/src/pythagorean_triplet.h
Normal file
34
c/pythagorean-triplet/src/pythagorean_triplet.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef PYTHAGOREAN_TRIPLET
|
||||
#define PYTHAGOREAN_TRIPLET
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct triplet {
|
||||
uint16_t a;
|
||||
uint16_t b;
|
||||
uint16_t c;
|
||||
} triplet_t;
|
||||
|
||||
typedef struct triplets {
|
||||
size_t count;
|
||||
size_t pool;
|
||||
triplet_t *triplets;
|
||||
} triplets_t;
|
||||
|
||||
triplets_t *triplets_with_sum(uint16_t sum);
|
||||
void free_triplets(triplets_t *triplet);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
51
c/raindrops/GNUmakefile
Normal file
51
c/raindrops/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o test.out
|
54
c/raindrops/README.md
Normal file
54
c/raindrops/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Raindrops
|
||||
|
||||
Your task is to convert a number into a string that contains raindrop sounds corresponding to certain potential factors. A factor is a number that evenly divides into another number, leaving no remainder. The simplest way to test if a one number is a factor of another is to use the [modulo operation](https://en.wikipedia.org/wiki/Modulo_operation).
|
||||
|
||||
The rules of `raindrops` are that if a given number:
|
||||
|
||||
- has 3 as a factor, add 'Pling' to the result.
|
||||
- has 5 as a factor, add 'Plang' to the result.
|
||||
- has 7 as a factor, add 'Plong' to the result.
|
||||
- _does not_ have any of 3, 5, or 7 as a factor, the result should be the digits of the number.
|
||||
|
||||
## Examples
|
||||
|
||||
- 28 has 7 as a factor, but not 3 or 5, so the result would be "Plong".
|
||||
- 30 has both 3 and 5 as factors, but not 7, so the result would be "PlingPlang".
|
||||
- 34 is not factored by 3, 5, or 7, so the result would be "34".
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
A variation on FizzBuzz, a famous technical interview question that is intended to weed out potential candidates. That question is itself derived from Fizz Buzz, a popular children's game for teaching division. [https://en.wikipedia.org/wiki/Fizz_buzz](https://en.wikipedia.org/wiki/Fizz_buzz)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/raindrops/makefile
Normal file
37
c/raindrops/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
29
c/raindrops/src/raindrops.c
Normal file
29
c/raindrops/src/raindrops.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include "raindrops.h"
|
||||
#include <stdio.h>
|
||||
|
||||
char *convert(char result[], int drops)
|
||||
{
|
||||
char *p=result;
|
||||
|
||||
if (!(drops%3)) p+=sprintf(p, "%s", "Pling");
|
||||
if (!(drops%5)) p+=sprintf(p, "%s", "Plang");
|
||||
if (!(drops%7)) p+=sprintf(p, "%s", "Plong");
|
||||
if (p==result) sprintf(p, "%d", drops);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1, i;
|
||||
char buffer[128];
|
||||
|
||||
for (; arg<ac; ++arg) {
|
||||
i=atoi(av[arg]);
|
||||
printf("raindrops(%d)=%s\n", i, convert(buffer, i));
|
||||
}
|
||||
}
|
||||
#endif
|
18
c/raindrops/src/raindrops.h
Normal file
18
c/raindrops/src/raindrops.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef RAINDROPS_H
|
||||
#define RAINDROPS_H
|
||||
|
||||
char *convert(char result[], int drops);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
51
c/rational-numbers/GNUmakefile
Normal file
51
c/rational-numbers/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o tests.out $(LIBS)
|
67
c/rational-numbers/README.md
Normal file
67
c/rational-numbers/README.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Rational Numbers
|
||||
|
||||
A rational number is defined as the quotient of two integers `a` and `b`, called the numerator and denominator, respectively, where `b != 0`.
|
||||
|
||||
The absolute value `|r|` of the rational number `r = a/b` is equal to `|a|/|b|`.
|
||||
|
||||
The sum of two rational numbers `r₁ = a₁/b₁` and `r₂ = a₂/b₂` is `r₁ + r₂ = a₁/b₁ + a₂/b₂ = (a₁ * b₂ + a₂ * b₁) / (b₁ * b₂)`.
|
||||
|
||||
The difference of two rational numbers `r₁ = a₁/b₁` and `r₂ = a₂/b₂` is `r₁ - r₂ = a₁/b₁ - a₂/b₂ = (a₁ * b₂ - a₂ * b₁) / (b₁ * b₂)`.
|
||||
|
||||
The product (multiplication) of two rational numbers `r₁ = a₁/b₁` and `r₂ = a₂/b₂` is `r₁ * r₂ = (a₁ * a₂) / (b₁ * b₂)`.
|
||||
|
||||
Dividing a rational number `r₁ = a₁/b₁` by another `r₂ = a₂/b₂` is `r₁ / r₂ = (a₁ * b₂) / (a₂ * b₁)` if `a₂` is not zero.
|
||||
|
||||
Exponentiation of a rational number `r = a/b` to a non-negative integer power `n` is `r^n = (a^n)/(b^n)`.
|
||||
|
||||
Exponentiation of a rational number `r = a/b` to a negative integer power `n` is `r^n = (b^m)/(a^m)`, where `m = |n|`.
|
||||
|
||||
Exponentiation of a rational number `r = a/b` to a real (floating-point) number `x` is the quotient `(a^x)/(b^x)`, which is a real number.
|
||||
|
||||
Exponentiation of a real number `x` to a rational number `r = a/b` is `x^(a/b) = root(x^a, b)`, where `root(p, q)` is the `q`th root of `p`.
|
||||
|
||||
Implement the following operations:
|
||||
- addition, subtraction, multiplication and division of two rational numbers,
|
||||
- absolute value, exponentiation of a given rational number to an integer power, exponentiation of a given rational number to a real (floating-point) power, exponentiation of a real number to a rational number.
|
||||
|
||||
Your implementation of rational numbers should always be reduced to lowest terms. For example, `4/4` should reduce to `1/1`, `30/60` should reduce to `1/2`, `12/8` should reduce to `3/2`, etc. To reduce a rational number `r = a/b`, divide `a` and `b` by the greatest common divisor (gcd) of `a` and `b`. So, for example, `gcd(12, 8) = 4`, so `r = 12/8` can be reduced to `(12/4)/(8/4) = 3/2`.
|
||||
|
||||
Assume that the programming language you are using does not have an implementation of rational numbers.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
Wikipedia [https://en.wikipedia.org/wiki/Rational_number](https://en.wikipedia.org/wiki/Rational_number)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/rational-numbers/makefile
Normal file
37
c/rational-numbers/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
115
c/rational-numbers/src/rational_numbers.c
Normal file
115
c/rational-numbers/src/rational_numbers.c
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "rational_numbers.h"
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#define N(r) ((r).numerator)
|
||||
#define D(r) ((r).denominator)
|
||||
|
||||
/* Note. We should probably check for possible overflow in all
|
||||
* functions below (not covered in exercise).
|
||||
* To do this, a simple solution could be to make operations with
|
||||
* long long (or some other method), and add a field in rational_t
|
||||
* to express such overflow, division by zero, etc...
|
||||
*/
|
||||
|
||||
/* Euclidean algorithm (by Donald Knuth) */
|
||||
rational_t reduce(rational_t r)
|
||||
{
|
||||
int16_t a=abs(N(r)), b=abs(D(r)), t;
|
||||
|
||||
while (b != 0) {
|
||||
t = b;
|
||||
b = a % b;
|
||||
a = t;
|
||||
}
|
||||
if (D(r) < 0)
|
||||
a=-a;
|
||||
return (rational_t) { N(r)/a, D(r)/a };
|
||||
}
|
||||
|
||||
/* to avoid pow() for integers
|
||||
* BUG: does not check for overflow
|
||||
*/
|
||||
static inline int power(int n, int p)
|
||||
{
|
||||
int res=n;
|
||||
|
||||
if (p==0)
|
||||
return 1;
|
||||
while (--p)
|
||||
res*=n;
|
||||
return res;
|
||||
}
|
||||
|
||||
/* All formulas below come from https://en.wikipedia.org/wiki/Rational_number
|
||||
*/
|
||||
rational_t add(rational_t r1, rational_t r2)
|
||||
{
|
||||
return reduce((rational_t) {
|
||||
N(r1) * D(r2) + N(r2) * D(r1),
|
||||
D(r1) * D(r2)
|
||||
});
|
||||
}
|
||||
|
||||
rational_t subtract(rational_t r1, rational_t r2)
|
||||
{
|
||||
return reduce((rational_t) {
|
||||
N(r1) * D(r2) - N(r2) * D(r1),
|
||||
D(r1) * D(r2)
|
||||
});
|
||||
}
|
||||
|
||||
rational_t multiply(rational_t r1, rational_t r2)
|
||||
{
|
||||
return reduce((rational_t) {
|
||||
N(r1) * N(r2),
|
||||
D(r1) * D(r2)
|
||||
});
|
||||
}
|
||||
|
||||
rational_t divide(rational_t r1, rational_t r2)
|
||||
{
|
||||
return reduce((rational_t) {
|
||||
N(r1) * D(r2),
|
||||
D(r1) * N(r2)
|
||||
});
|
||||
}
|
||||
|
||||
rational_t absolute(rational_t r)
|
||||
{
|
||||
return (rational_t) {
|
||||
abs(N(r)),
|
||||
abs(D(r))
|
||||
};
|
||||
}
|
||||
|
||||
rational_t exp_rational(rational_t r, uint16_t n)
|
||||
{
|
||||
return reduce((rational_t) {
|
||||
power(N(r), n),
|
||||
power(D(r), n)
|
||||
});
|
||||
}
|
||||
|
||||
float exp_real(uint16_t x, rational_t r)
|
||||
{
|
||||
return powf((float)x, (float)N(r)/D(r));
|
||||
}
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1;
|
||||
rational_t r1, r2;
|
||||
|
||||
for (; arg<ac-1; ++arg, ++arg) {
|
||||
r1.numerator=atoi(av[arg]);;
|
||||
r1.denominator=atoi(av[arg+1]);;
|
||||
r2=reduce(r1);
|
||||
printf("reduce(%d, %d)=(%d, %d)\n", N(r1), D(r1), N(r2), D(r2));
|
||||
}
|
||||
}
|
||||
#endif
|
33
c/rational-numbers/src/rational_numbers.h
Normal file
33
c/rational-numbers/src/rational_numbers.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef RATIONAL_NUMBERS
|
||||
#define RATIONAL_NUMBERS
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
int16_t numerator;
|
||||
int16_t denominator;
|
||||
} rational_t;
|
||||
|
||||
rational_t add(rational_t r1, rational_t r2);
|
||||
rational_t subtract(rational_t r1, rational_t r2);
|
||||
rational_t multiply(rational_t r1, rational_t r2);
|
||||
rational_t divide(rational_t r1, rational_t r2);
|
||||
rational_t absolute(rational_t r);
|
||||
rational_t exp_rational(rational_t r, uint16_t n);
|
||||
float exp_real(uint16_t x, rational_t r);
|
||||
rational_t reduce(rational_t r);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
@@ -4,10 +4,9 @@
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
resistor_band_t color_code(resistor_band_t *colors)
|
||||
resistor_band_t color_code(resistor_band_t colors[static 2])
|
||||
{
|
||||
resistor_band_t c1=*colors, c2=*(colors+1);
|
||||
|
||||
return c1>=BLACK && c1<=WHITE && c2>=BLACK && c2<=WHITE? c1*10+c2: ERROR;
|
||||
}
|
||||
|
||||
@@ -20,7 +19,7 @@ int main(int ac, char **av)
|
||||
for (; arg<ac-1; ++arg, ++arg) {
|
||||
*i=atoi(av[arg]);
|
||||
*(i+1)=atoi(av[arg+1]);
|
||||
printf("color(%d, %d)=%d\n", i[0], i[1], color_code(i));
|
||||
printf("color(%d, %d)=%d\n", *i, *(i+1), color_code(i));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@@ -15,7 +15,7 @@ typedef enum {
|
||||
ERROR=-1,
|
||||
} resistor_band_t;
|
||||
|
||||
extern resistor_band_t color_code(resistor_band_t *);
|
||||
extern resistor_band_t color_code(resistor_band_t [static 2]);
|
||||
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
|
51
c/rna-transcription/GNUmakefile
Normal file
51
c/rna-transcription/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o test.out
|
57
c/rna-transcription/README.md
Normal file
57
c/rna-transcription/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# RNA Transcription
|
||||
|
||||
Given a DNA strand, return its RNA complement (per RNA transcription).
|
||||
|
||||
Both DNA and RNA strands are a sequence of nucleotides.
|
||||
|
||||
The four nucleotides found in DNA are adenine (**A**), cytosine (**C**),
|
||||
guanine (**G**) and thymine (**T**).
|
||||
|
||||
The four nucleotides found in RNA are adenine (**A**), cytosine (**C**),
|
||||
guanine (**G**) and uracil (**U**).
|
||||
|
||||
Given a DNA strand, its transcribed RNA strand is formed by replacing
|
||||
each nucleotide with its complement:
|
||||
|
||||
* `G` -> `C`
|
||||
* `C` -> `G`
|
||||
* `T` -> `A`
|
||||
* `A` -> `U`
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
Hyperphysics [http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html](http://hyperphysics.phy-astr.gsu.edu/hbase/Organic/transcription.html)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/rna-transcription/makefile
Normal file
37
c/rna-transcription/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
37
c/rna-transcription/src/rna_transcription.c
Normal file
37
c/rna-transcription/src/rna_transcription.c
Normal file
@@ -0,0 +1,37 @@
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include "rna_transcription.h"
|
||||
|
||||
static char C[256]={
|
||||
['G']='C', ['C']='G', ['T']='A', ['A']='U',
|
||||
};
|
||||
|
||||
char *to_rna(const char *dna)
|
||||
{
|
||||
char *rna=malloc(strlen(dna+1)), *p;
|
||||
|
||||
if (rna) {
|
||||
for (p=rna; *dna; p++, dna++) {
|
||||
if (!(*p=C[(int)*dna])) {
|
||||
free(rna);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
*p=0;
|
||||
}
|
||||
return rna;
|
||||
}
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1;
|
||||
|
||||
for (; arg<ac; ++arg) {
|
||||
printf("rna(%s)=%s\n", av[arg], to_rna(av[arg]));
|
||||
}
|
||||
}
|
||||
#endif
|
18
c/rna-transcription/src/rna_transcription.h
Normal file
18
c/rna-transcription/src/rna_transcription.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef RNA_TRANSCRIPTION_H
|
||||
#define RNA_TRANSCRIPTION_H
|
||||
|
||||
char *to_rna(const char *dna);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
51
c/roman-numerals/GNUmakefile
Normal file
51
c/roman-numerals/GNUmakefile
Normal file
@@ -0,0 +1,51 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# "make": build with all predefined tests (without editing test source code)
|
||||
# "make debugall": build with all predefined tests and debug code
|
||||
# "make mem": perform memcheck with all tests enabled
|
||||
# "make unit": build standalone (unit) test
|
||||
# "make debug": build standalone test with debugging code
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all mem unit debug std debugtest
|
||||
|
||||
default: all
|
||||
|
||||
# default is to build with all predefined tests
|
||||
BUILD := teststall
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
debugall: CFLAGS+=-DDEBUG
|
||||
debugall: all
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: clean std
|
||||
|
||||
debug: CFLAGS+=-DUNIT_TEST -DDEBUG
|
||||
debug: clean std
|
||||
|
||||
debugtest: CFLAGS+=-DDEBUG
|
||||
debugtest: test
|
||||
|
||||
std: src/*.c src/*.h
|
||||
$(CC) $(CFLAGS) src/*.c -o test.out
|
81
c/roman-numerals/README.md
Normal file
81
c/roman-numerals/README.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Roman Numerals
|
||||
|
||||
Write a function to convert from normal numbers to Roman Numerals.
|
||||
|
||||
The Romans were a clever bunch. They conquered most of Europe and ruled
|
||||
it for hundreds of years. They invented concrete and straight roads and
|
||||
even bikinis. One thing they never discovered though was the number
|
||||
zero. This made writing and dating extensive histories of their exploits
|
||||
slightly more challenging, but the system of numbers they came up with
|
||||
is still in use today. For example the BBC uses Roman numerals to date
|
||||
their programmes.
|
||||
|
||||
The Romans wrote numbers using letters - I, V, X, L, C, D, M. (notice
|
||||
these letters have lots of straight lines and are hence easy to hack
|
||||
into stone tablets).
|
||||
|
||||
```text
|
||||
1 => I
|
||||
10 => X
|
||||
7 => VII
|
||||
```
|
||||
|
||||
There is no need to be able to convert numbers larger than about 3000.
|
||||
(The Romans themselves didn't tend to go any higher)
|
||||
|
||||
Wikipedia says: Modern Roman numerals ... are written by expressing each
|
||||
digit separately starting with the left most digit and skipping any
|
||||
digit with a value of zero.
|
||||
|
||||
To see this in practice, consider the example of 1990.
|
||||
|
||||
In Roman numerals 1990 is MCMXC:
|
||||
|
||||
1000=M
|
||||
900=CM
|
||||
90=XC
|
||||
|
||||
2008 is written as MMVIII:
|
||||
|
||||
2000=MM
|
||||
8=VIII
|
||||
|
||||
See also: http://www.novaroma.org/via_romana/numbers.html
|
||||
|
||||
## Getting Started
|
||||
|
||||
Make sure you have read the "Guides" section of the
|
||||
[C track][c-track] on the Exercism site. This covers
|
||||
the basic information on setting up the development environment expected
|
||||
by the exercises.
|
||||
|
||||
## Passing the Tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three
|
||||
rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test`
|
||||
task.
|
||||
|
||||
make test
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the
|
||||
test to fail. Then write just enough code to get the test to pass. Once you've
|
||||
done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your
|
||||
implementation for readability and expressiveness and then go on to the next
|
||||
test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own
|
||||
low-level algorithms or facilities by hand.
|
||||
|
||||
## Source
|
||||
|
||||
The Roman Numeral Kata [http://codingdojo.org/cgi-bin/index.pl?KataRomanNumerals](http://codingdojo.org/cgi-bin/index.pl?KataRomanNumerals)
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
37
c/roman-numerals/makefile
Normal file
37
c/roman-numerals/makefile
Normal file
@@ -0,0 +1,37 @@
|
||||
### If you wish to use extra libraries (math.h for instance),
|
||||
### add their flags here (-lm in our case) in the "LIBS" variable.
|
||||
|
||||
LIBS = -lm
|
||||
|
||||
###
|
||||
CFLAGS = -std=c99
|
||||
CFLAGS += -g
|
||||
CFLAGS += -Wall
|
||||
CFLAGS += -Wextra
|
||||
CFLAGS += -pedantic
|
||||
CFLAGS += -Werror
|
||||
CFLAGS += -Wmissing-declarations
|
||||
CFLAGS += -DUNITY_SUPPORT_64
|
||||
|
||||
ASANFLAGS = -fsanitize=address
|
||||
ASANFLAGS += -fno-common
|
||||
ASANFLAGS += -fno-omit-frame-pointer
|
||||
|
||||
.PHONY: test
|
||||
test: tests.out
|
||||
@./tests.out
|
||||
|
||||
.PHONY: memcheck
|
||||
memcheck: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(ASANFLAGS) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o memcheck.out $(LIBS)
|
||||
@./memcheck.out
|
||||
@echo "Memory check passed"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -rf *.o *.out *.out.dSYM
|
||||
|
||||
tests.out: test/*.c src/*.c src/*.h
|
||||
@echo Compiling $@
|
||||
@$(CC) $(CFLAGS) src/*.c test/vendor/unity.c test/*.c -o tests.out $(LIBS)
|
73
c/roman-numerals/src/roman_numerals.c
Normal file
73
c/roman-numerals/src/roman_numerals.c
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "roman_numerals.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
static struct conv_s {
|
||||
unsigned char r;
|
||||
unsigned d;
|
||||
} conv[] = {
|
||||
{ 'M', 1000 },
|
||||
{ 'D', 500 },
|
||||
{ 'C', 100 },
|
||||
{ 'L', 50 },
|
||||
{ 'X', 10 },
|
||||
{ 'V', 5 },
|
||||
{ 'I', 1 }
|
||||
};
|
||||
|
||||
/* rules could differ (like IIII/VIIII instead of IV/IX), so it is better not
|
||||
* to harcode values like 4, 9, 40, 90 etc...
|
||||
* Example: the Colosseum gate 44 was written XLIIII, and not XLIV.
|
||||
* we can therefore add a parameter in function below, and add a rule in
|
||||
* the code to easily return a different notation.
|
||||
*/
|
||||
char *to_roman_numeral(unsigned int n /*, int notation */ )
|
||||
{
|
||||
unsigned cur=0, mult, pos=0, i;
|
||||
char res[64]={0}, *to;
|
||||
|
||||
/* max number = 3999 = MMMCMXCIX */
|
||||
if (n >= 4000) /* could be different if we */
|
||||
return NULL; /* accept the 5000 sign */
|
||||
|
||||
while (n) {
|
||||
/* we could : switch (notation) {
|
||||
* case ROMAN_RULE:
|
||||
*/
|
||||
if ((mult=n/conv[cur].d)) { /* >= current multiplier */
|
||||
if (mult%5==4) { /* 4 & 9 */
|
||||
res[pos++]=conv[cur].r;
|
||||
res[pos++]=conv[cur-mult/4].r; /* 4/4=1, 9/4=2 */
|
||||
} else { /* 1-3 & 5-8 */
|
||||
if (mult >= 5)
|
||||
res[pos++]=conv[cur-1].r;
|
||||
for (i=mult%5; i>0; --i)
|
||||
res[pos++]=conv[cur].r;
|
||||
}
|
||||
n-=mult*conv[cur].d;
|
||||
}
|
||||
cur+=2;
|
||||
}
|
||||
if ((to=malloc(pos+1)))
|
||||
memcpy(to, res, pos+1);
|
||||
return to;
|
||||
}
|
||||
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#ifdef UNIT_TEST
|
||||
#include <stdlib.h>
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int arg=1;
|
||||
unsigned i;
|
||||
|
||||
for (; arg<ac; ++arg) {
|
||||
i=atoi(av[arg]);
|
||||
printf("roman(%d)=%s\n", i, to_roman_numeral(i));
|
||||
}
|
||||
}
|
||||
#endif
|
20
c/roman-numerals/src/roman_numerals.h
Normal file
20
c/roman-numerals/src/roman_numerals.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef ROMAN_NUMERALS_H
|
||||
#define ROMAN_NUMERALS_H
|
||||
|
||||
#define ROMAN_RULE 0
|
||||
|
||||
char *to_roman_numeral(unsigned int number);
|
||||
|
||||
/* See GNUmakefile below for explanation
|
||||
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||
*/
|
||||
#if defined UNIT_TEST || defined DEBUG
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#ifdef TESTALL
|
||||
#undef TEST_IGNORE
|
||||
#define TEST_IGNORE() {}
|
||||
#endif
|
||||
|
||||
#endif
|
56
c/run-length-encoding/GNUmakefile
Normal file
56
c/run-length-encoding/GNUmakefile
Normal file
@@ -0,0 +1,56 @@
|
||||
# The original 'makefile' has a flaw:
|
||||
# 1) it overrides CFLAGS
|
||||
# 2) it does not pass extra "FLAGS" to $(CC) that could come from environment
|
||||
#
|
||||
# It means :
|
||||
# - we need to edit 'makefile' for different builds (DEBUG, etc...), which is
|
||||
# not practical at all.
|
||||
# - Also, it does not allow to run all tests without editing the test source
|
||||
# code.
|
||||
#
|
||||
# To use this makefile (GNU make only):
|
||||
# 1) copy it into exercise directory
|
||||
# 2) add ex.h to exercise include file
|
||||
# 3) add ex.c to exercise source code, and create a suitable main function
|
||||
# 4) use make with one of the following targets :
|
||||
# all: compile and run all predefined tests.
|
||||
# nowarn: compile with no -Werror, and run all predefined tests
|
||||
# debug: compile with -DDEBUG and run all predefined tests
|
||||
# mem: perform memcheck with all tests enabled
|
||||
# unit: build standalone (unit) bimary
|
||||
# unitnowarn: build standalone (unit) binary with -Werror disabled
|
||||
# unitdebug: build standalone binary with -DDEBUG
|
||||
#
|
||||
# Original 'makefile' targets can be used (test, memcheck, clean, ...)
|
||||
|
||||
.PHONY: default all nowarn debug mem unit unitnowarn unitdebug standalone
|
||||
|
||||
default: all
|
||||
|
||||
ALLSOURCES:=$(wildcard ./*.c)
|
||||
TESTSOURCES:=$(wildcard ./test_*.c)
|
||||
SRC:=$(filter-out $(TESTSOURCES),$(ALLSOURCES))
|
||||
|
||||
include makefile
|
||||
|
||||
all: CFLAGS+=-DTESTALL
|
||||
all: clean test
|
||||
|
||||
nowarn: CFLAGS:=$(filter-out -Werror,$(CFLAGS))
|
||||
nowarn: clean all
|
||||
|
||||
debug: CFLAGS+=-DDEBUG
|
||||
debug: all
|
||||
|
||||
mem: CFLAGS+=-DTESTALL
|
||||
mem: clean memcheck
|
||||
|
||||
unitnowarn: CFLAGS:=$(filter-out -Werror,$(CFLAGS))
|
||||
unitnowarn: clean unit
|
||||
|
||||
unitdebug: CFLAGS+=-DDEBUG
|
||||
unitdebug: clean unit
|
||||
|
||||
unit: CFLAGS+=-DUNIT_TEST
|
||||
unit: *.c *.h
|
||||
$(CC) $(CFLAGS) $(SRC) -o tests.out $(LIBS)
|
63
c/run-length-encoding/HELP.md
Normal file
63
c/run-length-encoding/HELP.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
Get the first test compiling, linking and passing by following the [three rules of test-driven development][3-tdd-rules].
|
||||
|
||||
The included makefile can be used to create and run the tests using the `test` task.
|
||||
|
||||
```console
|
||||
$ make test
|
||||
```
|
||||
|
||||
Create just the functions you need to satisfy any compiler errors and get the test to fail.
|
||||
Then write just enough code to get the test to pass.
|
||||
Once you've done that, move onto the next test.
|
||||
|
||||
As you progress through the tests, take the time to refactor your implementation for readability and expressiveness and then go on to the next test.
|
||||
|
||||
Try to use standard C99 facilities in preference to writing your own low-level algorithms or facilities by hand.
|
||||
|
||||
[3-tdd-rules]: http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit run_length_encoding.c run_length_encoding.h` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [C track's documentation](https://exercism.org/docs/tracks/c)
|
||||
- [Exercism's support channel on gitter](https://gitter.im/exercism/support)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
Make sure you have read the "Guides" section of the [C track][c-track] on the Exercism site.
|
||||
This covers the basic information on setting up the development environment expected by the exercises.
|
||||
|
||||
## Submitting Incomplete Solutions
|
||||
|
||||
If you are struggling with a particular exercise, it is possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
||||
## Resources
|
||||
|
||||
To get help if having trouble, you can use the following resources:
|
||||
|
||||
- [StackOverflow][] can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
|
||||
- [CPPReference][] can be used to look up information on C concepts, operators, types, standard library functions and more.
|
||||
- [TutorialsPoint][] has similar content as CPPReference in its C programming section.
|
||||
- [The C Programming][K&R] book by K&R is the original source of the language and is still useful today.
|
||||
|
||||
[c-track]: https://exercism.io/my/tracks/c
|
||||
[stackoverflow]: http://stackoverflow.com/questions/tagged/c
|
||||
[cppreference]: https://en.cppreference.com/w/c
|
||||
[tutorialspoint]: https://www.tutorialspoint.com/cprogramming/
|
||||
[K&R]: https://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628/
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user