Friday, December 29, 2023

How to reverse singly linked list in C (trivial way)

There is a beautiful morning. It's snowing. And I decided to write one more article. Today it will be just simple article where I would like to present my version how singly linked list can be reversed in C.

At first we need to define our list:

1
2
3
4
typedef struct list_s {
	int data;
	struct list_s* next;
} list_t, *list_p, **list_pp;

In this code the variable data is some data. In our case its type is INTEGER (int). The variable next is a pointer to next element.

So, now we need to write a function that will print our list:

1
2
3
4
5
6
7
void print_list(list_p l) {
	while(l) {
		UNUSED(printf("%d ", l->data));
		l = l->next;
	}
	UNUSED(puts(""));
}

Because some functions return result which we don't want to use and if we don't want to see any warnings in some compilers I think we need to suppress potential warnings. Because of that I created macro called UNUSED. It's just explicit cast to void type.

1
#define UNUSED(x) (void) x

Now we need to write functions which will reverse our list. I will write two functions.
The first function gets pointer to list, reverses this list and after that returns new pointer, but argument of this function is still without changes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
list_p reverse_list(list_p l) {
	list_p new_head = NULL;
	
	while(l) {
		list_p next = l->next;
		l->next = new_head;
		new_head = l;
		l = next;
	};

	return new_head;
}

The second function gets pointer to pointer to list, reverses this list and after that returns new pointer but as argument (not through return). In other words this function will change input argument.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
void reverse_list_self(list_pp l) {
	list_p new_head = NULL;
	list_p lst = *l;

	while(lst) {
		list_p next_lst = lst->next;
		lst->next = new_head;
		new_head = lst;
		lst = next_lst;
	}

	*l = new_head;
}

Currently we have function for printing, two functions for reversing and struct which describes our list. And now we have to write main function. This function also has to create our list. I would like to tell that it's just example so I will not read return code of some functions and I will not handle any memory errors and read errno.
By the way I could be not use UNUSED macro because I use gcc compiler and it does not argue if I don't read return code of printf or pust functions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int main() {
	list_p list = NULL;

	/* Fill */
	for(unsigned int i = 10; i > 0; --i) {
		list_p el = malloc(sizeof(*list));
		el->data = i;
		el->next = list;
		list = el;
	}

	print_list(list);

	list = reverse_list(list);

	print_list(list);

	reverse_list_self(&list);
	
	print_list(list);
	
	return EXIT_SUCCESS;
}

So currently we are able to assemble all code parts in one program.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <stdlib.h>
#include <stdio.h>

#define UNUSED(x) (void) x

typedef struct list_s {
	int data;
	struct list_s* next;
} list_t, *list_p, **list_pp;

static void print_list(list_p l);
static list_p reverse_list(list_p l);
static void reverse_list_self(list_pp l);

int main() {
	list_p list = NULL;

	/* Fill */
	for(unsigned int i = 10; i > 0; --i) {
		list_p el = malloc(sizeof(*list));
		el->data = i;
		el->next = list;
		list = el;
	}

	print_list(list);

	list = reverse_list(list);

	print_list(list);

	reverse_list_self(&list);
	
	print_list(list);
	
	return EXIT_SUCCESS;
}

void print_list(list_p l) {
	while(l) {
		UNUSED(printf("%d ", l->data));
		l = l->next;
	}
	UNUSED(puts(""));
}

list_p reverse_list(list_p l) {
	list_p new_head = NULL;
	
	while(l) {
		list_p next = l->next;
		l->next = new_head;
		new_head = l;
		l = next;
	};

	return new_head;
}

void reverse_list_self(list_pp l) {
	list_p new_head = NULL;
	list_p lst = *l;

	while(lst) {
		list_p next_lst = lst->next;
		lst->next = new_head;
		new_head = lst;
		lst = next_lst;
	}

	*l = new_head;
}

/*
 * The end of the file
 */

