first commit

This commit is contained in:
Midou 2025-03-10 08:51:18 +00:00
commit d88d439df3
Signed by: midou
GPG Key ID: 1D134A95FE521A7A
2 changed files with 464 additions and 0 deletions

92
phase_1/bonus/main.c Normal file
View File

@ -0,0 +1,92 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* @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);
}

372
phase_1/obligatory/strlen.c Normal file
View File

@ -0,0 +1,372 @@
#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;
}