
Привет, Хабр!
Если вы только начинаете свой путь в C, то наверняка уже знаете о том, насколько важны библиотеки. Они облегчают жизнь и позволяют сосредоточиться на решении задач, а не на создании всего с нуля. В статье расскажем о трех полезных библиотек на C, которые станут отличными прикладными помощниками.
GNU Scientific Library (GSL)
GNU Scientific Library — это свободно распространяемая библиотека для выполнения научных вычислений.
Линейная алгебра
GSL поддерживает создание и управление векторами и матрицами, включая базовые операции, такие как сложение, умножение и транспонирование.
Библиотека предоставляет функции для разложения матриц (LU, QR, Cholesky) и решения линейных систем уравнений.
#include <gsl/gsl_matrix.h> #include <gsl/gsl_linalg.h> int main() { gsl_matrix *m = gsl_matrix_alloc(3, 3); gsl_vector *b = gsl_vector_alloc(3); gsl_vector *x = gsl_vector_alloc(3); // заполнение матрицы и вектора gsl_matrix_set(m, 0, 0, 1.0); gsl_matrix_set(m, 0, 1, 2.0); gsl_matrix_set(m, 0, 2, 3.0); gsl_vector_set(b, 0, 1.0); gsl_linalg_HH_solve(m, b, x); gsl_matrix_free(m); gsl_vector_free(b); gsl_vector_free(x); return 0; }
Численное интегрирование
Существуют разные методы интегрирования, такие как адаптивные методы, методы Гаусса-Кронрода и интеграцию на бесконечных интервалах.
#include <gsl/gsl_integration.h> double f(double x, void *params) { return x*x; } int main() { gsl_integration_workspace *w = gsl_integration_workspace_alloc(1000); double result, error; gsl_function F; F.function = &f; gsl_integration_qags(&F, 0, 1, 0, 1e-7, 1000, w, &result, &error); gsl_integration_workspace_free(w); return 0; }
Функции хороши для вычисления определенных интегралов и обработки функций с особенностями и сингулярностями.
Генерация случайных чисел
Есть обширный набор генераторов случайных чисел и распределений, включая нормальное, экспоненциальное и другие распределения.
#include <gsl/gsl_rng.h> #include <gsl/gsl_randist.h> int main() { gsl_rng *r = gsl_rng_alloc(gsl_rng_default); double x = gsl_ran_gaussian(r, 1.0); gsl_rng_free(r); return 0; }
Специальные функции
Есть в библиотеке множество специальных функций, таких как функции Бесселя, гамма-функции, полиномы Лежандра и многие другие, которые часто встречаются в научных вычислениях.
#include <gsl/gsl_sf_bessel.h> int main() { double x = 5.0; double y = gsl_sf_bessel_J0(x); printf("J0(%g) = %.18e\n", x, y); return 0; }
Статистика и анализ данных
Еще есть инструменты для статистического анализа данных, включая методы оценки, тесты гипотез, и функции для работы с временными рядами.
#include <gsl/gsl_statistics.h> int main() { double data[] = {17.0, 15.0, 23.0, 7.0, 9.0, 13.0}; double mean = gsl_stats_mean(data, 1, 6); double variance = gsl_stats_variance(data, 1, 6); printf("Mean: %g, Variance: %g\n", mean, variance); return 0; }
Пример применения
Провелем численное интегрирование функции, решим систему линейных уравнений и проведемстатистический анализ набора данных. Бдем использовать GSL для решения всех этих задач в одном проекте:
#include <stdio.h> #include <gsl/gsl_integration.h> #include <gsl/gsl_matrix.h> #include <gsl/gsl_linalg.h> #include <gsl/gsl_statistics.h> double my_function(double x, void *params) { return x*x; } int main() { // численное интегрирование gsl_integration_workspace *workspace = gsl_integration_workspace_alloc(1000); gsl_function F; F.function = &my_function; double result, error; gsl_integration_qags(&F, 0, 1, 0, 1e-7, 1000, workspace, &result, &error); printf("Integral result: %g, error: %g\n", result, error); gsl_integration_workspace_free(workspace); // решение системы линейных уравнений gsl_matrix *m = gsl_matrix_alloc(2, 2); gsl_vector *b = gsl_vector_alloc(2); gsl_vector *x = gsl_vector_alloc(2); gsl_matrix_set(m, 0, 0, 2.0); gsl_matrix_set(m, 0, 1, 1.0); gsl_matrix_set(m, 1, 0, 1.0); gsl_matrix_set(m, 1, 1, 3.0); gsl_vector_set(b, 0, 1.0); gsl_vector_set(b, 1, 2.0); gsl_linalg_HH_solve(m, b, x); printf("Solution: x0 = %g, x1 = %g\n", gsl_vector_get(x, 0), gsl_vector_get(x, 1)); gsl_matrix_free(m); gsl_vector_free(b); gsl_vector_free(x); // статистический анализ double data[] = {17.0, 15.0, 23.0, 7.0, 9.0, 13.0}; double mean = gsl_stats_mean(data, 1, 6); double variance = gsl_stats_variance(data, 1, 6); printf("Mean: %g, Variance: %g\n", mean, variance); return 0; }
Как можно увидеть, GSL — очень мощный инструмент. Подробнее с библиотекой можно ознакомиться здесь.
SQLite
SQLite — это легковесная, встроенная, самодостаточная и безсерверная библиотека, реализующая SQL-диск-движо
Архитектура SQLite
-
Токенизатор: Преобразует SQL-запросы в токены для их дальнейшей обработки. Эта стадия важна для правильной интерпретации SQL-команд.
-
Парсер: Использует Lemon парсер для создания синтаксического дерева запросов.
-
Генератор кода: Создает байт-код для выполнения SQL-запросов. Этот байт-код затем интерпретируется VM SQLite.
-
Виртуальная машина: Выполняет байт-код, обеспечивая выполнение SQL-команд. Виртуальная машина реализована в файле
vdbe.cи управляется через API, такие какsqlite3_step().
Основные возможности
-
Создание и управление БД: SQLite позволяет создавать базы данных, таблицы и индексы с помощью стандартных SQL-команд.
-
SQL-запросы: Поддержка полного набора SQL-команд, включая SELECT, INSERT, UPDATE, DELETE и JOIN.
-
Встроенные функции: SQLite предоставляет множество встроенных функций, таких как
abs(),length(),datetime(),coalesce()и многие другие. -
Триггеры и представления: Поддержка триггеров и представлений для выполнения автоматических операций и упрощения сложных запросов.
-
Транзакции: Поддержка атомарных транзакций с возможностью отката
ROLLBACKи фиксацииCOMMIT. -
Пользовательские функции: Возможность создания пользовательских функций на C, которые могут быть вызваны из SQL-запросов.
Пример использования
#include <stdio.h> #include <sqlite3.h> int main() { sqlite3 *db; char *err_msg = 0; // открытие/создание БД int rc = sqlite3_open("test.db", &db); if (rc != SQLITE_OK) { fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(db)); return rc; } // создание таблицы char *sql = "CREATE TABLE IF NOT EXISTS Friends(Id INT, Name TEXT);" "INSERT INTO Friends VALUES(1, 'Tom');" "INSERT INTO Friends VALUES(2, 'Rebecca');" "INSERT INTO Friends VALUES(3, 'Jim');"; rc = sqlite3_exec(db, sql, 0, 0, &err_msg); if (rc != SQLITE_OK) { fprintf(stderr, "SQL error: %s\n", err_msg); sqlite3_free(err_msg); sqlite3_close(db); return rc; } // чтение данных sql = "SELECT * FROM Friends"; sqlite3_stmt *stmt; rc = sqlite3_prepare_v2(db, sql, -1, &stmt, 0); if (rc != SQLITE_OK) { fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(db)); sqlite3_close(db); return rc; } while (sqlite3_step(stmt) == SQLITE_ROW) { printf("%s: %s\n", sqlite3_column_text(stmt, 0), sqlite3_column_text(stmt, 1)); } // завершение работы с базой данных sqlite3_finalize(stmt); sqlite3_close(db); return 0; }
Подробнее про библиотеку можно посмотреть здесь.
SDL
Simple DirectMedia Layer — мощная кроссплатформенная библиотека для разработки мультимедийных приложений и игр. SDL предоставляет низкоуровневый доступ к аудио, клавиатуре, мыши, джойстику и графическому оборудованию.
Основные функции SDL
Все приложения на SDL начинаются с инициализации, которая выполняется с помощью функции SDL_Init. Эта функция принимает флаги, определяющие подсистемы, которые необходимо инициализировать, такие как видео, аудио, джойстики и т.д.
Для корректного завершения работы и освобождения ресурсов используется функция SDL_Quit:
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) { printf("SDL_Init Error: %s\n", SDL_GetError()); return 1; } // завершение работы SDL_Quit();
SDL позволяет создавать окна с помощью функции SDL_CreateWindow, которая принимает параметры для установки заголовка окна, его позиции и размеров. Для рендеринга используется функция SDL_CreateRenderer, которая создает контекст рендера для заданного окна:
SDL_Window *win = SDL_CreateWindow("Hello SDL", 100, 100, 640, 480, SDL_WINDOW_SHOWN); if (win == NULL) { printf("SDL_CreateWindow Error: %s\n", SDL_GetError()); SDL_Quit(); return 1; } SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if (ren == NULL) { SDL_DestroyWindow(win); printf("SDL_CreateRenderer Error: %s\n", SDL_GetError()); SDL_Quit(); return 1; }
Функция SDL_PollEvent используется для извлечения событий из очереди:
SDL_Event e; while (SDL_PollEvent(&e)) { if (e.type == SDL_QUIT) { break; } }
Для работы с изображениями SDL предоставляет функции загрузки текстур и их рендеринга на экран. Функция SDL_CreateTextureFromSurface создает текстуру из загруженного изображения, а SDL_RenderCopy используется для её отображения:
SDL_Surface *bmp = SDL_LoadBMP("image.bmp"); if (bmp == NULL) { printf("SDL_LoadBMP Error: %s\n", SDL_GetError()); SDL_DestroyRenderer(ren); SDL_DestroyWindow(win); SDL_Quit(); return 1; } SDL_Texture *tex = SDL_CreateTextureFromSurface(ren, bmp); SDL_FreeSurface(bmp); if (tex == NULL) { printf("SDL_CreateTextureFromSurface Error: %s\n", SDL_GetError()); SDL_DestroyRenderer(ren); SDL_DestroyWindow(win); SDL_Quit(); return 1; } SDL_RenderClear(ren); SDL_RenderCopy(ren, tex, NULL, NULL); SDL_RenderPresent(ren);
Пример использования
Рассмотрим простой пример создания окна, рендеринга изображения и обработки событий:
#include <SDL.h> #include <stdio.h> int main(int argc, char **argv) { if (SDL_Init(SDL_INIT_VIDEO) != 0) { printf("SDL_Init Error: %s\n", SDL_GetError()); return 1; } SDL_Window *win = SDL_CreateWindow("Hello SDL", 100, 100, 640, 480, SDL_WINDOW_SHOWN); if (win == NULL) { printf("SDL_CreateWindow Error: %s\n", SDL_GetError()); SDL_Quit(); return 1; } SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); if (ren == NULL) { SDL_DestroyWindow(win); printf("SDL_CreateRenderer Error: %s\n", SDL_GetError()); SDL_Quit(); return 1; } SDL_Surface *bmp = SDL_LoadBMP("image.bmp"); if (bmp == NULL) { printf("SDL_LoadBMP Error: %s\n", SDL_GetError()); SDL_DestroyRenderer(ren); SDL_DestroyWindow(win); SDL_Quit(); return 1; } SDL_Texture *tex = SDL_CreateTextureFromSurface(ren, bmp); SDL_FreeSurface(bmp); if (tex == NULL) { printf("SDL_CreateTextureFromSurface Error: %s\n", SDL_GetError()); SDL_DestroyRenderer(ren); SDL_DestroyWindow(win); SDL_Quit(); return 1; } SDL_RenderClear(ren); SDL_RenderCopy(ren, tex, NULL, NULL); SDL_RenderPresent(ren); SDL_Event e; while (1) { if (SDL_PollEvent(&e) && e.type == SDL_QUIT) { break; } } SDL_DestroyTexture(tex); SDL_DestroyRenderer(ren); SDL_DestroyWindow(win); SDL_Quit(); return 0; }
Код создает окно, загружает изображение, отображает его и обрабатывает событие закрытия окна.
В завершение хочу порекомендовать вам бесплатный вебинар про основы работы с памятью в языке C. Зарегистрироваться можно по этой ссылке.
ссылка на оригинал статьи https://habr.com/ru/articles/827918/
Добавить комментарий