Let's compile our code:
$ ls -lah
total 4.0K
drwxr-xr-x 2 bodro bodro   20 Dec 29 13:47 .
drwxr-xr-x 5 bodro bodro   92 Oct  1  2021 ..
-rw-r--r-- 1 bodro bodro 1.1K Oct  1  2021 main.c
$ gcc -Wall -Wextra -Wpedantic -o main main.c 
$ ls -lah
total 20K
drwxr-xr-x 2 bodro bodro   32 Dec 29 13:48 .
drwxr-xr-x 5 bodro bodro   92 Oct  1  2021 ..
-rwxr-xr-x 1 bodro bodro  16K Dec 29 13:48 main
-rw-r--r-- 1 bodro bodro 1.1K Oct  1  2021 main.c
$ file main
main: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV),
dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,
BuildID[sha1]=087a2c8d0fd1b8fee07a6b84806ae9698ae84424, for GNU/Linux 3.2.0, not stripped
$ strip --strip-all main
$ file main
main: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV),
dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,
BuildID[sha1]=087a2c8d0fd1b8fee07a6b84806ae9698ae84424, for GNU/Linux 3.2.0, stripped
$ ls -lah
total 20K
drwxr-xr-x 2 bodro bodro   32 Dec 29 13:49 .
drwxr-xr-x 5 bodro bodro   92 Oct  1  2021 ..
-rwxr-xr-x 1 bodro bodro  15K Dec 29 13:49 main
-rw-r--r-- 1 bodro bodro 1.1K Oct  1  2021 main.c
$
As we can see it was compiled correctly.

Shall we check?
$ ./main 
1 2 3 4 5 6 7 8 9 10 
10 9 8 7 6 5 4 3 2 1 
1 2 3 4 5 6 7 8 9 10
$
OK. I hope you understand that our code works. :)

So today we wrote simple code that reverses singly linked list in C without temporary lists or arrays. It's just simple task however you can meet it when you try to pass any interview.

Have a nice day my friends! And Happy coming New Year! :)
Best regards,
Vasiliy V. Bodrov aka Bodro,
the 29-th of December, 2023.

Thursday, December 28, 2023

Narrowing type conversions in C/C++

 Hi, my friends and just everyone! :)

You shouldn't think that I forgot about my blog. After more then 6 years I decided to continue writing articles. And I'm glad to present my new article about strange behavior of C++ compilers. However, the reason maybe more interesting. E.g. in C++ standards.

So today I would like to talk about implicit type conversions and particular about implicit narrowing conversion of types.

Me and my friends were sure that if we can lose data the compiler has to show error or at least show warning.
Actually, look at this:

1
2
3
4
5
6
7
8
#include <cstdint>

void f(uint16_t) {}

int main() {
    uint32_t x = 0xFFFFFFFF;
    f(x);
}

I think you are sure that gcc or clang compilers have to show warning or error? :) But no!
$ rm -f a.out; g++ main1.cpp && ./a.out
$ rm -f a.out; clang++ main1.cpp && ./a.out
$
As we can see there are no any warnings or errors. Hmmm. Ok! Maybe we can use special warnings level? No problem!
$ rm -f a.out; g++ -Wall -Wextra -Wpedantic main1.cpp && ./a.out
$ rm -f a.out; clang++ -Wall -Wextra -Wpedantic main1.cpp && ./a.out
$
So, we don't see any warnings or errors. And any warnings flags couldn't help. In that case we can write the program which can demonstrate big problems with that behavior.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <cstdint>

void Bob(uint16_t x) {
    std::cout << "I'm Bob. My salary is $"
              << x
              << std::endl;
}

struct Snob {
    Snob(uint16_t x) {
        std::cout << "I'm Snob and my salary is $"
                  << x
                  << std::endl;
    }
};

int main() {
    uint32_t x = 0xFFFF0001; // 4294901761

    std::cout << "I'm the boss and I would like to give money to Bob and Snob. "
              << "Guys! Take your salary! "
              << "It is $"
              << x
              << std::endl;
    
    Bob(x);

    Snob snob(x);
}

The result (gcc):
$ rm -f a.out; g++ -std=c++17 -Wall -Wextra -Wpedantic main2.cpp && ./a.out
I'm the boss and I would like to give money to Bob and Snob. Guys! Take your salary!
It is $4294901761
I'm Bob. My salary is $1
I'm Snob and my salary is $1
$
The result (clang):
$ rm -f a.out; clang++ -std=c++17 -Wall -Wextra -Wpedantic main2.cpp && ./a.out
I'm the boss and I would like to give money to Bob and Snob. Guys! Take your salary!
It is $4294901761
I'm Bob. My salary is $1
I'm Snob and my salary is $1
$

OK? Do you understand what problems can be? Currently, I have no idea about reasons. I have not found the explanation of this behavior yet. So if you know I would be happy if you could explain to me.

Have a nice time! :)
Best regards,
Vasiliy V. Bodrov aka Bodro,
the 28-th of December, 2023.

Tuesday, May 16, 2017

It's a notes about Erlang. It's a generator that uses a lazy calculating.

Hello my young Erlang programmers!























































It's a result (I apologize for the strange syntax highlighting):

bodro@vbodrov-pc:~/workspace/develop/test/test58$ erl
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:8:8] [async-threads:10] [kernel-poll:false]

