Пишем простой список на C
Привет, Хабр!
В статье хочу показать как написать простой список на C, а именно породию на ArrayList из Java.
Сразу скажу я не проффесионал в C, и могу допускать ошибки, если вы найдете таковые то напишите в коммментариях, я обезательно исправлю эти моменты. Также статья нацелена на новичков из за довольно простой темы.
Начнем
Создадим заголовочный файо list.h и .c файл к нему. Если вы не знаете что это такое и как с этим работать, то можете прочти об этом ниже.
Заголовочные файлы
Чтоб сделать свою программу модульной, тоесть разделить код на несколько файлов, а не писать всю программу в одном файле, есть заголовочные файлы. В них содержится информация какие функции, структуры и тд будут подключены. К каждому заголовочному файлу, нужно сделать файл-реализатор, там уже функции из заголовочного файла будут имплементированы. Если вы раньше изучали Java, то заголовочный файл — это интерфейс, с реализатор это класс который имплементирует этот интерфейс. Также при компиляции нужно указывать реализаторы (Например clang main.c list.c). Подробнее можете посмотреть в ЭТОЙ СТАТЬЕ.
В заголовочном файле, будет структура List, в которой будет массив int, но вы можете указать любой другой тип данных. Ну и ниже напишу пример.
#ifndef LIST_H
#define LIST_H
typedef struct List {
int* data;
int length;
int capacity;
} List;
List* new_list();
void list_add(List* list, int el);
int* list_get(List* list, int pos);
void list_remove(List* list, int pos);
#endif
List — эта структура списка, data — это указатель на элементы списка, length — это длинна списка, а capacity — это вместимость списка, ну и new_list возвращает указатель на созданный список.
Я думаю нам пока-что хватит этих функций и структуры. Теперь зайдем в list.c. Там подключаем этот заголовочный файл через #include «list.h», и реализуем функции!
Сразу дам код, и буду его обьяснять.
Реализация list.h
#include
#include "list.h"
#include
List* new_list() {
List* list = (List*) malloc(sizeof(List));
if(list == NULL) {
return NULL;
}
list->data = malloc(sizeof(int) * 1);
if (list->data == NULL) {
free(list);
return NULL;
}
list->capacity = 1;
list->length = 0;
return list;
}
void list_add(List* list, int el) {
if(list->length == list->capacity) {
list->capacity *= 2;
list->data = realloc(list->data, sizeof(int) * list->capacity);
}
list->data[list->length++] = el;
}
int* list_get(List* list, int pos) {
if(pos >= 0 && pos < list->length)
return &list->data[pos];
printf("%s\n", "return NULL");
return NULL;
}
void list_remove(List* list, int pos) {
if(pos >= 0 && pos < list->length){
for (int i = pos; i < list->length - 1; i++) {
list->data[i] = list->data[i + 1];
}
list->length--;
}
}
void list_free(List* list) {
free(list->data);
free(list);
}
Обьяснение функций
new_list — Тут создается список. Мы выделяем под него память, и если не на устройстве не хватило места (malloc вернет NULL) то сразу возвращаем NULL. Далее выделяем память память под data, тоесть наши элементы, и если на устройстве не хватило места, то освобождаем память выделеную для обьекта list, и возвращаем NULL. Также устанавоиваем стандартную вместимость (1), и начальную длинну (0).
list_add (List*, int) — Тут добавляем элемент в список, пердав список и добавляемый элемент. И если длинна списка будет совпадать с вместимостью, умножаем вместимость вдвое. И с помощью realloc меняем размер выделеной памяти для списка. И после всего этого, в в конец добавляем переданный элемент.
Конечно это очень не оптимизировано, и при больших списках он будет занимать очень много памяти, но я пишу статю чтоб новички (хоть и я тоже новичок) поняли как создавать простые списки, и потом сами написали более оптимизированый вариант. И вобщем моя реализация не нацелена на постоянное использование, а служит примером.
list_get(List*, int) — возврадаем элемент из списка по указанной позиции. В параметры передаем список и позицию элемента. И если позиция будет в промежутке от 0 до длинны списка, то возвращаем элемент, иначе возвращаем NULL.
list_remove(List*, int pos) — удаляем элемент по указанной позици, идет таже проверка их list_get, и просто сдвигаем элементы после удаленной позиции назад. Далее просто уменьшаем длинну списка.
list_free(List*) — освобождает память выделеную под data и сам список. Все просто.
Пример использования
Просто создадим список, добавим элементы, удалим элемент под индексом 1, и выводим все элементы на экран.
Компилируем код — clang main.c list.c, и запускаем — ./a.out. Может отличаться в зависимости от OC, я использую Linux.
#include
#include "list.h"
int main() {
List* list = new_list();
list_add(list, 12);
list_add(list, 83);
list_add(list, 212);
list_add(list, 0);
list_remove(list, 1);
for(int i=0; ilength; i++) {
printf("pos: %d = %d\n", i, *list_get(list, i));
}
list_free(list);
}
Output:
pos: 0 = 12
pos: 1 = 212
pos: 2 = 0
Конец
Статья получилась довольно короткой, до этого я думал что он будет больше… Но всеже я показал как сделать список похожий на ArrayList из Java. Если есть вопросы или поправки пишите в комментариях.
Пока, Хабр!