diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4c7608a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,33 @@ +name: C CI + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install GCC and tools + run: | + sudo apt-get update + sudo apt-get install -y build-essential gcc lcov + + - name: Build and test + run: | + gcc -o main 05_hw/stack.c 05_hw/main.c -fsanitize=address -fsanitize=undefined -fprofile-arcs -ftest-coverage + ./main + + - name: Generate coverage report + run: | + gcov 05_hw/stack.c + lcov --capture --directory . --output-file coverage.info + genhtml coverage.info --output-directory coverage diff --git a/05_hw/main.c b/05_hw/main.c index fded814..60c5f24 100644 --- a/05_hw/main.c +++ b/05_hw/main.c @@ -1,34 +1,95 @@ #include "stack.h" - +#include #include +#include -int main() { +void test_stack_operations() { + printf("Start of testing\n"); Stack stack; initStack(&stack); + assert(isEmpty(&stack) == true); + printf("The initial stack\n"); + traverseStack(&stack); push(&stack, 10); + assert(stack.top->data == 10); push(&stack, 20); push(&stack, 30); - printf("After pushing elements:\n"); + assert(isEmpty(&stack) == false); + printf("Stack after adding elements\n"); + traverseStack(&stack); + assert(getTop(&stack)->data == 30); + assert(pop(&stack) == true); + printf("Stack after excluding the last element\n"); traverseStack(&stack); - pop(&stack); - printf("After popping an element:\n"); - traverseStack(&stack); + assert(getTop(&stack)->data == 20); + + assert(searchByValue(&stack, 20) != NULL); + assert(searchByValue(&stack, 100) == NULL); + + assert(searchByIndex(&stack, 0)->data == 20); + assert(searchByIndex(&stack, 1)->data == 10); + assert(searchByIndex(&stack, 2) == NULL); + + destroyStack(&stack); + assert(isEmpty(&stack) == true); + printf("End of testing\n"); +} + +// Функция для измерения времени выполнения push +void benchmark_push(Stack* stack, int num_operations) { + clock_t start, end; + double cpu_time_used; + + start = clock(); // Засекаем время начала + for (int i = 0; i < num_operations; i++) { + push(stack, i); // Выполняем push + } + end = clock(); // Засекаем время окончания + + cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; + printf("Push benchmark: %d operations took %f seconds\n", num_operations, cpu_time_used); +} + +// Функция для измерения времени выполнения pop +void benchmark_pop(Stack* stack, int num_operations) { + clock_t start, end; + double cpu_time_used; - Node* searchResult = searchByValue(&stack, 20); - if (searchResult != NULL) { - printf("Element with value 20 found.\n"); - } else { - printf("Element with value 20 not found.\n"); + // Предварительно заполняем стек + for (int i = 0; i < num_operations; i++) { + push(stack, i); } - Node* topElement = getTop(&stack); - if (topElement != NULL) { - printf("Top element: %d\n", topElement->data); + start = clock(); // Засекаем время начала + for (int i = 0; i < num_operations; i++) { + pop(stack); // Выполняем pop } + end = clock(); // Засекаем время окончания + + cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC; + printf("Pop benchmark: %d operations took %f seconds\n", num_operations, cpu_time_used); +} + +int main() { + test_stack_operations(); + printf("All tests passed!\n"); + + Stack stack; + initStack(&stack); + + int num_operations = 1000000; // Количество операций + + // Бенчмарк push + benchmark_push(&stack, num_operations); + + // Бенчмарк pop + benchmark_pop(&stack, num_operations); + + destroyStack(&stack); return 0; } diff --git a/05_hw/stack.c b/05_hw/stack.c index 0964440..a0eb236 100644 --- a/05_hw/stack.c +++ b/05_hw/stack.c @@ -1,6 +1,5 @@ #include #include - #include "stack.h" Node* createNode(int data) { @@ -15,35 +14,46 @@ void initStack(Stack* stack) { } void destroyStack(Stack* stack) { + if (stack == NULL || stack->top == NULL) return; Node* current = stack->top; while (current != NULL) { - Node *tmp = current; + Node* tmp = current; current = current->next; - free(tmp); + free(tmp); } + stack->top = NULL; } void push(Stack* stack, int data) { + if (stack == NULL) return; Node* newNode = createNode(data); newNode->next = stack->top; stack->top = newNode; } -void pop(Stack* stack) { + +bool pop(Stack* stack) { + if (stack == NULL || stack->top == NULL) return false; Node* temp = stack->top; stack->top = stack->top->next; + free(temp); + return true; } + Node* searchByValue(Stack* stack, int value) { + if (stack == NULL) return NULL; Node* current = stack->top; while (current != NULL) { if (current->data == value) { return current; } + current = current->next; } return NULL; } + Node* searchByIndex(Stack* stack, int index) { Node* current = stack->top; int count = 0; @@ -57,11 +67,14 @@ Node* searchByIndex(Stack* stack, int index) { return NULL; } -Node* getTop(Stack* stack) { +Node* getTop(const Stack* stack) { + if (stack == NULL) return NULL; return stack->top; } -void traverseStack(Stack* stack) { + +void traverseStack(const Stack* stack) { + if (stack == NULL) return; Node* current = stack->top; printf("Stack elements: "); while (current != NULL) { @@ -71,8 +84,9 @@ void traverseStack(Stack* stack) { printf("\n"); } -bool isEmpty(Stack* stack) { - free(stack->top); - return stack->top == NULL; + +bool isEmpty(const Stack* stack) { + return stack == NULL || stack->top == NULL; } + diff --git a/05_hw/stack.h b/05_hw/stack.h index ef0734e..9e79136 100644 --- a/05_hw/stack.h +++ b/05_hw/stack.h @@ -23,17 +23,17 @@ void destroyStack(Stack *stack); void push(Stack* stack, int data); -void pop(Stack* stack); +bool pop(Stack* stack); Node* searchByValue(Stack* stack, int value); Node* searchByIndex(Stack* stack, int index); -Node* getTop(Stack* stack); +Node* getTop(const Stack* stack); -void traverseStack(Stack* stack); +void traverseStack(const Stack* stack); -bool isEmpty(Stack* stack); +bool isEmpty(const Stack* stack); #ifdef __cplusplus }