Eshell V7.3  (abort with ^G)
1> c(test).
{ok,test}
2> test:test_all().
TEST #1
0:10   -> [0,1,2,3,4,5,6,7,8,9]
1000:5 -> [1000,1001,1002,1003,1004]
1:2    -> [1,2]
1:1    -> [1]
1:0    -> []
TEST #2
0:10   -> [0,1,2,3,4,5,6,7,8,9]
1000:5 -> [1000,1001,1002,1003,1004]
1:2    -> [1,2]
1:1    -> [1]
1:0    -> []
TEST #3
0:10   -> [0,1,2,3,4,5,6,7,8,9]
1000:5 -> [1000,1001,1002,1003,1004]
1:2    -> [1,2]
1:1    -> [1]
1:0    -> []
TEST #4
0:10   -> true
1000:5 -> true
1:2    -> true
1:1    -> true
1:0    -> true
TEST #5
0:10   -> true
1000:5 -> true
1:2    -> true
1:1    -> true
1:0    -> true
TEST #6
0:10   -> true
1000:5 -> true
1:2    -> true
1:1    -> true
1:0    -> true
TEST #7
0:10   -> true
1000:5 -> true
1:2    -> true
1:1    -> true
1:0    -> true
ok
3> q().
ok
4> bodro@vbodrov-pc:~/workspace/develop/test/test58$

Best regards,
Vasiliy V. Bodrov aka Bodro,
May 16, 2017.

GNU Compiler Collection: extensions, nested functions, object-oriented programming, functional paradigm etc. It's the C language only!

Hello my dear frineds!

I want to tell you about possibilities of the C language. I will do it with the example of a linear list.

You can see the links:
All GCC Extensions
Nested Functions

So. It's a structure of the linked list:
    struct storage_data_s {
        value_t                value;
        char*                  name;
        char*                  comment;
        struct storage_data_s* next;
    }* data;

It's a structure of the storage with the linked list:
/* It's a storage */
typedef struct storage_s {
    struct storage_data_s {
        value_t                value;
        char*                  name;
        char*                  comment;
        struct storage_data_s* next;
    }* data;

    void (*init)(struct storage_s* _this);
    
    void (*add)(struct storage_s* _this,
                value_t _value,
                char* _name,
                char* _comment);
    
    void (*for_each)(struct storage_s const* _this,
                     output_f output);
    
    void (*clear)(struct storage_s* _this);
    
    void (*deinit)(struct storage_s* _this);
}      storage_t,
      *storage_p,
     **storage_pp,
*const storage_cp;

typedef storage_t const* storage_pc;
typedef storage_t const* const storage_cpc;

The first argument of all functions is a pointer to "this" (self, this etc).

This is the complete text of the code (I apologize for the strange syntax highlighting):

storage.h:
/* ****************************************************************************
 * Programmer: Vasiliy V. Bodrov aka Bodro
 * May 15, 2016.
 * ****************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Vasiliy V. Bodrov aka Bodro
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 **************************************************************************** */

#pragma once

#include <stdbool.h>

/* It's a type of value */
typedef void* value_t;
typedef void** value_p;
typedef void const* value_tc;

/* The user must to determine these functions */
#ifndef __STORAGE_C_FILE__
typedef struct __value_user_helpers_handlers_s {
    value_t (*new)(user_value_t _uv);
    user_value_t (*get)(value_tc _v);
    user_value_t (*get2)(value_tc _v, user_value_t _container);
}  __value_user_helpers_handlers_t,
  *__value_user_helpers_handlers_p;
#else /* __STORAGE_C_FILE__ */
typedef void*  __value_user_helpers_handlers_p;
#endif /* __STORAGE_C_FILE__ */

typedef struct value_handlers_s {
    void (*delete)(value_p _v);
    value_t (*copy)(value_tc _v);
    value_t (*move)(value_p _v);
    bool (*p_move)(void); /* predicate */
    
    __value_user_helpers_handlers_p x;
} value_handlers_t;

#ifdef __STORAGE_C_FILE__
value_handlers_t __value_helpers_handlers;
#else /* __STORAGE_C_FILE__ */
extern value_handlers_t __value_helpers_handlers;
#endif /* __STORAGE_C_FILE__ */

/* This type is pointer to output function */
typedef void (*output_f)(value_t _value,
                         char const* _name,
                         char const* _comment);

/* It's a storage */
typedef struct storage_s {
    struct storage_data_s {
        value_t                value;
        char*                  name;
        char*                  comment;
        struct storage_data_s* next;
    }* data;

    void (*init)(struct storage_s* _this);
    
    void (*add)(struct storage_s* _this,
                value_t _value,
                char* _name,
                char* _comment);
    
    void (*for_each)(struct storage_s const* _this,
                     output_f output);
    
    void (*clear)(struct storage_s* _this);
    
    void (*deinit)(struct storage_s* _this);
}      storage_t,
      *storage_p,
     **storage_pp,
