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
|
*.out
|
||||||
*_test.sh
|
*_test.sh
|
||||||
test/
|
test/
|
||||||
|
test-framework/
|
||||||
|
users/
|
||||||
.exercism
|
.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"
|
#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
|
/* test does not include invalid input, but it should, as the subject is
|
||||||
* about DNA sequence, not ASCII chars sequence :-)
|
* about DNA sequence, not ASCII chars sequence :-)
|
||||||
* exercism test needs only:
|
* exercism test needs only:
|
||||||
@@ -16,22 +7,25 @@
|
|||||||
*/
|
*/
|
||||||
#define V(p) (*(p)=='A' || *(p)=='C' || *(p)=='G' || *(p)=='T')
|
#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;
|
int res=0;
|
||||||
const char *l=lhs, *r=rhs;
|
|
||||||
|
|
||||||
if (!l || !r)
|
if (!l || !r)
|
||||||
return -1;
|
return -1;
|
||||||
for (; V(l) && V(r); ++l, ++r) {
|
for (; V(l) && V(r); ++l, ++r)
|
||||||
if (*l != *r)
|
if (*l != *r)
|
||||||
res++;
|
res++;
|
||||||
}
|
return *l || *r? -1: res;
|
||||||
return *r || *l? -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)
|
int main(int ac, char **av)
|
||||||
{
|
{
|
||||||
if (ac==3) {
|
if (ac==3) {
|
||||||
|
@@ -3,9 +3,8 @@
|
|||||||
|
|
||||||
int compute(const char *lhs, const char *rhs);
|
int compute(const char *lhs, const char *rhs);
|
||||||
|
|
||||||
/* Note: For explanation on section below, see 'GNUfilename' included in
|
/* See GNUmakefile below for explanation
|
||||||
* link below :
|
* https://github.com/braoult/exercism/blob/master/c/templates/GNUmakefile
|
||||||
* https://exercism.io/my/solutions/103b2f7d92db42309c1988030f5202c7
|
|
||||||
*/
|
*/
|
||||||
#ifdef TESTALL
|
#ifdef TESTALL
|
||||||
#undef TEST_IGNORE
|
#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>
|
#include <stdlib.h>
|
||||||
#endif
|
#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);
|
resistor_band_t c1=*colors, c2=*(colors+1);
|
||||||
|
|
||||||
return c1>=BLACK && c1<=WHITE && c2>=BLACK && c2<=WHITE? c1*10+c2: ERROR;
|
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) {
|
for (; arg<ac-1; ++arg, ++arg) {
|
||||||
*i=atoi(av[arg]);
|
*i=atoi(av[arg]);
|
||||||
*(i+1)=atoi(av[arg+1]);
|
*(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
|
#endif
|
||||||
|
@@ -15,7 +15,7 @@ typedef enum {
|
|||||||
ERROR=-1,
|
ERROR=-1,
|
||||||
} resistor_band_t;
|
} 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
|
#ifdef TESTALL
|
||||||
#undef TEST_IGNORE
|
#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