rusi/strings.c

253 lines
11 KiB
C
Raw Normal View History

// ============================================================
// Управление динамическим массивом строк
// ============================================================
#включить "руси.з"
#включить <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;
}