*const storage_cp;

typedef storage_t const* storage_pc;
typedef storage_t const* const storage_cpc;

/* These are creator and remover */
storage_p storage_creator(void);
void storage_remover(storage_pp);

/* ****************************************************************************
 * End of file
 **************************************************************************** */



storage.c:
/* ****************************************************************************
 * Programmer: Vasiliy V. Bodrov aka Bodro
 * May 15, 2016.
 * ****************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Vasiliy V. Bodrov aka Bodro
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 **************************************************************************** */

#define __STORAGE_C_FILE__

#include "storage.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdbool.h>

static void handler_init(struct storage_s*);
static void handler_add(struct storage_s*, value_t, char*, char*);
static void handler_for_each(struct storage_s const*, output_f);
static void handler_clear(struct storage_s*);
static void handler_deinit(struct storage_s*);

/* 
 * These are exported functions
 */
storage_p storage_creator(void) {
    storage_p _storage = NULL;
    
    _storage = (storage_p) calloc(1, sizeof(storage_t));
    assert(_storage);

    if(_storage) {
        _storage->init     = handler_init;
        _storage->add      = handler_add;
        _storage->for_each = handler_for_each;
        _storage->clear    = handler_clear;
        _storage->deinit   = handler_deinit;

        _storage->init(_storage);
    }
            
    return _storage;
}

void storage_remover(storage_pp _storage) {
    assert(*_storage);

    if(*_storage) {
        if((*_storage)->deinit) {
            (*_storage)->deinit(*_storage);
        }

        free(*_storage);
        
        *_storage = NULL;
    }
}

/* 
 * These are static (internal) functions
 */

void handler_init(struct storage_s* _this) {
    assert(_this);
    
    _this->clear(_this);
    _this->data = NULL;
}

void handler_add(struct storage_s* _this,
                 value_t _value, char* _name, char* _comment) {
    assert(_this);

    auto struct storage_data_s* _search_end(struct storage_data_s*);
    auto struct storage_data_s* _allocator(struct storage_data_s*);
    auto void _add(struct storage_data_s*);
    auto value_t _copy(value_p _value);

    _add(_allocator(_search_end(_this->data)));

    struct storage_data_s* _search_end(struct storage_data_s* _) {
        if(!_ || !_->next) return _;
        return _search_end(_->next);
    }

    struct storage_data_s* _allocator(struct storage_data_s* _) {
        struct storage_data_s* _new =
            (struct storage_data_s*) calloc(1, sizeof(struct storage_data_s));
        assert(_new);

        if(_) _->next = _new;
        else _this->data = _new;

        return _new;
    }

    void _add(struct storage_data_s* _) {
        assert(_);
        
        _->value   = _copy(&_value);
        _->name    = (_name) ? strdup(_name) : NULL;
        _->comment = (_comment) ? strdup(_comment) : NULL;
        _->next    = NULL;
    }
    
    value_t _copy(value_p _value) {
        return (__value_helpers_handlers.p_move()) ?
            __value_helpers_handlers.move(_value) :
            __value_helpers_handlers.copy(*_value);
    }
}

void handler_for_each(struct storage_s const* _this,
                      output_f _output)
{
    assert(_this);
    assert(_output);

    auto void _f(struct storage_data_s*);

    _f(_this->data);

    void _f(struct storage_data_s* _) {
        if(!_) return;
        _output(_->value, _->name, _->comment);
        _f(_->next);
    }
}

void handler_clear(struct storage_s* _this)
{
    assert(_this);

    auto void _purge(struct storage_data_s*);

    _purge(_this->data);

    _this->data = NULL;

    void _purge(struct storage_data_s* _)
    {
        if(!_) return;

        if(_->name) {
            free(_->name);
        }

        if(_->comment) {
            free(_->comment);
        }

        __value_helpers_handlers.delete(&(_->value));
        _->value   = NULL;
        _->name    = NULL;
        _->comment = NULL;

        /* Note. It isn't a tail call! I can do the tail recursion,
         * but I don't want this. So I use direct recursion. Bodro.
         */
        _purge(_->next);

        _->next = NULL;
        free(_);
        _ = NULL;
    }
}

void handler_deinit(struct storage_s* _this)
{
    assert(_this);
    
    _this->clear(_this);
    _this->data = NULL;
}

