3 Useful Libraries for Beginners. Part 1

Linear algebra

GSL supports the creation and manipulation of vectors and matrices, including basic operations such as addition, multiplication, and transpose.

The library provides functions for matrix decomposition (LU, QR, Cholesky) and solving linear systems of equations.

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

Numerical integration

There are different integration methods such as adaptive methods, Gauss-Kronrod methods and integration over infinite intervals.

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

Functions are good for calculating definite integrals and handling functions with singularities.

Random Number Generation

There is a wide range of random number generators and distributions, including normal, exponential, and other distributions.

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

Special functions

The library contains many special functions such as Bessel functions, gamma functions, Legendre polynomials and many others that are often encountered in scientific computing.

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

Statistics and data analysis

There are also tools for statistical data analysis, including estimation methods, hypothesis tests, and functions for working with time series.

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

Example of application

We will perform numerical integration of the function, solve a system of linear equations, and perform statistical analysis of the data set. We will use GSL to solve all these problems in one project:

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

As you can see, GSL is a very powerful tool. You can learn more about the library here read here.

SQLite

SQLite is a lightweight, embedded, self-contained, and serverless library that implements the SQL disk engine.

SQLite Architecture

  • Tokenizer: Transforms SQL queries into tokens for further processing. This stage is important for the correct interpretation of SQL commands.

  • Parser: Uses the Lemon parser to create a syntax tree for queries.

  • Code Generator: Generates bytecode for executing SQL queries. This bytecode is then interpreted by the SQLite VM.

  • Virtual machine: Executes bytecode, providing execution of SQL commands. The virtual machine is implemented in a file vdbe.c and is controlled via APIs such as sqlite3_step().

Main features

  • Database creation and management: SQLite allows you to create databases, tables, and indexes using standard SQL commands.

  • SQL queries: Supports a full set of SQL commands, including SELECT, INSERT, UPDATE, DELETE and JOIN.

  • Built-in functions: SQLite provides many built-in functions such as abs(), length(), datetime(), coalesce() and many others.

  • Triggers and Views: Support for triggers and views to perform automated operations and simplify complex queries.

  • Transactions: Support for atomic transactions with rollback capability ROLLBACK and fixations COMMIT.

  • User defined functions: Ability to create user-defined functions in C that can be called from SQL queries.

Example of use

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

You can find more information about the library see here.

SDL

Simple DirectMedia Layer is a powerful cross-platform library for developing multimedia applications and games. SDL provides low-level access to audio, keyboard, mouse, joystick, and graphics hardware.

SDL Main Functions

All SDL applications start with initialization, which is performed using the function SDL_Init. This function takes flags that specify the subsystems to initialize, such as video, audio, joysticks, etc.

To properly terminate work and free up resources, use the function 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 allows you to create windows using the function SDL_CreateWindowwhich takes parameters to set the window title, position, and size. The function used for rendering is SDL_CreateRendererwhich creates a rendering context for a given window:

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

Function SDL_PollEvent used to retrieve events from the queue:

SDL_Event e;
while (SDL_PollEvent(&e)) {
    if (e.type == SDL_QUIT) {
        break;
    }
}

For working with images, SDL provides functions for loading textures and rendering them to the screen. Function SDL_CreateTextureFromSurface creates a texture from the loaded image, and SDL_RenderCopy is used to display it:

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

Example of use

Let's look at a simple example of creating a window, rendering an image, and handling events:

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

The code creates a window, loads an image, displays it, and handles the window close event.

More about the library – https://www.libsdl.org/.


In conclusion, I would like to recommend you a free webinar about the basics of working with memory in the C language. You can register at this link.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *