diff --git a/data_structures/list/Makefile b/data_structures/list/Makefile index 9fda5ca1d6..fc39cf8d5d 100644 --- a/data_structures/list/Makefile +++ b/data_structures/list/Makefile @@ -1,12 +1,17 @@ CC = gcc -CFLAGS = -g -c -Wall +CFLAGS = -g -Wall -c all: main + main: main.o list.o - $(CC) -g main.o list.o -o main + $(CC) main.o list.o -o main + +main.o: main.c list.h + $(CC) $(CFLAGS) main.c -list.o: list.c +list.o: list.c list.h $(CC) $(CFLAGS) list.c clean: - rm *o main + rm -f *.o main + diff --git a/data_structures/list/list.c b/data_structures/list/list.c index 762ffdfaad..6a05d7bf17 100644 --- a/data_structures/list/list.c +++ b/data_structures/list/list.c @@ -1,80 +1,124 @@ #include "list.h" -#include + #include -#include -#include #include +#include -#define L List_T +/** Initial capacity for new lists */ +#define LIST_INITIAL_CAPACITY 8 -/* Initial list */ -L List_init(void) +/** + * @brief Resize the internal array to a new capacity. + * @param list Pointer to the List. + * @param new_capacity New capacity. + * @return 0 on success, -1 on failure. + */ +static int list_resize(List* list, size_t new_capacity) { - L list; - list = (L)malloc(sizeof(L)); - list->next = NULL; - return list; + void** new_items = realloc(list->items, new_capacity * sizeof(void*)); + if (!new_items) + return -1; + list->items = new_items; + list->capacity = new_capacity; + return 0; } -/* Push an element into top of the list */ -L List_push(L list, void *val) +List* list_init(void) { - L new_elem = (L)malloc(sizeof(L)); - new_elem->val = val; - new_elem->next = list; - return new_elem; + List* list = malloc(sizeof(List)); + if (!list) + return NULL; + + list->items = malloc(LIST_INITIAL_CAPACITY * sizeof(void*)); + if (!list->items) + { + free(list); + return NULL; + } + + list->size = 0; + list->capacity = LIST_INITIAL_CAPACITY; + return list; } -/* Length of list */ -int List_length(L list) +int list_append(List* list, void* val) { - int n; - for (n = 0; list; list = list->next) n++; - return n - 1; + if (list->size >= list->capacity) + { + if (list_resize(list, list->capacity * 2) != 0) + return -1; + } + list->items[list->size++] = val; + return 0; } -/* Convert list to array */ -void **List_toArray(L list) +int list_insert(List* list, size_t index, void* val) { - int i, n = List_length(list) + 1; - void **array = (void **)malloc((n + 1) * sizeof(*array)); + if (index > list->size) + return -1; - for (i = 0; i < n; i++) + if (list->size >= list->capacity) { - array[i] = list->val; - list = list->next; + if (list_resize(list, list->capacity * 2) != 0) + return -1; } - array[i] = NULL; + + memmove(&list->items[index + 1], &list->items[index], + (list->size - index) * sizeof(void*)); + list->items[index] = val; + list->size++; + return 0; +} + +void* list_pop(List* list) +{ + if (list->size == 0) + return NULL; + + return list->items[--list->size]; +} + +size_t list_length(const List* list) { return list->size; } + +void** list_to_array(const List* list) +{ + void** array = malloc((list->size + 1) * sizeof(void*)); + if (!array) + return NULL; + + memcpy(array, list->items, list->size * sizeof(void*)); + array[list->size] = NULL; return array; } -/* Create and return a list */ -L List_list(L list, void *val, ...) +List* list_from_args(void* first, ...) { va_list ap; - L *p = &list; + List* list = list_init(); + if (!list) + return NULL; - va_start(ap, val); - for (; val; val = va_arg(ap, void *)) + va_start(ap, first); + void* val = first; + while (val != NULL) { - *p = malloc(sizeof(L)); - (*p)->val = val; - p = &(*p)->next; + if (list_append(list, val) != 0) + { + list_free(list); + va_end(ap); + return NULL; + } + val = va_arg(ap, void*); } - *p = NULL; va_end(ap); + return list; } -/* Append 2 lists together */ -L List_append(L list, L tail) +void list_free(List* list) { - L *p = &list; - while ((*p)->next) - { - p = &(*p)->next; - } - - *p = tail; - return list; + if (!list) + return; + free(list->items); + free(list); } diff --git a/data_structures/list/list.h b/data_structures/list/list.h index 3d31f42de1..c5c6348cdd 100644 --- a/data_structures/list/list.h +++ b/data_structures/list/list.h @@ -1,24 +1,80 @@ #ifndef __LIST__ #define __LIST__ -#define L List_T -typedef struct L *L; +#include -struct L +/** + * @file list.h + * @brief Dynamic array of generic pointers, similar to Python lists. + */ + +/** + * @struct List + * @brief Represents a dynamic array of void pointers. + */ +typedef struct { - void *val; - L next; -}; - -extern L List_init(void); -extern L List_push(L list, void *val); -extern int List_length(L list); -extern void **List_toArray(L list); -extern L List_append(L list, L tail); -extern L List_list(L list, void *val, ...); -/* TODO */ -extern L List_copy(L list); -extern int List_pop(L *list); - -#undef L + void **items; /**< Pointer to array of elements */ + size_t size; /**< Current number of elements */ + size_t capacity; /**< Allocated capacity */ +} List; + +/** + * @brief Initialize a new empty list. + * @return Pointer to the newly created List. + */ +List *list_init(void); + +/** + * @brief Append an element to the end of the list. + * @param list Pointer to the List. + * @param val Pointer to the value to append. + * @return 0 on success, -1 on allocation failure. + */ +int list_append(List *list, void *val); + +/** + * @brief Insert an element at a given index. + * @param list Pointer to the List. + * @param index Position to insert. + * @param val Pointer to the value to insert. + * @return 0 on success, -1 on error. + */ +int list_insert(List *list, size_t index, void *val); + +/** + * @brief Remove and return the last element from the list. + * @param list Pointer to the List. + * @return Pointer to the removed element, NULL if list is empty. + */ +void *list_pop(List *list); + +/** + * @brief Get the number of elements in the list. + * @param list Pointer to the List. + * @return Number of elements. + */ +size_t list_length(const List *list); + +/** + * @brief Convert the list to a NULL-terminated array. + * @param list Pointer to the List. + * @return Pointer to a newly allocated array. Caller must free it. + */ +void **list_to_array(const List *list); + +/** + * @brief Create a list from variable arguments, ending with NULL. + * @param first Pointer to the first element. + * @param ... Subsequent elements ending with NULL. + * @return Pointer to the newly created List. + */ +List *list_from_args(void *first, ...); + +/** + * @brief Free the list structure (does not free individual elements). + * @param list Pointer to the List. + */ +void list_free(List *list); + #endif diff --git a/data_structures/list/main.c b/data_structures/list/main.c index 95c11b6601..25bb331f35 100644 --- a/data_structures/list/main.c +++ b/data_structures/list/main.c @@ -1,37 +1,91 @@ +/** + * @file main.c + * @brief Tests the dynamic array-based List implementation. + * @details Demonstrates append, insert, pop, and conversion to array. + * @author Pranveer + */ + #include #include #include #include + #include "list.h" -void print_list(char **array) +/** + * @brief Prints a NULL-terminated array of strings. + * @param array Pointer to the array of strings. + */ +void print_string_array(char** array) { - int i; - for (i = 0; array[i]; i++) printf("%s", array[i]); + for (size_t i = 0; array[i]; i++) printf("%s", array[i]); printf("\n"); } -int main() +/** + * @brief Self-test implementation for List. + */ +static void test_list() { - List_T list1, list2, list3; - char **str1 = (char **)malloc(100 * sizeof(char *)); - - list1 = List_init(); - list1 = List_push(list1, "Dang "); - list1 = List_push(list1, "Hoang "); - list1 = List_push(list1, "Hai "); - printf("List 1: "); - str1 = (char **)List_toArray(list1); - print_list(str1); - - list2 = List_init(); - list2 = List_list(list2, "Mentor ", "Graphics ", "Siemens", NULL); - printf("List 2: "); - print_list((char **)List_toArray(list2)); - - list3 = List_append(list1, list2); - printf("Test append list2 into list1: "); - print_list((char **)List_toArray(list3)); + // Initialize a new list + List* list1 = list_init(); + assert(list1 != NULL); + assert(list_length(list1) == 0); + + // Append elements + assert(list_append(list1, "Hai ") == 0); + assert(list_append(list1, "Hoang ") == 0); + assert(list_append(list1, "Dang ") == 0); + assert(list_length(list1) == 3); + + // Convert to array and check order + void** array1 = list_to_array(list1); + assert(strcmp(array1[0], "Hai ") == 0); + assert(strcmp(array1[1], "Hoang ") == 0); + assert(strcmp(array1[2], "Dang ") == 0); + assert(array1[3] == NULL); + free(array1); + + // Insert element at index 1 + assert(list_insert(list1, 1, "Inserted ") == 0); + assert(list_length(list1) == 4); + void** array2 = list_to_array(list1); + assert(strcmp(array2[1], "Inserted ") == 0); + free(array2); + + // Pop element + void* popped = list_pop(list1); + assert(strcmp((char*)popped, "Dang ") == 0); + assert(list_length(list1) == 3); + + // Create a list from variadic arguments + List* list2 = list_from_args("Mentor ", "Graphics ", "Siemens", NULL); + assert(list2 != NULL); + assert(list_length(list2) == 3); + // Append list2 into list1 manually + for (size_t i = 0; i < list_length(list2); i++) + assert(list_append(list1, list2->items[i]) == 0); + assert(list_length(list1) == 6); + + // Convert to array and print + char** final_array = (char**)list_to_array(list1); + printf("Final list: "); + print_string_array(final_array); + free(final_array); + + // Free lists + list_free(list1); + list_free(list2); + + printf("All list tests passed successfully!\n"); +} + +/** + * @brief Main function. + */ +int main() +{ + test_list(); return 0; }