#ifdef __STORAGE_C_FILE__
#undef __STORAGE_C_FILE__
#endif /* __STORAGE_C_FILE__ */

/* ****************************************************************************
 * End of file
 **************************************************************************** */



test.c:
/* ****************************************************************************
 * Programmer: Vasiliy V. Bodrov aka Bodro
 * May 15, 2016.
 * ****************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2016 Vasiliy V. Bodrov aka Bodro
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
 * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 **************************************************************************** */

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

/* BEGIN >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
/* We prepare the user types and functions */
struct string_s;

typedef struct string_func_s {
    char* (*s_new)(struct string_s* _this, char const* _s);
    char const* (*s_get)(struct string_s* _this);
    void (*s_del)(struct string_s* _this);
} string_func_t;

typedef struct string_s {
    struct string_s* _self;     /* It's a pointer to yourself */
    char* s;                    /* It's a date (string) */
    struct string_func_s* f;    /* It's a pointer to table of functions */
} string;

typedef string user_value_t;

#include "storage.h"
/* END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */

string new_string(string_func_t* _f);
string new_string2(string_func_t* _f, char const* _v);
void del_string(string* _s);

inline static char* handler_s_new(struct string_s*, char const*);
inline static char const* handler_s_get(struct string_s*);
inline static void handler_s_del(struct string_s*);

void user_handler_delete(value_p);
value_t user_handler_copy(value_tc);
value_t user_handler_move(value_p);
value_t user_handler_new(user_value_t);
user_value_t user_handler_get(value_tc);
user_value_t user_handler_get2(value_tc, user_value_t);

string new_string(string_func_t* _f) {
    string* _s = malloc(sizeof(string));
    
    assert(_s);

    _s->_self = _s;
    _s->s = NULL;
    _s->f = _f;

    return *_s;
}

string new_string2(string_func_t* _f, char const* _v) {
    string s = new_string(_f);
    s.f->s_new(s._self, _v);
    return s;
}

void del_string(string* _s) {
    if(_s) {
        _s->f->s_del(_s);
        _s->f = NULL;
        _s->_self = NULL;
        free(_s);
    }
}

char* handler_s_new(struct string_s* _this, char const* _s) {
    assert(_this);
    if(_this && _this->s) _this->f->s_del(_this);
    _this->s = (_s) ? strdup(_s) : NULL;
    return _this->s;
}

char const* handler_s_get(struct string_s* _this) {
    assert(_this);
    return _this->s;
}

void handler_s_del(struct string_s* _this) {
    assert(_this);
    if(_this && _this->s) {
        free(_this->s);
        _this->s = NULL;
    }
}

void user_handler_delete(value_p _v) {
    if(_v && *_v) {
        del_string((string*) *_v);
        *_v = NULL;
    }
}

value_t user_handler_copy(value_tc _v) {
    string s_old = user_handler_get(_v);
    string s_new = new_string2(s_old.f, s_old.f->s_get(s_old._self));
    return user_handler_new(s_new);
}

value_t user_handler_move(value_p _v) {
    assert(_v);
    string s_old = user_handler_get(*_v);
    string s_new = new_string2(s_old.f, s_old.f->s_get(s_old._self));
    del_string(s_old._self);
    
    return user_handler_new(s_new);
}

value_t user_handler_new(user_value_t _uv) {
    return (value_t) _uv._self;
}

user_value_t user_handler_get(value_tc _v) {
    assert(_v);
    return *((string*) _v);
}

user_value_t user_handler_get2(value_tc _v, user_value_t _container) {
    (void) _container;
    return user_handler_get(_v);
}

