Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: C/C++ CI

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Set up CMake
uses: jwlawson/actions-setup-cmake@v1

- name: Install dependencies
run: sudo apt-get install -y gcc g++ cmake

- name: Configure CMake
run: cmake -B build -S 05_hw -DCMAKE_C_FLAGS="-fsanitize=address,undefined,leak -g"

- name: Build project
run: cmake --build build

- name: Run tests
run: ./build/stack_tests
10 changes: 10 additions & 0 deletions 05_hw/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
cmake_minimum_required(VERSION 3.10)

project(stack)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -g")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -g")

add_library(stack stack.c)

add_executable(main main.c)
target_link_libraries(main stack)

add_executable(stack_tests stack_tests.c stack.c)
target_link_libraries(stack_tests stack gcov)

add_executable(benchmark benchmark.c stack.c)
target_link_libraries(benchmark stack gcov)
55 changes: 39 additions & 16 deletions 05_hw/README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,45 @@
# Домашнее задание
# Отчет по лабораторной работе
**Выполнил студент Корязин Егор, группа М24-ИВТ-4**

Файлы stack.c и stack.h являются простой реализацией стека, хранящего целые числа.
В коде есть баги и ошибки.
## Ход работы

Необходимо привести код в порядок.
### 1. Исправить ошибки
Были исправлены ошибки в следующих функциях:
destroyStack, pop, searchByValue, isEmpty

* Исправить ошибки;
* Покрыть код тестами;
* Проверить покрытие кода тестами (убедиться, что все функции и условия протестированы);
* Выбрать статический анализатор и запустить его (исправить ошибки, если будут);
* Запустить тесты с санитайзерами (исправить ошибки, если будут);
* Для базовых функций (push / pop) написать бенчмарки;
* Изучить возможности Github Actions и настроить CI для тестирования (*).

Во время рефакторинга разрешается изменять не только код функций, но и их c сигнатуры,
если это будет оправдано с точки зрения использования/тестирования этих функций.

Решение - Pull Request с исправлением. Желательно разбивать изменения на атомарные коммиты
с целью повышения качества ревью и ускорения получения фидбека.
### 2. Покрыть код тестами
Все функции были покрыты тестами и проходят успешно:
![Все тесты прошли](/05_hw/images/sanitazier_not_error.jpg)

### 3. Проверить покрытие кода тестами
Для оценки покрытия кода тестами был использован инструмент lcov. Как видно на изображении ниже, тесты покрывают все участки кода.

![Отчет о покрытие тестами](/05_hw/images/coverage.jpg)

### 4. Выбрать статический анализатор и запустить его
Для анализа кода был использован статический анализатор Cppcheck. Было обнаружено несколько предупреждений:

![Статический анализатор 1](/05_hw/images/check_static_sanitazier.jpg)
![Статический анализатор 2](/05_hw/images/check_static_sanitazier_2.jpg)

После исправления некоторых моментов, список предупреждений был уменьшен (с некоторыми замечаниями был не согласен, поэтому не исправил их):

![Статический анализатор после исправлений](/05_hw/images/check_static_sanitazier_after_fix.jpg)

### 5. Запустить тесты с санитайзерами
Были запущены тесты с использованием AddressSanitizer для обнаружения потенциальных ошибок работы с памятью. Тесты прошли без ошибок:

![Нет ошибок от санитайзера](/05_hw/images/sanitazier_not_error.jpg)

Чтобы убедиться в работоспособности санитайзера, в код была добавлена ошибка. AddressSanitizer корректно указал на ошибку, как видно на следующих изображениях:

![Добавлена ошибка в код](/05_hw/images/special_error_in_code.png)
![Санитайзер обнаружил ошибку](/05_hw/images/special_error_sanitazier.png)

### 6. Написание бенчмарков для функций push и pop
Для базовых функций push и pop были написаны бенчмарки, чтобы оценить их временную сложность. На графике видно, что сложность функций приблизительно равна O(N).

![Результаты бенчмарка](/05_hw/images/bencmarking.jpg)

(*) - необязательное задание.
66 changes: 66 additions & 0 deletions 05_hw/benchmark.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "stack.h"

#define NUM_ITERATIONS 10000000

void benchmark_push(Stack* stack, int num_operations, bool print) {
clock_t start = clock();

for (int i = 0; i < num_operations; i++) {
push(stack, i);
}

clock_t end = clock();
double time_spent = (double)(end - start) / CLOCKS_PER_SEC;

if (print){
printf("Time taken for %d push operations: %f seconds\n", num_operations, time_spent);
}
}

void benchmark_pop(Stack* stack, int num_operations) {
clock_t start = clock();

for (int i = 0; i < num_operations; i++) {
pop(stack);
}

clock_t end = clock();
double time_spent = (double)(end - start) / CLOCKS_PER_SEC;

printf("Time taken for %d pop operations: %f seconds\n", num_operations, time_spent);
}

int main() {
Stack stack;
initStack(&stack);

printf("Benchmarking push operation:\n");

for (int i = 1000; i <= NUM_ITERATIONS; i *= 10) {
benchmark_push(&stack, i, true);

// Освобождаем стек после каждого теста
while (!isEmpty(&stack)) {
pop(&stack);
}
}

// Заполняем стек для тестирования pop
benchmark_push(&stack, NUM_ITERATIONS, false);

printf("\nBenchmarking pop operation:\n");

for (int i = 1000; i <= NUM_ITERATIONS; i *= 10) {
benchmark_pop(&stack, i);

// Восстанавливаем стек после каждого теста
benchmark_push(&stack, i, false);
}

destroyStack(&stack);

return 0;
}
Binary file added 05_hw/images/bencmarking.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 05_hw/images/check_static_sanitazier.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 05_hw/images/check_static_sanitazier_2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 05_hw/images/coverage.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 05_hw/images/sanitazier_not_error.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 05_hw/images/special_error_in_code.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added 05_hw/images/special_error_sanitazier.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 9 additions & 2 deletions 05_hw/stack.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include "stack.h"

// TODO: если будет не достаток памяти, может быть ошибка
Node* createNode(int data) {
Node* newNode = (Node*)malloc(sizeof(Node));
newNode->data = data;
Expand All @@ -21,6 +22,7 @@ void destroyStack(Stack* stack) {
current = current->next;
free(tmp);
}
stack->top = NULL;
}

void push(Stack* stack, int data) {
Expand All @@ -31,19 +33,25 @@ void push(Stack* stack, int data) {

void pop(Stack* stack) {
Node* temp = stack->top;
stack->top = stack->top->next;
if (temp != NULL) {
stack->top = stack->top->next;
free(temp);
}
}


Node* searchByValue(Stack* stack, int value) {
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;
Expand Down Expand Up @@ -72,7 +80,6 @@ void traverseStack(Stack* stack) {
}

bool isEmpty(Stack* stack) {
free(stack->top);
return stack->top == NULL;
}

Loading