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
12 changes: 1 addition & 11 deletions .github/workflows/build-and-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,4 @@ jobs:
- uses: actions/checkout@v5
- name: Check format
run: |
find . -path ./build -prune -o -type f -name '*.[c|h]' -print | xargs clang-format-18 --style=file --dry-run -Werror
- name: Configure
run: |
# -DCMAKE_EXPORT_COMPILE_COMMANDS=ON is important for clang-tidy
cmake . -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
- name: Build
run: |
cmake --build build
- name: Lint
run: |
run-clang-tidy-18 -p=build
find . -path ./build -prune -o -type f -name '*.[c|h]' -print | xargs clang-format-18 --style=file --dry-run -Werror
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ project(C_Homework C)

add_subdirectory(src/CheckHowLintersWork)

add_subdirectory(src/ListTasks1)

set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

add_compile_options(-Wall -Wextra -Wpedantic)
5 changes: 5 additions & 0 deletions src/ListTasks1/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
add_library(listTask OneLinkedList.c)

add_executable(sortedListTask sortedListTask.c)

target_link_libraries(sortedListTask PRIVATE listTask)
117 changes: 117 additions & 0 deletions src/ListTasks1/OneLinkedList.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#include "OneLinkedList.h"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

list.h вполне нормальное название, но ладно

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct ListNode ListNode;

struct ListNode {
int value;
struct ListNode* next;
};
Comment on lines +6 to +11

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

это то же самое, что и

Suggested change
typedef struct ListNode ListNode;
struct ListNode {
int value;
struct ListNode* next;
};
typedef struct ListNode {
int value;
struct ListNode* next;
} ListNode;

но так тоже можно


struct List {
ListNode* head;
};

List* newList()
{
List* list = calloc(1, sizeof(*list));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Так можно, но лучше (как мне кажется) аллоцировать как угодно (malloc/calloc), и явно проинициализировать поля

return list;
}

bool isEmpty(List* list) { return list->head == NULL; }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Желательно чтобы все методы были в одном стиле

Suggested change
bool isEmpty(List* list) { return list->head == NULL; }
bool isEmpty(List* list) {
return list->head == NULL;
}


bool insert(List* list, int value)
{
if (list == NULL) {
return false;
}
ListNode* newNode = malloc(sizeof(ListNode));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нужно сделать проверку, что память действительно выделилась

ListNode* current = list->head;

if (isEmpty(list)) {
newNode->value = value;
newNode->next = list->head;
list->head = newNode;
return true;
}
// если элемент меньше самого маленького значения в голове
if (current->value > value) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В комментарии написано меньше, а тут больше :)
Надо поменять местами операнды (и поменять знак), так более явно соответствует комментарию

Suggested change
if (current->value > value) {
if (value < current->value) {

list->head = newNode;
newNode->next = current;
newNode->value = value;
return true;
}
// если элемент должен быть где-то в середине
while (current->next != NULL) {
if ((current->next->value > value) && (current->value <= value)) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это то же самое, что просто проверить, что value >= current->value, мы всегда знаем, что следующий будет точно >= value вследствие сортированности

newNode->next = current->next;
current->next = newNode;
newNode->value = value;
return true;
}
current = current->next;
}

// последний случай, когда элемент больше остальных
newNode->next = NULL;
current->next = newNode;
newNode->value = value;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Все три раза в newNode было записано value, это можно сделать сразу после аллокации (но после проверки аллокации!)

return true;
}

bool removeElement(List* list, int value)
{
if (list == NULL || isEmpty(list)) {
return false;
}
ListNode* current = list->head;

if (current->value == value) {
list->head = current->next;
free(current);
return true;
}

while (current->next != NULL && current->next->value != value) {
current = current->next;
}
if (current->next != NULL && current->next->value == value) {
ListNode* toDelete = current->next;
current->next = toDelete->next;
free(toDelete);
return true;
}
return false;
}

bool deleteList(List* list)
{
if (list == NULL) {
return false;
}
Comment on lines +91 to +93

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вообще free(NULL) - вполне нормальная операция, поэтому можно разрешить и то, что list - NULL, но так тоже можно

ListNode* current = list->head;
while (current != NULL) {
ListNode* toDelete = current;
current = current->next;
free(toDelete);
}
list->head = NULL;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это можно и не делать, list всё равно будет деаллоцирован

free(list);
return true;
}

