first commit
This commit is contained in:
commit
d88d439df3
92
phase_1/bonus/main.c
Normal file
92
phase_1/bonus/main.c
Normal 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
372
phase_1/obligatory/strlen.c
Normal 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;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user