int main(int argc, char** argv) {
    (void) argc; (void) argv;

    auto bool p_true(void);
    auto bool p_false(void);
    
    string_func_t s_func;
    
    s_func.s_new = handler_s_new;
    s_func.s_get = handler_s_get;
    s_func.s_del = handler_s_del;

    __value_user_helpers_handlers_t user_helpers;

    user_helpers.new    = user_handler_new;
    user_helpers.get    = user_handler_get;
    user_helpers.get2   = user_handler_get2;
    
    __value_helpers_handlers.delete = user_handler_delete;
    __value_helpers_handlers.copy   = user_handler_copy;
    __value_helpers_handlers.move   = user_handler_move;
    __value_helpers_handlers.x      = &user_helpers;

    /* It's a work (#1) */
    do {
        storage_p storage = storage_creator();

        do {
            /* We don't use "move". We use "copy"*/
            __value_helpers_handlers.p_move = p_false;
            
            string data = new_string2(&s_func, "> ");
            storage->add(storage,
                         __value_helpers_handlers.x->new(data), NULL, NULL);
            del_string(data._self);
        } while(0);

        /* We don't use "copy". We use "move"*/
        __value_helpers_handlers.p_move = p_true;
        
        storage->add(storage,
                     __value_helpers_handlers.x->new(
                         new_string2(&s_func, "Hello")), NULL, NULL);
        storage->add(storage,
                     __value_helpers_handlers.x->new(
                         new_string2(&s_func, ",")), NULL, NULL);
        storage->add(storage,
                     __value_helpers_handlers.x->new(
                         new_string2(&s_func, " ")), NULL, NULL);
        storage->add(storage,
                     __value_helpers_handlers.x->new(
                         new_string2(&s_func, "World")), NULL, NULL);
        storage->add(storage,
                     __value_helpers_handlers.x->new(
                         new_string2(&s_func, "!")), NULL, NULL);
        
        void output1(value_t _value,
                     char const* _name,
                     char const* _comment) {
            (void) _name; (void) _comment;
            string s = __value_helpers_handlers.x->get(_value);
            (void) printf("%s", s.f->s_get(s._self));
        }

        storage->for_each(storage, output1);
        (void) puts("");
        
        storage_remover(&storage);
    } while(0);
    /* It's the end of work */

    bool p_true(void) {
        return true;
    }
    
    bool p_false(void) {
        return false;
    }
    
    return EXIT_SUCCESS;
}

/* ****************************************************************************
 * End of file
 **************************************************************************** */


build.sh:
#! /bin/bash

# To use:
# $ rm -f test; clear; ./build.sh; ./test
# $ rm -f test; clear; ./build.sh; valgrind ./test
# $ rm -f test; clear; ./build.sh; valgrind --leak-check=full ./test

gcc -std=gnu99 -Wall -Wextra storage.c test.c -lm -lc -o test
#gcc -std=gnu99 -Wall -Wextra -Wtrampolines storage.c test.c -lm -lc -o test


It's a result (without Valgrind):

bodro@vbodrov-pc:~/workspace/develop/test/test62$ rm -f test; ./build.sh; ./test
> Hello, World!
bodro@vbodrov-pc:~/workspace/develop/test/test62$

It's a result (with Valgrind):

bodro@vbodrov-pc:~/workspace/develop/test/test62$ rm -f test; ./build.sh; valgrind --leak-check=full ./test
==23326== Memcheck, a memory error detector
==23326== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==23326== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==23326== Command: ./test
==23326== 
> Hello, World!
==23326== 
==23326== HEAP SUMMARY:
==23326==     in use at exit: 0 bytes in 0 blocks
==23326==   total heap usage: 32 allocs, 32 frees, 1,594 bytes allocated
==23326== 
==23326== All heap blocks were freed -- no leaks are possible
==23326== 
==23326== For counts of detected and suppressed errors, rerun with: -v
==23326== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
bodro@vbodrov-pc:~/workspace/develop/test/test62$

Best regards,
Vasiliy V. Bodrov aka Bodro,
May 15-16, 2017.

How do you swap two variable?

Hi!

How do you swap two variable?

Look at this! It's a C++ code.
#include <iostream>

using namespace std;

inline void swap_var(int& _x, int& _y) {
    int _ = _x; _x = _y; _y = _;
}

inline void swap_xor(int& _x, int& _y) {
    _x ^= _y; _y ^= _x; _x ^= _y;
}

inline void swap_math(int& _x, int& _y) {
    _x += _y; _y = _x - _y; _x -= _y;
}

int main(void) {
    int a = 5;
    int b = 77201;

    cout << a << ":" << b << endl;
    swap_var(a, b);
    cout << a << ":" << b << endl;
    swap_xor(a, b);
    cout << a << ":" << b << endl;
    swap_math(a, b);
    cout << a << ":" << b << endl;
}


It's the result:
$ rm -f t; g++ -Wall -Wextra -Werror -O2 t.cpp -o t; ./t;
5:77201
77201:5
5:77201
77201:5
$


This is a C code.
#include <stdlib.h>
#include <stdio.h>

void swap_var(int* _x, int* _y) {
    int _ = *_x; *_x = *_y; *_y = _;
}

void swap_xor(int* _x, int* _y) {
    *_x ^= *_y; *_y ^= *_x; *_x ^= *_y;
}

void swap_math(int* _x, int* _y) {
    *_x += *_y; *_y = *_x - *_y; *_x -= *_y;
}

int main(void) {
    int a = 5;
    int b = 77201;

    (void) printf("%d:%d\n", a, b);
    swap_var(&a, &b);
    (void) printf("%d:%d\n", a, b);
    swap_xor(&a, &b);
    (void) printf("%d:%d\n", a, b);
    swap_math(&a, &b);
    (void) printf("%d:%d\n", a, b);

    return EXIT_SUCCESS;
}