void printList(List* list)
{
if (list == NULL || isEmpty(list)) {
printf("Список пустой\n");
return;
}
ListNode* current = list->head;
while (current != NULL) {
printf("%d ", current->value);
current = current->next;
}
printf("\n");
}
50 changes: 50 additions & 0 deletions src/ListTasks1/OneLinkedList.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once
#include <stdbool.h>

// структура содержащая указатель на список
typedef struct List List;

/*
* функция создания нового списка
* ничего не принимает
* возвращает указатель на список
*/
List* newList();
Comment on lines +7 to +12

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если функция ничего не принимает, то это сразу видно и можно не писать в комментарии :)


/*
* функция вставки элемента по заданному индексу
* принимает на вход указатель на список и значение
* возвращает булевое значение, сообщающее, удачно ли прошла операция
*/
bool insert(List* list, int value);

/*
* функция удаления элемента по индексу
* принимает указатель на список и значение элемента
* возвращает булевое значние, сообщающее, удачно ли прошла операция
* внутри себя освобождает память удаляемого элемента
*/
bool removeElement(List* list, int value);

/*
* функция удаления всего списка
* принимает указатель на список
* возвращает булевое значение, удачно ли прошла операция
*/
bool deleteList(List* list);

/*
* функция вывода списка в консоль
* принимает только указатель на список
* ничего не возвращает
* печатает элементы списка через пробел
* в случае переданного пустого или несуществующего списка сообщает об этом пользователю
*/
void printList(List* list);

/*
* функция проверки, пустой ли список
* возвращает true если пустой, false, если нет
* на вход принимает указатель на список
*/
bool isEmpty(List* list);
99 changes: 99 additions & 0 deletions src/ListTasks1/sortedListTask.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#include "OneLinkedList.h"
#include <stdbool.h>
#include <stdio.h>

void printMenu()
{
printf("\n=== МЕНЮ КОМАНД ===\n");
printf("1 - Добавить элемент (с сортировкой по возрастанию)\n");
printf("2 - Удалить элемент по значению\n");
printf("3 - Вывести список\n");
printf("0 - Выход из программы\n");
}

void clearInputBuffer()
{
int c;
while ((c = getchar()) != '\n') { }
Comment on lines +16 to +17

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно просто

Suggested change
int c;
while ((c = getchar()) != '\n') { }
while (getchar() != '\n') { }

}

void addElementInList(List* list)
{
int element = 0;
printf("Введите элемент который хотите добавить\n");

if (scanf("%d", &element) != 1) {
printf("Ошибка: введено некорректное значение!\n");
clearInputBuffer();
return;
}
clearInputBuffer();
insert(list, element);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

insert возвращает bool, значит надо его проверить

printf("Элемент успешно добавлен\n");
}

void removeElemetFromList(List* list)
{
int value = 0;
printf("Введите значение элемента, который хотите удалить: ");
if (scanf("%d", &value) != 1) {
printf("Ошибка: введено некорректное значение!\n");
clearInputBuffer();
return;
}
clearInputBuffer();

if (removeElement(list, value)) {
printf("Элемент успешно удален.\n");
} else {
printf("Что-то пошло не так. Возможно введено неверное значение.\n");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут скорее стоит написать, что значения нет в списке, потому что false возвращается если список - NULL (а такого почти никогда не происходит), список пустой или элемент не найден; пустой список => никакого элемента в нём не найти

}
}

void printTheList(List* list)
{
printf("Список элементов:\n");
printList(list);
}

void handleCommands()
{
printf("Вводите команды. После каждой введенной команды нажимайте Enter\n");
printf("Чтобы завершить работу с программой, введите 0\n\n");
List* list = newList();
int command = 0;
while (1) {
printf("Введите команду: ");
if (scanf("%d", &command) != 1) {
printf("Ошибка: пожалуйста, введите число от 0 до 3!\n");
clearInputBuffer();
continue; // Пропускаем остаток цикла и начинаем заново
}
clearInputBuffer();
if (command == 0) {
break;
}
switch (command) {
case 1:
addElementInList(list);
break;
case 2:
removeElemetFromList(list);
break;
case 3:
printTheList(list);
break;
default:
printf("Вероятно, такой команды не существует\n");
}
}
deleteList(list);
printf("Работа с программой завершена. Память очищена\n");
}

int main()
{
printMenu();
handleCommands();
return 0;
}