diff --git a/include/name_string.h b/include/name_string.h index 8d6c473..9ea8ab0 100644 --- a/include/name_string.h +++ b/include/name_string.h @@ -26,8 +26,11 @@ typedef struct NAME_STR { string *create_from_cstr(const char *str); void destroy_string(string *str); -string *concatenate_string(string *str, string *other); -int compare_on_length(string *str, string *other); +string *concatenate_string(const string *str, const string *other); +void strip(string *str); + +int compare_on_length(const string *str, const string *other); +int compare_on_alphabet(const string *str, const string *other); #endif diff --git a/src/main.c b/src/main.c index fc81c1c..9fbbedd 100644 --- a/src/main.c +++ b/src/main.c @@ -1,23 +1,117 @@ #include +#include #include +#define MIN_VEC_SIZE 8 +//stdint guarantees the least types, unlike the standard uint32_t; +typedef uint_least32_t uint32; + +//Simple vector implementation for our strings +typedef struct str_vector +{ + string **array; + uint32 size; + uint32 _capacity; +} string_vector; + +string_vector *create_vector(uint32 capacity) +{ + if(capacity < MIN_VEC_SIZE) + { + capacity = MIN_VEC_SIZE; + } + string_vector *vec = malloc(sizeof(string_vector)); + vec->array = malloc(sizeof(string *) * capacity); + vec->size = 0; + vec->_capacity = capacity; + return vec; +} + +/* + * For our particular program, we don't need the ability to remove items from + * the vector, as we'll only ever be adding to it. + */ +void vector_add(string_vector *vector, string *str) +{ + if(vector->size == vector->_capacity) + { + string **new_array = malloc(sizeof(string *) * vector->_capacity * 2); + for(uint32 index = 0; index < vector->_capacity; index++) + { + new_array[index] = vector->array[index]; + } + free(vector->array); + vector->array = new_array; + vector->_capacity *= 2; + } + vector->array[vector->size] = str; + vector->size++; +} + +void print_vector(string_vector *vector) +{ + for(uint32 index = 0; index < vector->size; index++) + { + printf("%s", vector->array[index]->c_str); + } +} + +/* + * Compare function to be used by qsort. Due to the implementation in the C + * Standard Library, this function necessarily accepts void * and must cast to + * the type it expects. + */ +int compare(const void *str1, const void *str2) +{ + const string *first = *(const string **) str1; + const string *second = *(const string **) str2; + + int res = compare_on_length(first, second); + if(res == 0) + { + return compare_on_alphabet(first, second); + } + return res; +} + +/* + * Sorts the passed vector with the rules that: + * 1. Strings are sorted by length first, not alphabet. + * 2. Strings are sorted by alphabet only if they are the same length. + */ +void perform_length_alphabet_sort(string_vector *vector) +{ + qsort((void *) vector->array, vector->size, sizeof(string *), compare); +} + int main(int argc, char **argv) { - string *test = create_from_cstr("Testing"); - printf("String: %s\n", test->c_str); - printf("Size expected: %d\n", 7); - printf("Actual Size: %d\n", test->len); + char *tests[10] = { + "What ", + "Where", + " When", + " Why ", + "How", + "Test1", + "Test2", + "Anne", + "Jill", + "Bob" + }; - string *other = create_from_cstr("This is also a test"); - string *combined = concatenate_string(test, other); - printf("First String: %s\n", test->c_str); - printf("Second String: %s\n", other->c_str); - printf("Expected: TestingThis is also a test\n"); - printf("Actual: %s\n", combined->c_str); - printf("Length of first string: %d\n", test->len); - printf("Length of second string: %d\n", other->len); - printf("Expected Length: %d\n", test->len + other->len); - printf("Length of Combined String: %d\n", combined->len); + string_vector *vector = create_vector(0); + + for(uint32 index = 0; index < 10; index++) + { + string *str = create_from_cstr(tests[index]); + strip(str); + vector_add(vector, str); + } + + print_vector(vector); + perform_length_alphabet_sort(vector); + printf("\nSorted Array\n------------\n"); + print_vector(vector); return 0; } diff --git a/src/name_string.c b/src/name_string.c index 5d5d998..52b65a3 100644 --- a/src/name_string.c +++ b/src/name_string.c @@ -7,7 +7,7 @@ string *create_from_cstr(const char *str) { - string *new_str = (string *)malloc(sizeof(string)); + string *new_str = (string *) malloc(sizeof(string)); if(!str) { //The passed c string is a null or invalid pointer. @@ -24,7 +24,7 @@ string *create_from_cstr(const char *str) } //Make sure to +1 for the null byte at the end - new_str->c_str = (char *)malloc(sizeof(char)*size + 1); + new_str->c_str = (char *) malloc(sizeof(char) * size + 1); for(index = 0; index < size && *str != '\0'; index++) { new_str->c_str[index] = str[index]; @@ -47,17 +47,21 @@ void destroy_string(string *str) free(str); } -string *concatenate_string(string *str, string *other) +string *concatenate_string(const string *str, const string *other) { if(!str || !other) + { return NULL; + } if(str->len + other->len > MAX_STR_SIZE) + { return NULL; + } strlen_t total_len = str->len + other->len; - string *new_str = (string *)malloc(sizeof(string)); - new_str->c_str = (char *)malloc(sizeof(char)*total_len + 1); + string *new_str = (string *) malloc(sizeof(string)); + new_str->c_str = (char *) malloc(sizeof(char) * total_len + 1); new_str->len = total_len; for(strlen_t index = 0; index < str->len; index++) @@ -66,13 +70,78 @@ string *concatenate_string(string *str, string *other) } for(strlen_t index = 0; index < other->len; index++) { - new_str->c_str[index+str->len] = other->c_str[index]; + new_str->c_str[index + str->len] = other->c_str[index]; } new_str->c_str[total_len] = '\0'; return new_str; } -int compare_on_length(string *str, string *other) +static int is_whitespace(char c) +{ + if(c == ' ' || c == '\t' || c == '\n' || c == '\v') + { + return 1; + } + return 0; +} + +void strip(string *str) +{ + //Sanity check + if(!str || !str->c_str || str->len == 0) + { + return; + } + //Strip the left side + strlen_t lstrip_index = 0; + for(strlen_t index = 0; index < str->len; index++) + { + if(is_whitespace(str->c_str[index])) + { + lstrip_index++; + } + else + { + break; + } + } + + //Find right side strip index + strlen_t rstrip_index = str->len; + for(strlen_t index = str->len - 1; index >= 0; index--) + { + if(is_whitespace(str->c_str[index])) + { + rstrip_index--; + } + else + { + break; + } + } + + if(lstrip_index == rstrip_index) + { + free(str->c_str); + str->c_str = NULL; + str->len = 0; + } + else + { + strlen_t chop_off = lstrip_index + (str->len - rstrip_index); + char *new = malloc(sizeof(char) * (str->len - chop_off + 1)); + for(strlen_t index = lstrip_index; index < rstrip_index; index++) + { + new[index - lstrip_index] = str->c_str[index]; + } + new[rstrip_index - lstrip_index] = '\0'; + free(str->c_str); + str->c_str = new; + str->len -= chop_off; + } +} + +int compare_on_length(const string *str, const string *other) { if(str->len < other->len) { @@ -104,10 +173,10 @@ static char lowercase(char c) { return c; } - return (char)(c-32); + return (char) (c - 32); } -int compare_on_alphabet(string *str, string *other) +int compare_on_alphabet(const string *str, const string *other) { strlen_t min_len = min(str->len, other->len); for(strlen_t index = 0; index < min_len; index++) @@ -115,9 +184,13 @@ int compare_on_alphabet(string *str, string *other) char str_lower_char = lowercase(str->c_str[index]); char other_lower_char = lowercase(other->c_str[index]); if(str_lower_char < other_lower_char) + { return -1; + } else if(str_lower_char > other_lower_char) + { return 1; + } } //Only difference is length return compare_on_length(str, other);