It's the result:
$ rm -f t; gcc -Wall -Wextra -Werror -O2 t.c -o t; ./t
5:77201
77201:5
5:77201
77201:5
$

And finally, Erlang :)
-module(t).
-export([t/0]).

swap({X, Y}) ->
    {Y, X}.

t() ->
    A = {1, 2},
    swap(A).

It's the result:
$ erl
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:8:8] [async-threads:10] [kernel-poll:false]

Eshell V7.3  (abort with ^G)
1> c(t).
{ok,t}
2> t:t().
{2,1}
3> q().
ok
4> $

Best regards,
Vasiliy V. Bodrov aka Bodro,
May 16, 2017.

Friday, May 12, 2017

It's a notes about Erlang. It's a work with "crypto" (DES CBC).

Hi, my readers!

I continue the experiments with Erlang. Today I want to introduce a code that works with library "crypto".
I'm trying to encrypt any strings. I'm using DES CBC algorithm.

Look at this!

% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Module: des.erl
% Description: it's a program for a work with crypto module (tests)
% Author: Vasiliy V. Bodrov aka Bodro (bodrov@qtech.ru)
% Date: it's the 19-th of April, 2017 year
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The MIT License (MIT)
%
% Copyright (c) 2017 Vasiliy V. Bodrov aka Bodro
%
% Permission is hereby granted, free of charge, to any person obtaining a
% copy of this software and associated documentation files (the "Software"),
% Software is furnished to do so, subject to the following conditions:
%
% The above copyright notice and this permission notice shall be included
% in all copies or substantial portions of the Software.
%
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
% IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
% CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
% OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
% THE USE OR OTHER DEALINGS IN THE SOFTWARE.
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% See: http://directory.fsf.org/wiki/License:Expat
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-module(des).
-export([test/0, license/0]).
-vsn(1.0).

-define(BLOCK_SIZE, 8).
-define(INPUT_PROMPT, "    Input data: ").

test() ->
    io:format("*****************************************************~n", []),
    io:format("TEST #1:~n~n", []),
    test_impl(),
    io:format("*****************************************************~n", []).

test_impl() ->
    Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>,
    IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>,
    Str = io:get_line(?INPUT_PROMPT),
    P = normalize_str(Str),
    C = crypto:block_encrypt(des_cbc, Key, IVec, P),
    R = crypto:block_decrypt(des_cbc, Key, IVec, C),
    print({P, C, R}).

print({P, C, R}) ->
    io:format("    --------------------------------------------~n", []),
    io:format("    Source: ~p~n", [P]),
    io:format("    --------------------------------------------~n", []),
    io:format("    Source as string: ~p~n", [denormalize_str(P)]),
    io:format("    --------------------------------------------~n", []),
    io:format("    Encrypted: ~p~n", [C]),
    io:format("    --------------------------------------------~n", []),
    io:format("    Decrypted: ~p~n", [R]),
    io:format("    --------------------------------------------~n", []),
    io:format("    Decrypted as string: ~p~n", [denormalize_str(erlang:binary_to_list(R))]).

list_size(L) when is_list(L) ->
    list_size_impl(L, 0).

list_size_impl([], S) ->
    S;
list_size_impl([_|T], S) ->
    list_size_impl(T, S + 1).

normalize_str([]) ->
    [];
normalize_str(L) when is_list(L)->
    C = list_size(L) rem ?BLOCK_SIZE,
    normalizator(L, ?BLOCK_SIZE - C).
    
normalizator(L, 0) ->
    L;
normalizator(L, N) ->
    normalizator(L ++ [0], N - 1).

denormalize_str([]) ->
    [];
denormalize_str(L) when is_list(L) ->
    denormalizator(L, []).

denormalizator([], X) ->
    X;
denormalizator([0|_], X) ->
    X;
denormalizator([10|_], X) ->
    X;
denormalizator([H|T], X) ->
    denormalizator(T, X ++ [H]).

license() ->
    io:format(" The MIT License (MIT)~n"),
    io:format("~n"),
    io:format(" Copyright (c) 2017 Vasiliy V. Bodrov aka Bodro~n"),
    io:format("~n"),
    io:format(" Permission is hereby granted, free of charge, to any person obtaining a~n"),
    io:format(" copy of this software and associated documentation files (the \"Software\"),~n"),
    io:format(" Software is furnished to do so, subject to the following conditions:~n"),
    io:format("~n"),
    io:format(" The above copyright notice and this permission notice shall be included~n"),
    io:format(" in all copies or substantial portions of the Software.~n"),
    io:format("~n"),
    io:format(" THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS~n"),
    io:format(" OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF~n"),
    io:format(" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.~n"),
    io:format(" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY~n"),
    io:format(" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT~n"),
    io:format(" OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR~n"),
    io:format(" THE USE OR OTHER DEALINGS IN THE SOFTWARE.").
    
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% End of file
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



