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;
|
||
} |