From d88d439df3fc6187bf3a31f910125b140da8a748 Mon Sep 17 00:00:00 2001 From: Midou Date: Mon, 10 Mar 2025 08:51:18 +0000 Subject: [PATCH] first commit --- phase_1/bonus/main.c | 92 +++++++++ phase_1/obligatory/strlen.c | 372 ++++++++++++++++++++++++++++++++++++ 2 files changed, 464 insertions(+) create mode 100644 phase_1/bonus/main.c create mode 100644 phase_1/obligatory/strlen.c diff --git a/phase_1/bonus/main.c b/phase_1/bonus/main.c new file mode 100644 index 0000000..4e0709a --- /dev/null +++ b/phase_1/bonus/main.c @@ -0,0 +1,92 @@ +#include +#include +#include + +/** + * @brief Function to split a string into an array of strings + * + * @details This function splits a string into an array of strings using a + * delimiter character. The function allocates memory for the array of strings + * and the individual strings. The caller is responsible for freeing the memory + * allocated by this function. + * + * @param str The string to split + * @param delimiter The character to split the string by + * + * @return An array of strings + */ +char **split_str(const char *str, char delimiter) { + int count = 1; // Number of substrings (at least 1) + for (int i = 0; str[i] != '\0'; + i++) { // Count the number of delimiters until the end + if (str[i] == delimiter) + count++; + } + + // clang-format off + + // Allocate memory for the array of strings (+1 for NULL terminator) + // Code format for those who don't know: + // | (char **) for casting, something C++ already does (we love C) + // | malloc for allocating memory + // | (count + 1) * sizeof(char *) for the size of the array of strings + // | now for the memory size, since we previously counted the number of + // | delimiters we can use that to allocate the memory for the strings + char **result = (char **)malloc((count + 1) * sizeof(char *)); + if (!result) + return NULL; // In case there is not enough memory + + // let's get real: string will be " /IAE/ /CHALLENGE/" (space at first too) + int start = 0, pos = 0; + int len = strlen(str); // Length of the string: 18 + for (int i = 0; i <= len; i++) { // Loop through the string + if (str[i] == delimiter || + str[i] == + '\0') { // Found a delimiter or end of string (that would be "/") + int word_length = i - start; // Length of the word, in this case 1 + result[pos] = (char *)malloc( + (word_length + 1) * sizeof(char)); // Allocate memory for the word, + // size would be 1 + char size + if (!result[pos]) { + // Free previously allocated memory in case of failure + for (int j = 0; j < pos; j++) { + free(result[j]); + } + free(result); + return NULL; + } + strncpy(result[pos], &str[start], + word_length); // Copy the string from start to word_length + result[pos][word_length] = '\0'; // Null terminate + pos++; + start = i + 1; + } + } + + // clang-format on + + result[pos] = NULL; // Null terminate the array of strings + return result; // Return the array of strings +} + +int main(void) { + printf("--------[BONUS]--------"); + char *str = + " /IAE/ /CHALLENGE/"; // Change this to test with different strings + char **vector = split_str(str, '/'); + int i; + + i = 0; + while (vector[i] != NULL) { + printf("Substring %d : %s\n", i + 1, vector[i]); + i++; + } + + while (vector[i] != NULL) { + free(vector[i]); + i++; + } + + free(vector); + return (0); +} diff --git a/phase_1/obligatory/strlen.c b/phase_1/obligatory/strlen.c new file mode 100644 index 0000000..26f17bd --- /dev/null +++ b/phase_1/obligatory/strlen.c @@ -0,0 +1,372 @@ +#include +#include +#include +#include // Not used in the challenge, only for assertions. +#include + +// 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; +}