373 lines
9.7 KiB
C
373 lines
9.7 KiB
C
#include <assert.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h> // Not used in the challenge, only for assertions.
|
|
#include <string.h>
|
|
|
|
// 1st challenge
|
|
|
|
/**
|
|
* @brief Function to calculate the length of a string
|
|
*
|
|
* @details This function calculates the length of a string by counting the
|
|
* number of characters until the null terminator.
|
|
*
|
|
* @param `string` The string to calculate the length of
|
|
*
|
|
* @return The length of the string
|
|
*/
|
|
int my_strlen(const char *string) {
|
|
int i = 0;
|
|
int total = 0;
|
|
char letter = string[0];
|
|
|
|
while (letter != '\0') {
|
|
total++;
|
|
letter = string[++i];
|
|
}
|
|
|
|
return total;
|
|
};
|
|
|
|
/**
|
|
* @brief Function to assert the length of a string
|
|
*
|
|
* @details This function asserts that the length of a string is equal to the
|
|
* length of the string calculated by the standard strlen function.
|
|
*
|
|
* @param `string` The string to assert the length of
|
|
*
|
|
* @return 0 if the assertion passes
|
|
*/
|
|
int assert_string(const char *string) {
|
|
assert(my_strlen(string) == strlen(string));
|
|
return 0;
|
|
}
|
|
|
|
// 1st challenge, application
|
|
void strlen_test(void) {
|
|
const char *test1 = "IAE CLUB";
|
|
const char *test2 = "House Of Code";
|
|
const char *test3 = "G";
|
|
const char *test4 = "";
|
|
|
|
printf(" Test 1: %s\n", test1);
|
|
printf(" Length : %d\n", my_strlen(test1));
|
|
assert_string(test1);
|
|
|
|
printf(" Test 2: %s\n", test2);
|
|
printf(" Length : %d\n", my_strlen(test2));
|
|
assert_string(test2);
|
|
|
|
printf(" Test 3: %s\n", test3);
|
|
printf(" Length : %d\n", my_strlen(test3));
|
|
assert_string(test3);
|
|
|
|
printf(" Test 4: %s\n", test4);
|
|
printf(" Length : %d\n", my_strlen(test4));
|
|
assert_string(test4);
|
|
}
|
|
|
|
// 2nd challenge
|
|
|
|
/**
|
|
* @brief Function to reverse a string
|
|
*
|
|
* @details This function reverses a string by swapping the first and last
|
|
* characters, then moving towards the center of the string.
|
|
* --------------------------------------------------------------
|
|
* theoretical visualisation:
|
|
* [(A)][B][C][D][(E)] -> [E][(B)][C][D][(A)] -> [E][D][C][B][A] -> Done
|
|
*
|
|
* @param `str` The string to reverse
|
|
*/
|
|
void reverse_string(char *str) {
|
|
int first = 0, last = my_strlen(str) - 1;
|
|
// we remove the \0
|
|
// WARN: don't put this stupid comment
|
|
|
|
while (first < last) {
|
|
char temporary = str[first];
|
|
str[first] = str[last];
|
|
str[last] = temporary;
|
|
first++, last--;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Function to assert the reverse of a string
|
|
*
|
|
* @details This function asserts that the reverse of a string is equal to the
|
|
* original string.
|
|
*
|
|
* @param `string` The string to assert the reverse of
|
|
*
|
|
* @return 0 if the assertion passes
|
|
*/
|
|
int assert_reverse(const char *string) {
|
|
char *copy = strdup(string);
|
|
reverse_string(copy);
|
|
reverse_string(copy);
|
|
assert(strcmp(string, copy) == 0);
|
|
free(copy);
|
|
return 0;
|
|
}
|
|
|
|
// 2nd challenge, application
|
|
void invert_test(void) {
|
|
char test1[] = " edoc fo esuoH oT emocleW ";
|
|
char test2[] = " uoy pleh lliw ti ;3 melborp ni noitcnuf siht esU ";
|
|
char test3[] = " Hello World ";
|
|
char test4[] = "G";
|
|
|
|
printf(" Before : %s\n", test1);
|
|
reverse_string(test1);
|
|
printf(" After : %s\n\n", test1);
|
|
assert_reverse(test1);
|
|
|
|
printf(" Before : %s\n", test2);
|
|
reverse_string(test2);
|
|
printf(" After : %s\n\n", test2);
|
|
assert_reverse(test2);
|
|
|
|
printf(" Before : %s\n", test3);
|
|
reverse_string(test3);
|
|
printf(" After : %s\n\n", test3);
|
|
assert_reverse(test3);
|
|
|
|
printf(" Before : %s\n", test4);
|
|
reverse_string(test4);
|
|
printf(" After : %s\n\n", test4);
|
|
assert_reverse(test4);
|
|
}
|
|
|
|
// 3rd challenge
|
|
|
|
/**
|
|
* @brief Function to reverse the words in a string
|
|
*
|
|
* @details This function reverses the words in a string by first splitting the
|
|
* string into words, then reversing each word, and finally reversing the entire
|
|
* string.
|
|
*
|
|
* @param `str` The string to reverse the words of
|
|
*/
|
|
void reverse_words(char str[]) {
|
|
// Algorithm is straight forward
|
|
int i = 0, j = 0, pos = 0, glob = 0;
|
|
char word[20][20] = {' '}; // Dirty fix, should be dynamic using malloc
|
|
// clang-format off
|
|
// INFO: malloc function to use: (char **)malloc((count + 1) * sizeof(char*));
|
|
// but I don't feel like manipulating pointers too much. (I use C++ more)
|
|
// clang-format on
|
|
printf("%s", word[0]);
|
|
// Get the lenght of the string and loop around, then split the words.
|
|
for (i = 0; i < my_strlen(str); i++) {
|
|
if ((str[i] == ' ') || (str[i] == '\0')) {
|
|
word[pos][j] = '\0';
|
|
pos++, j = 0;
|
|
} else {
|
|
word[pos][j] = str[i];
|
|
j++;
|
|
}
|
|
}
|
|
|
|
// For each word, reverse it
|
|
for (i = 0; i <= pos; i++) {
|
|
reverse_string(word[i]);
|
|
}
|
|
|
|
// Then reverse the entire string
|
|
for (i = 0; i <= pos; i++) {
|
|
for (j = 0; j < my_strlen(word[i]); j++) {
|
|
str[glob] = word[i][j];
|
|
glob++;
|
|
}
|
|
if (i != pos) {
|
|
printf(" ");
|
|
}
|
|
glob++;
|
|
}
|
|
|
|
reverse_string(str);
|
|
}
|
|
|
|
/**
|
|
* @brief Function to assert the reverse of a string
|
|
*
|
|
* @details This function asserts that the reverse of a string is equal to the
|
|
* original string.
|
|
*
|
|
* @param `string` The string to assert the reverse of
|
|
*
|
|
* @return 0 if the assertion passes
|
|
*/
|
|
int assert_reverse_words(const char *string) {
|
|
char *copy = strdup(string); // We don't want to alter the original string
|
|
reverse_words(copy);
|
|
reverse_words(copy);
|
|
assert(strcmp(string, copy) == 0);
|
|
free(copy);
|
|
return 0;
|
|
}
|
|
|
|
// 3rd challenge, application
|
|
void reverse_test(void) {
|
|
char test1[] = "The dragons are coming";
|
|
char test2[] = "code love I";
|
|
char test3[] = "G";
|
|
|
|
printf("Before : %s\n", test1);
|
|
reverse_words(test1);
|
|
printf("After : %s\n\n", test1);
|
|
assert_reverse_words(test1);
|
|
|
|
printf("Before : %s\n", test2);
|
|
reverse_words(test2);
|
|
printf("After : %s\n\n", test2);
|
|
assert_reverse_words(test2);
|
|
|
|
printf("Before : %s\n", test3);
|
|
reverse_words(test3);
|
|
printf("After : %s\n\n", test3);
|
|
assert_reverse_words(test3);
|
|
|
|
// HACK: dirty scren cleanup
|
|
printf("\n\n");
|
|
}
|
|
|
|
/**
|
|
* @brief Function to check if two characters are matching brackets
|
|
*
|
|
* @note helper function for `isValid()`
|
|
*
|
|
* @param `c1` The first character
|
|
*
|
|
* @param `c2` The second character
|
|
*
|
|
* @return true if the characters are matching brackets, false otherwise
|
|
*/
|
|
bool checkMatch(char c1, char c2) {
|
|
if (c1 == '(' && c2 == ')')
|
|
return true;
|
|
if (c1 == '[' && c2 == ']')
|
|
return true;
|
|
if (c1 == '{' && c2 == '}')
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// Fourth challenge
|
|
|
|
/**
|
|
* @brief Function to check if a string has valid brackets
|
|
* @details This function checks if a string has valid brackets by using a stack
|
|
* to keep track of the opening brackets. When a closing bracket is found, the
|
|
* top of the stack is checked to see if it matches the closing bracket. If the
|
|
* stack is empty or the brackets do not match, the function returns false.
|
|
*
|
|
* --------------------------------------------------------------
|
|
*
|
|
* theoretical visualisation: (| | are the "comments")
|
|
* [{(})] -> | [ stored | [{(})] -> | ( stored | [{(})] -> | ) matches | [{(}]
|
|
* -> | } stored | [{(}] -> | ] matches | [{(] -> | false
|
|
*
|
|
* @param `s` The string to check
|
|
*
|
|
* @return true if the string has valid brackets, false otherwise
|
|
*/
|
|
bool isValid(const char *s) {
|
|
char stack[100]; // gross way of allocating memory
|
|
int top = -1; // below 0, so we can check if it's empty
|
|
|
|
// Keep iterating till the end of the string
|
|
for (int i = 0; s[i] != '\0'; i++) {
|
|
char c = s[i]; // Get the character at the current index
|
|
|
|
// If the character is an opening bracket, push it onto the stack
|
|
if (c == '(' || c == '{' || c == '[') {
|
|
// WARN: As with static memory allocation, this shouldn't be done on real
|
|
// code. Besides, *just use C++ for real work*.
|
|
|
|
// If there is an overflow, return false
|
|
if (top >= 100 - 1) {
|
|
return false;
|
|
}
|
|
stack[++top] = c;
|
|
// Same thing goes here, but we check if the closing bracket matches the
|
|
// top
|
|
} else if (c == '}' || c == ']' || c == ')') {
|
|
// If there is a mismatch or it's not empty, return false
|
|
if (top == -1 || !checkMatch(stack[top], c)) {
|
|
return false;
|
|
}
|
|
top--;
|
|
}
|
|
}
|
|
|
|
// Debugging statement
|
|
// printf("Top: %d\n", top);
|
|
|
|
// If the stack is empty, the string has valid brackets
|
|
return top == -1;
|
|
}
|
|
|
|
/**
|
|
* @brief Function to assert the validity of a string
|
|
*
|
|
* @details This function asserts that the validity of a string is equal to the
|
|
* expected value.
|
|
*
|
|
* @param `string` The string to assert the validity of
|
|
*
|
|
* @param `expected` The expected value
|
|
*
|
|
* @return 0 if the assertion passes
|
|
*/
|
|
int assert_brackets(const char *string, bool expected) {
|
|
// Actually i don't know why we i added this, most likely for the sake of
|
|
// consistency
|
|
assert(isValid(string) ? expected : !expected);
|
|
return 0;
|
|
}
|
|
|
|
// Fourth challenge, application
|
|
void check(void) {
|
|
const char *test1 = "()";
|
|
const char *test2 = "[{() }]";
|
|
const char *test3 = "{[( a+b) * x}";
|
|
const char *test4 = "{[ a+b ]*( x/y)}";
|
|
|
|
printf("Test 1: %s\n", test1);
|
|
printf("Is valid : %s\n", isValid(test1) ? "Yes" : "No");
|
|
assert_brackets(test1, true);
|
|
|
|
printf("Test 2: %s\n", test2);
|
|
printf("Is valid : %s\n", isValid(test2) ? "Yes" : "No");
|
|
assert_brackets(test2, true);
|
|
|
|
printf("Test 3: %s\n", test3);
|
|
printf("Is valid : %s\n", isValid(test3) ? "Yes" : "No");
|
|
assert_brackets(test3, false);
|
|
|
|
printf("Test 4: %s\n", test4);
|
|
printf("Is valid : %s\n", isValid(test4) ? "Yes" : "No");
|
|
assert_brackets(test4, true);
|
|
}
|
|
|
|
// Global test function of all challenges
|
|
int main(void) {
|
|
printf("----------[1]----------\n");
|
|
strlen_test();
|
|
printf("----------[2]----------\n");
|
|
invert_test();
|
|
printf("----------[3]----------\n");
|
|
reverse_test();
|
|
printf("----------[4]----------\n");
|
|
check();
|
|
printf("--------[BONUS]--------\n");
|
|
printf("Check the bonus/main.c file for the bonus challenge.\n");
|
|
|
|
return 0;
|
|
}
|