253 lines
11 KiB
C
253 lines
11 KiB
C
|
|
// ============================================================
|
|||
|
|
// Управление динамическим массивом строк
|
|||
|
|
// ============================================================
|
|||
|
|
|
|||
|
|
#включить "руси.з"
|
|||
|
|
#включить <stdio.h> // стандартная библиотека
|
|||
|
|
#включить <stdlib.h> // стандартная библиотека
|
|||
|
|
#включить <stdarg.h> // стандартная библиотека
|
|||
|
|
#включить <string.h> // стандартная библиотека
|
|||
|
|
|
|||
|
|
// ============================================================
|
|||
|
|
// Управление динамическим массивом строк
|
|||
|
|
// ============================================================
|
|||
|
|
|
|||
|
|
пусто массив_строк_добавить(МассивСтрок *массив, символ *строка) {
|
|||
|
|
если (!массив) возврат;
|
|||
|
|
|
|||
|
|
// Инициализация массива при первом использовании
|
|||
|
|
если (!массив->data) {
|
|||
|
|
массив->data = (символ **)calloc(8, размер(символ *));
|
|||
|
|
если (!массив->data) {
|
|||
|
|
// Ошибка выделения памяти - выходим
|
|||
|
|
возврат;
|
|||
|
|
}
|
|||
|
|
массив->capacity = 8;
|
|||
|
|
массив->len = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Расширение массива при необходимости
|
|||
|
|
если (массив->capacity == массив->len) {
|
|||
|
|
size_t новая_ёмкость = массив->capacity * 2;
|
|||
|
|
символ **новые_данные = (символ **)realloc(массив->data, размер(символ *) * новая_ёмкость);
|
|||
|
|
если (!новые_данные) {
|
|||
|
|
// Ошибка перевыделения памяти
|
|||
|
|
возврат;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
массив->data = новые_данные;
|
|||
|
|
массив->capacity = новая_ёмкость;
|
|||
|
|
|
|||
|
|
// Инициализация новых элементов нулями
|
|||
|
|
для (size_t ш = массив->len; ш < массив->capacity; ш++) {
|
|||
|
|
массив->data[ш] = NULL;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Добавление строки
|
|||
|
|
массив->data[массив->len++] = строка;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ============================================================
|
|||
|
|
// Форматирование строки в стиле printf
|
|||
|
|
// ============================================================
|
|||
|
|
|
|||
|
|
символ *формат(символ *строка_формата, ...) {
|
|||
|
|
если (!строка_формата) возврат NULL;
|
|||
|
|
|
|||
|
|
символ *буфер = NULL;
|
|||
|
|
size_t разм_буфера = 0;
|
|||
|
|
|
|||
|
|
// Открываем поток в память
|
|||
|
|
FILE *поток = open_memstream(&буфер, &разм_буфера);
|
|||
|
|
если (!поток) {
|
|||
|
|
возврат NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Форматируем вывод
|
|||
|
|
va_list арг;
|
|||
|
|
va_start(арг, строка_формата);
|
|||
|
|
цел рез = vfprintf(поток, строка_формата, арг);
|
|||
|
|
va_end(арг);
|
|||
|
|
|
|||
|
|
// Закрываем поток (это освобождает внутренние ресурсы)
|
|||
|
|
fclose(поток);
|
|||
|
|
|
|||
|
|
// Проверяем успешность записи
|
|||
|
|
если (рез < 0) {
|
|||
|
|
free(буфер);
|
|||
|
|
возврат NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
возврат буфер;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ============================================================
|
|||
|
|
// Дополнительные полезные функции для работы со строками
|
|||
|
|
// ============================================================
|
|||
|
|
|
|||
|
|
// Создает копию строки с выделением памяти
|
|||
|
|
символ *строка_дублировать(конст символ *исходная) {
|
|||
|
|
если (!исходная) возврат NULL;
|
|||
|
|
|
|||
|
|
size_t длина = strlen(исходная) + 1;
|
|||
|
|
символ *копия = (символ *)malloc(длина);
|
|||
|
|
если (!копия) возврат NULL;
|
|||
|
|
|
|||
|
|
memcpy(копия, исходная, длина);
|
|||
|
|
возврат копия;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Объединяет две строки в новую
|
|||
|
|
символ *строка_склеить(конст символ *первая, конст символ *вторая) {
|
|||
|
|
если (!первая) возврат строка_дублировать(вторая);
|
|||
|
|
если (!вторая) возврат строка_дублировать(первая);
|
|||
|
|
|
|||
|
|
size_t дл1 = strlen(первая);
|
|||
|
|
size_t дл2 = strlen(вторая);
|
|||
|
|
символ *рез = (символ *)malloc(дл1 + дл2 + 1);
|
|||
|
|
если (!рез) возврат NULL;
|
|||
|
|
|
|||
|
|
memcpy(рез, первая, дл1);
|
|||
|
|
memcpy(рез + дл1, вторая, дл2 + 1);
|
|||
|
|
возврат рез;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Объединяет три строки в новую
|
|||
|
|
символ *строка_склеить3(конст символ *первая, конст символ *вторая, конст символ *третья) {
|
|||
|
|
если (!первая && !вторая && !третья) возврат NULL;
|
|||
|
|
если (!первая) возврат строка_склеить(вторая, третья);
|
|||
|
|
если (!вторая) возврат строка_склеить(первая, третья);
|
|||
|
|
если (!третья) возврат строка_склеить(первая, вторая);
|
|||
|
|
|
|||
|
|
size_t дл1 = strlen(первая);
|
|||
|
|
size_t дл2 = strlen(вторая);
|
|||
|
|
size_t дл3 = strlen(третья);
|
|||
|
|
символ *рез = (символ *)malloc(дл1 + дл2 + дл3 + 1);
|
|||
|
|
если (!рез) возврат NULL;
|
|||
|
|
|
|||
|
|
memcpy(рез, первая, дл1);
|
|||
|
|
memcpy(рез + дл1, вторая, дл2);
|
|||
|
|
memcpy(рез + дл1 + дл2, третья, дл3 + 1);
|
|||
|
|
возврат рез;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Освобождает массив строк
|
|||
|
|
пусто массив_строк_освободить(МассивСтрок *массив) {
|
|||
|
|
если (!массив) возврат;
|
|||
|
|
|
|||
|
|
если (массив->data) {
|
|||
|
|
// Освобождаем каждую строку
|
|||
|
|
для (size_t ш = 0; ш < массив->len; ш++) {
|
|||
|
|
если (массив->data[ш]) {
|
|||
|
|
free(массив->data[ш]);
|
|||
|
|
массив->data[ш] = NULL;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
// Освобождаем массив указателей
|
|||
|
|
free(массив->data);
|
|||
|
|
массив->data = NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
массив->len = 0;
|
|||
|
|
массив->capacity = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Очищает массив строк без освобождения памяти под него
|
|||
|
|
пусто массив_строк_очистить(МассивСтрок *массив) {
|
|||
|
|
если (!массив || !массив->data) возврат;
|
|||
|
|
|
|||
|
|
// Освобождаем только строки, но не массив указателей
|
|||
|
|
для (size_t ш = 0; ш < массив->len; ш++) {
|
|||
|
|
если (массив->data[ш]) {
|
|||
|
|
free(массив->data[ш]);
|
|||
|
|
массив->data[ш] = NULL;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
массив->len = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Получает строку по индексу с проверкой границ
|
|||
|
|
символ *массив_строк_получить(конст МассивСтрок *массив, size_t инд) {
|
|||
|
|
если (!массив || !массив->data || инд >= массив->len) {
|
|||
|
|
возврат NULL;
|
|||
|
|
}
|
|||
|
|
возврат массив->data[инд];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Устанавливает строку по индексу с проверкой границ
|
|||
|
|
бул массив_строк_установить(МассивСтрок *массив, size_t инд, символ *строка) {
|
|||
|
|
если (!массив || !массив->data || инд >= массив->len) {
|
|||
|
|
возврат ложь;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Освобождаем старую строку
|
|||
|
|
если (массив->data[инд]) {
|
|||
|
|
free(массив->data[инд]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
массив->data[инд] = строка;
|
|||
|
|
возврат истина;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Вставляет строку в указанную позицию
|
|||
|
|
бул массив_строк_вставить(МассивСтрок *массив, size_t поз, символ *строка) {
|
|||
|
|
если (!массив || !строка) возврат ложь;
|
|||
|
|
если (поз > массив->len) возврат ложь;
|
|||
|
|
|
|||
|
|
// Добавляем в конец
|
|||
|
|
если (поз == массив->len) {
|
|||
|
|
массив_строк_добавить(массив, строка);
|
|||
|
|
возврат истина;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Вставляем в середину - сначала добавляем элемент в конец
|
|||
|
|
массив_строк_добавить(массив, NULL);
|
|||
|
|
если (!массив->data) возврат ложь;
|
|||
|
|
|
|||
|
|
// Сдвигаем элементы вправо
|
|||
|
|
для (size_t ш = массив->len - 1; ш > поз; ш--) {
|
|||
|
|
массив->data[ш] = массив->data[ш - 1];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
массив->data[поз] = строка;
|
|||
|
|
возврат истина;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Удаляет строку по индексу
|
|||
|
|
бул массив_строк_удалить(МассивСтрок *массив, size_t инд) {
|
|||
|
|
если (!массив || !массив->data || инд >= массив->len) {
|
|||
|
|
возврат ложь;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Освобождаем удаляемую строку
|
|||
|
|
если (массив->data[инд]) {
|
|||
|
|
free(массив->data[инд]);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Сдвигаем элементы влево
|
|||
|
|
для (size_t ш = инд; ш < массив->len - 1; ш++) {
|
|||
|
|
массив->data[ш] = массив->data[ш + 1];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
массив->len--;
|
|||
|
|
массив->data[массив->len] = NULL;
|
|||
|
|
возврат истина;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Ищет строку в массиве
|
|||
|
|
ssize_t массив_строк_найти(конст МассивСтрок *массив, конст символ *строка) {
|
|||
|
|
если (!массив || !массив->data || !строка) возврат -1;
|
|||
|
|
|
|||
|
|
для (size_t ш = 0; ш < массив->len; ш++) {
|
|||
|
|
если (массив->data[ш] && strcmp(массив->data[ш], строка) == 0) {
|
|||
|
|
возврат (ssize_t)ш;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
возврат -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Проверяет, содержит ли массив строку
|
|||
|
|
бул массив_строк_содержит(конст МассивСтрок *массив, конст символ *строка) {
|
|||
|
|
возврат массив_строк_найти(массив, строка) >= 0;
|
|||
|
|
}
|