It's a result:
bodro@vbodrov-pc:~/workspace/develop/test/test56$ erl
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:8:8] [async-threads:10] [kernel-poll:false]

Eshell V7.3  (abort with ^G)
1> des:license().
 The MIT License (MIT)

 Copyright (c) 2017 Vasiliy V. Bodrov aka Bodro

 Permission is hereby granted, free of charge, to any person obtaining a
 copy of this software and associated documentation files (the "Software"),
 Software is furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included
 in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
 OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 THE USE OR OTHER DEALINGS IN THE SOFTWARE.ok
2> des:test().
*****************************************************
TEST #1:

    Input data: Hello, world!
    --------------------------------------------
    Source: [72,101,108,108,111,44,32,119,111,114,108,100,33,10,0,0]
    --------------------------------------------
    Source as string: "Hello, world!"
    --------------------------------------------
    Encrypted: <<202,49,22,168,11,91,77,221,161,37,37,51,151,179,205,184>>
    --------------------------------------------
    Decrypted: <<72,101,108,108,111,44,32,119,111,114,108,100,33,10,0,0>>
    --------------------------------------------
    Decrypted as string: "Hello, world!"
*****************************************************
ok
3> q().
ok
4> bodro@vbodrov-pc:~/workspace/develop/test/test56$

See you later! Bye! :)

Best regards,
Vasiliy V. Bodrov aka Bodro,
May 12, 2017.

Thursday, May 11, 2017

I want to tell you a little about myself

Hello dear friends!

My name is Vasiliy. My last name is Bodrov. I was born in the USSR (Russia) in 1984 year. I am a programmer, blogger and motorist. I have got accounts in many social networks.

Blogger (this blog) (English):
http://bodro-ipbsoftware.blogspot.com

LinkedIn (Russian, English):

Facebook (Russian, English):

Twitter (Russian, English):

Instagram (Russian, English):

Github (Russian, English):
https://github.com/vasiliybodrov

VKontakte (Russian):

Odnoklassniki (Russian):

LiveJournal (Russian):

I like to play guitar. Also I like to repair and tune cars. I really love cats and all animals in general. But the most of all I love cats. I have got several cats. I don't like a war. And I'm kind of cosmopolite.

In Myers–Briggs type indicator I'm an Intuitive Logical Extrovert (ENTP). I'm proud of it. ENTP is a fairly rare type in MBTI.

I'm a professional programmer. I like different programming languages, computer technology and I like to study a foundations of programming languages. I know quite a few programming languages, e.g.: C, C++, Linux shell (bash, sh, dash, ash, sed, awk etc), Erlang, Java, LISP (Common LISP, Scheme), JavaScript, Pascal, PHP, Assembler (x86), MS-DOS shell, Could Fusion, HTML, XHTML, HTML5, XUL, XSLT, CSS, ADA, BASIC, PL/1, Prolog, SQL, several DSL, VBA, .NET/C#, Python, Perl, Lua, Haskell, Brainfuck, Brainloller etc. But, having written the word "I know", I exaggerated a little. :) I just used these languages. However many of them I know quite well. I enjoy when I make code on C++ and Erlang! I love this languages! I just love them! And I very love GNU/Linux. Also I used many library in my work and hobby, e.g.: STL, Boost, Qt4, OpenGL, OpenCL, OpenMP, ExtJS, ExtGWT, GWT, Swing, AWT, Spring, VCL, Qt5, MFC, LibVLC, GTK, Android SDK, Nexgen TCP/IP stack, QDBus, libdbus, libxml2, Erlang/OTP, ZeroC ICE, PGQ, libcurl, Broadcom SDK, Zend Framework etc. But this doesn't mean that I know them all perfectly. I just use them at my work, hobby and for training. However many of them I know quite well. E.g. STL, Boost, Qt4 etc. I very like a functional paradigm and object-oriented programming. I enjoy programming!

I think that I told quite a lot about myself. See you later! Bye!




Best regards,
Vasiliy V. Bodrov aka Bodro,
the 11-th of May, 2017 year.

How to reverse singly linked list in C (trivial way)

There is a beautiful morning. It's snowing. And I decided to write one more article. Today it will be just simple article where I would...