Стартер пак в C: 3 полезные библиотеки для начинающих. Часть 1
Привет, Хабр!
Если вы только начинаете свой путь в 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. Зарегистрироваться можно по этой ссылке.