U ogromnom krajoliku računalnog programiranja, malo je jezika ostavilo tako neizbrisiv trag kao programski jezik C. Rođen iz želje da se izgradi moćniji i prijenosniji operativni sustav, C je postao temelj na kojem su izgrađena bezbrojna tehnološka dostignuća. Njegova bliska povezanost s operativnim sustavom UNIX, koji je dijelio njegovu filozofiju jednostavnosti i elegancije, dodatno je učvrstila njegovo mjesto u povijesti računalstva.

Priča o C-u počinje ranih 1970-ih kada je Dennis Ritchie, istraživač Bell Labsa, nastojao razviti operativni sustav koji bi se mogao lako prenijeti na različite računalne arhitekture. Kako bi postigao ovaj cilj, Ritchie je trebao jezik koji kombinira kontrolu niske razine s apstrakcijom visoke razine – jezik koji bi mogao izraziti složene ideje, a istovremeno dopuštati izravnu manipulaciju hardverom.

Nadahnut ranijim programskim jezikom B, Ritchie je krenuo u stvaranje novog jezika koji će postati prethodnik C-u. Sa svojom sažetom sintaksom i snažnim značajkama, C je brzo stekao popularnost među programerima. Njegova sposobnost učinkovitog pristupa memoriji, upravljanja pokazivačima i interakcije s hardverom učinila ga je idealnim za sistemsko programiranje.

U međuvremenu, u Bell Labsu, grupa vizionara, uključujući Kena Thompsona i Briana Kernighana, radila je na razvoju operativnog sustava UNIX. Prepoznavši potencijal C-a, donijeli su hrabru odluku da preprave UNIX u samom jeziku. Ovaj ključni trenutak označio je rođenje duboke i trajne veze između C-a i UNIX-a.

Brak između C-a i UNIX-a bio je idealan spoj. UNIX je pružio robusnu i fleksibilnu platformu za razvoj C-a, dok je C ponudio potrebne alate za izgradnju i poboljšanje operativnog sustava. Kako se UNIX širio na razne institucije i sveučilišta, tako se i koristio C. Njegova jednostavnost, učinkovitost i prenosivost učinile su ga jezikom izbora za razvoj softvera, učvrstivši njegovu reputaciju moćnog i svestranog alata.

Simbiotski odnos između C i UNIX-a doveo je do razvoja brojnih kultnih softvera i tehnologija. Sam jezik C doživio je doradu, objavljivanjem “Programskog jezika C” Kernighana i Ritchieja 1978., koji se obično naziva “K&R C.” Ova je knjiga postala konačan vodič za C programiranje, oblikujući način na koji su generacije programera pristupale jeziku.

Kako je vrijeme prolazilo, C i UNIX nastavili su se zajedno razvijati i napredovati. Utjecaj C-a proširio se izvan UNIX ekosustava, postavši jezik izbora za operativne sustave kao što su Windows, Linux i macOS. Njegov se utjecaj proširio na različite domene, uključujući ugrađene sustave, razvoj igara i znanstveno računalstvo.

Danas, desetljećima nakon njegovog početka, naslijeđe C-a i njegova veza s UNIX-om ostaju jaki. Nebrojeni programeri još uvijek prihvaćaju eleganciju i snagu jezika, a sustavi slični UNIX-u i dalje pružaju plodno tlo za nastavak evolucije C-a.

Povijest programskog jezika C i njegove duboko ukorijenjene veze s operativnim sustavom UNIX služe kao dokaz transformativne moći suradnje, jednostavnosti i elegantnog dizajna. Dok se krećemo kroz krajolik tehnologije koji se stalno mijenja, nemojmo zaboraviti dubok utjecaj C-a i UNIX-a, čiji je spoj postavio temelje za digitalni svijet u kojem danas živimo.

Ovo su moje kratke bilješke:

GCC kompilacija

compile
//compile single file:
gcc hello_world.c //produces a.out executable

//specify ouput file name:
gcc -o elf hello_world.c  //produces file: elf

//compile multiple .c files
gcc -o elf part_one.c part_two.c 
compile with debug data
// use '-g' option to enable debug data needed for valgrind
gcc -g hello_world.c

// to see all warnings 
gcc -Wall hello_world.c

// pedantic 
gcc -pedantic hello_world.c

// version -std=c89, -std=c99, -std=c11
gcc -std=c89 hello_world.c
macro as cli arg
#ifdef MY_MOD_ENABLE_FEATURE
 #define SIZE_FEATURE 1212
#endif
//then compile your code with -D:
gcc proggy.c -DMY_MOD_ENABLE_FEATURE

static linking / static library
gcc -c iff.c //create iff.o object
ar clq libiff.a iff.o //create static library libiff.a

//compile hello.c with libiff.a 
gcc -o hello hello.c -L ./ -liff //-L adds location, while lib name is: -l + lib[iff].a 
shared object / shared library
gcc -shared -o iff.so iff.c

//compile with piggy.so
gcc -o hello hello.c ./piggy.so
optimise
To get warning about uninitialized variables, use: 
$ gcc -O -Wall -Wextra foo.c
bash script: basic compile
usage: $./compile <filename> 
#!/bin/bash
LIBS=$(pkg-config --cflags --libs gtk+-2.0)
FILE_NAME=$(echo $1 | sed 's/.\///')
gcc -g -o ${FILE_NAME%.*}.elf $1 $LIBS
bash script: compile multiple
usage: $./compile.sh 
#filename: compile.sh
#!/bin/bash
SRC_FILES="boa.c boa.h main.c"
OBJ_FILES="boa.o main.o"
RM_FILES="boa.o main.o boa.h.gch"

# compile
for SRCFILE in $SRC_FILES
do
    gcc -g -O0 -c $SRCFILE
done

# build
gcc -g -O0 -o elf $OBJ_FILES

# clean
rm $RM_FILES

Tipovi

Svi tipovi
_Bool (bool) - hold 0/1 false/true
char - can hold one ascii char (0-255)

integer types:
char
short int
int
long int
long long int

unsigned integer types:
unsigned char
unsigned short int
unsigned int
unsigned long int
unsigned long long int

real floating types:
float
double
long double

(c11) complex types:
float _Complex
double _Complex
long double _Complex

empty type
void

qualifiers
const
volatile
restrict
Veličine
Byte = 8 bits (bit is binary number)
Kilobyte (KB)   = 1024 bytes
Megabyte (MB)  = 1024 Kilobytes
Gigabyte (GB)   = 1024 Megabytes
Terabyte (TB)    = 1024 Gigabytes
Petabyte (PB)  = 1024 Terabytes
Exabyte (EB)   = 1024 Petabytes
Zettabyte (ZB)  = 1024 Exabytes
Yottabyte (YB)  = 1024 Zettabytes

Depends on platform:
linux 64bit, gcc (GCC) 5.3.0:
char           (1byte, 8 bit) -128...127
unsigned char  (1byte, 8 bit) 0...255
short          (2byte, 16 bit) -32768...32767
unsigned short (2byte, 16 bit) 0...65535
int            (4byte, 32 bit) -2147483648...2147483647
unsigned int   (4byte, 32 bit) 0...4294987295
long           (8byte, 64 bit)
unsigned long  (8byte, 64 bit) 0...18446744073709551615
long long, singned/unsigned, same as long
float          (4byte, 32 bit) ±1.2×10-38 to ±3.4×1038
double         (8byte, 64 bit) ±2.3×10-308 to ±1.7×10308 OR alias to float for AVR.
long double    (16byte, 128 bit) (ARM: 8, AVR: 4, x86: 10, x64: 16bit)
Konverzija
converting real to integer type, fractional part is lost
printf("%d\n", (int) 33.424); // => 33
int int01 = 2.3434; // => 2

float fractional part can hold 6 digits
float f = 9.999999;
so when double gets downcasted to float (linux 64/gcc):
double g = 9.9999999999;
printf("%f\n", (float) g);// => 10.000000
Realni brojevi (float/double)
Interno se brojevi s pomičnim zarezom pohranjuju u dva dijela: razlomak (ili
mantisa) i eksponent. Ako su to M i E, vrijednost pomičnog zareza
broj je dan kao M x 2E. Na primjer, broj 0,375 pohranjen je kao
mantisa 0,75 i eksponent -1. Dostupan je samo ograničen broj bitova
pohraniti eksponent i mantisu. Uzmimo, kao primjer,
raspored broja s pomičnim zarezom u riječi od samo 8 bita. Odlučili smo se za
trobitni eksponent i pet bitna mantisa. Ovaj raspored je shematski
(pravi prikaz je drugačiji, pogledajte knjigu na računalu
arhitektura za sve detalje):

eksponent: mantisa:
[E2][E1][E0] [M4][M3][M2][M1][M0]

Bitovi su numerirani tako da je bit najmanje važnosti krajnji desni
bit svake od mantise i eksponenta. Pretpostavljamo da eksponent
pohranjuje brojeve s komplementom dvojke. Bitni uzorak za -1 je stoga 111. Mantisa je raspoređena tako da najvažniji bit M4 broji polovice,
sljedeći bit M3 broji četvrtinu, i tako dalje. Stoga, bit uzorak za
0,75 je 11000. Predstavljanje 0,375 kao 8-bitni broj s pomičnim zarezom
je stoga kao što je prikazano u nastavku:

eksponent: mantisa:
[1][1][1] [1][1][0][0][0]

Tipično, eksponent ima raspon od 10+-300, a mantisa ima oko
15 znamenki preciznost. Posljedica ograničene preciznosti mantise
je da su brojevi s pomičnim zarezom podskup realnih brojeva. Stoga,
dva broja s pomičnim zarezom mogu se naći u C, recimo x i y, tako da x postoji
nije jednako y, a između njih ne postoji broj s pomičnim zarezom
dva broja. Na primjer, u jednoj C implementaciji ne postoji
broj s pomičnim zarezom između:

1,000000000000000222044604925031
i:
1,000000000000000444089209850062

ili između:
345678912.0000000596046447753906
i:
345678912.0000001192092895507812

Brojevi s pomičnim zarezom zapravo prolaze kroz stvarne brojeve, iako unutra
malim koracima. Stvarna veličina koraka ovisi o stroju i kompajleru. Ovaj
koračno ponašanje ima niz posljedica. Prvo, mnogi brojevi ne mogu
biti točno predstavljen. Na primjer, mnogi računalni sustavi ne mogu
točno predstavljaju broj 0,1. Na primjer, najbliži brojevi su:

0.09999999999999999916733273153113
i:
0,1000000000000000055511151231257

Iz tog razloga brojevima s pomičnim zarezom treba pažljivo manipulirati:
0,1*10 nije nužno jednako 1,0. Na nekim je sustavima veći od
1; na drugima je manji od 1. Test jednakosti brojeva s pomičnim zarezom,
na primjer a==0.1, vjerojatno također neće dati očekivani rezultat.

Pointer

void* adresira bilo koju vrstu osim pointer funkcije
double    d = 23.231;
double  *d1 = &d;
double **d2 = &d1;

//void** is used only as pointer to void*
//so to pass double pointer to void use regular void*

void    *v1 = d2;
double **d3 = (double**) v1;
printf("%g\n",  **d3 );
cast void pointer u drugi tip
void *data;

//cast to const void ptr: 
(const void *) data;

//cast from struct:
double *double_ptr = ((double*) struct->vector);
//if struct->vector is array of void* pointers, you can use now double_ptr as array:
printf("%g\n", double_ptr[3]);

//simplify passed in dblptr for pointer arithmetic 
void** easypointer = (*struct)->vector;
easypointer += offset;
pass to void* argument
//outside variable 
int func(void *arg_data){...}
double number = 2.121; 
func(&number);

//direct pass 
func(&(double){42.424});
otmjene deklaracije
int board[8][8];   // an array of arrays of int
int **ptr;         // a pointer to a pointer to int
int * risks[10];   // a 10-element array of pointers to int
int (* rusks)[10]; // a pointer to an array of 10 ints
int *oof[3][4];    // a 3 x 4 array of pointers to int
int (* uuf)[3][4]; // a pointer to a 3 x 4 array of ints
int (* uof[3])[4]; // a 3-element array of pointers to 4-element arrays of int

1. The [], which indicates an array, and the (), which indicates a 
function, have the same precedence. This precedence is higher than that 
of the * indirection operator, which means that the following 
declaration makes risks an array of pointers rather than a pointer to 
an array:

int * risks[10];

2. The [] and () associate from left to right. This next declaration 
makes goods an array of 12 arrays of 50 ints, not an array of 50 arrays 
of 12 ints:

int goods[12][50];

3. Both [] and () have the same precedence, but because they associate 
from left to right, the following declaration groups * and rusks 
together before applying the brackets. This means that the following 
declaration makes rusks a pointer to an array of 10 ints:

int (* rusks)[10];

^^^^^^^^^^^^^^^^^^^^^^^^^

int *oof[3][4];

The [3] has higher precedence than the *, and, because of the 
left-to-right rule, it has higher precedence than the [4]. Hence, oof 
is an array with three elements. Next in order is [4], so the elements 
of oof are arrays of four elements. The * tells us that these elements 
are pointers. The int completes the picture: oof is a three-element 
array of four-element arrays of pointers to int, or, for short, a 3x4 
array of pointers to int. Storage is set aside for 12 pointers.


int (* uuf)[3][4];

The parentheses cause the * modifier to have first priority, making uuf 
a pointer to a 3x4 array of ints. Storage is set aside for a single 
pointer.

^^^^^^^^^^^^^^^^^^^^^^^^^

char * fump();       // function returning pointer to char
char (* frump)();    // pointer to a function that returns type char
char (* flump[3])(); // array of 3 pointers to functions that 
                     // return type char
                
You can use typedef to build a sequence of related types:
typedef int arr5[5];
typedef arr5 * p_arr5;
typedef p_arr5 arrp10[10];
arr5 togs; // togs an array of 5 int
p_arr5 p2; // p2 a pointer to an array of 5 int
arrp10 ap; // ap an array of 10 pointers to array-of-5-int
adresa elementa niza

int a[3];
int* b = &a[1]; //get address of element at index 1

printf

printf
int printf(const char *format, ...)

Parameters

format − This is the string that contains the text to be written to stdout.
It can optionally contain embedded format tags that are replaced by the values
specified in subsequent additional arguments and formatted as requested.
Format tags prototype is %[flags][width][.precision][length]specifier,
which is explained below:

specifier   Output
c   Character
d or i  Signed decimal integer
e   Scientific notation (mantissa/exponent) using e character
E   Scientific notation (mantissa/exponent) using E character
f   Decimal floating point
g   Uses the shorter of %e or %f
G   Uses the shorter of %E or %f
o   Signed octal
s   String of characters
u   Unsigned decimal integer
x   Unsigned hexadecimal integer
X   Unsigned hexadecimal integer (capital letters)
p   Pointer address
n   Nothing printed
%   Character

flags   Description
-   Left-justify within the given field width; Right justification is the
    default (see width sub-specifier).
+   Forces to precede the result with a plus or minus sign (+ or -) even for
    positive numbers. By default, only negative numbers are preceded with a -ve sign.
(space)     If no sign is going to be written, a blank space is inserted
            before the value.
#   Used with o, x or X specifiers the value is preceded with 0, 0x or 0X
    respectively for values different than zero. Used with e, E and f, it
    forces the written output to contain a decimal point even if no digits
    would follow. By default, if no digits follow, no decimal point is
    written. Used with g or G the result is the same as with e or E but
    trailing zeros are not removed.
0   Left-pads the number with zeroes (0) instead of spaces, where
    padding is specified (see width sub-specifier).

width   Description
(number)    Minimum number of characters to be printed. If the value to be
            printed is shorter than this number, the result is padded with
            blank spaces. The value is not truncated even if the result
            is larger.
*           The width is not specified in the format string, but as an
            additional integer value argument preceding the argument
            that has to be formatted.
.precision  Description
.number     For integer specifiers (d, i, o, u, x, X) − precision specifies
            the minimum number of digits to be written. If the value to be
            written is shorter than this number, the result is padded with
            leading zeros. The value is not truncated even if the result is
            longer. A precision of 0 means that no character is written for
            the value 0. For e, E and f specifiers − this is the number of
            digits to be printed after the decimal point. For g and G
            specifiers − This is the maximum number of significant digits
            to be printed. For s − this is the maximum number of characters
            to be printed. By default all characters are printed until the
            ending null character is encountered. For c type − it has no
            effect. When no precision is specified, the default is 1. If
            the period is specified without an explicit value for precision,
            0 is assumed.
.*          The precision is not specified in the format string, but as an
            additional integer value argument preceding the argument that has
            to be formatted.

length  Description
h   The argument is interpreted as a short int or unsigned short int (only
    applies to integer specifiers: i, d, o, u, x and X).
l   The argument is interpreted as a long int or unsigned long int for
    integer specifiers (i, d, o, u, x and X), and as a wide character or
    wide character string for specifiers c and s.
L   The argument is interpreted as a long double (only applies to floating
    point specifiers: e, E, f, g and G).

    additional arguments − Depending on the format string, the function
    may expect a sequence of additional arguments, each containing one
    value to be inserted instead of each %-tag specified in the format
    parameter (if any). There should be the same number of these arguments
    as the number of %-tags that expect a value.

Return Value
If successful, the total number of characters written is returned.
On failure, a negative number is returned.
sprintf – to string
char dest_string[3];
sprintf(dest_string, "%x", 256);
fprintf stderr – error messages
fprintf(stderr, "Memory error!\n");
exit(EXIT_FAILURE);

Datotečni I/O

Učitaj datoteku
char *das_load_text(char *__filename){
    FILE *f;
    char *text;
    size_t size;
    f = fopen(__filename, "r");
    if(f == NULL)
        return NULL;

    fseek(f, 0, SEEK_END);
    size = ftell(f);

    rewind(f);
    text = malloc(size + 1);
    size = fread(text, 1, size, f);
    fclose(f);
    text[size] = 0;

    return text;
}
dodaj liniju
void append_line(char *filename, char *line)
{
    FILE *fp;
    fp = fopen(filename ,"a+");
    fprintf(fp, line);
    fclose(fp);
}
i/o modovi
Mode String 

"r" 
Open a text file for reading.

"w" 
Open a text file for writing, truncating an existing file to zero
length, or creating the file if it does not exist.

"a" 
Open a text file for writing, appending to the end of an
existing file, or creating the file if it does not exist.

"r+" 
Open a text file for update (that is, for both reading and
writing).

"w+" 
Open a text file for update (reading and writing), first
truncating the file to zero length if it exists or creating the file
if it does not exist.

"a+" 
Open a text file for update (reading and writing), appending
to the end of an existing file, or creating the file if it does not
yet exist; the whole file can be read, but writing can only be
appended.

"rb", "wb", "ab", "ab+",
"a+b", "wb+", "w+b",
"ab+", "a+b" 

Like the preceding modes, except it uses binary mode instead
of text mode.

For systems such as Unix and Linux that have just one file type, 
the modes with the b are equivalent to the corresponding modes lacking the b.

Terminal

pošalji izlaz u drugi termial
Open terminal and find out where it is by typing:
$ tty
=> /dev/pts/5

Now open another and type:
$ echo "ekko" > /dev/pts/5

This should print "ekko" in /dev/pts/5

In C you could use:
void memerr(){
    FILE *f = fopen("/dev/pts/5", "w");
    fprintf(f, "%s\n", "Memory Error!");
}

Which is same as above. Also you can use cat command to clear target terminal.
argumenti naredbenog retka
 char *fg = NULL;
    char *bg = NULL;
    char *close = NULL;

    if (argc != 7){
        help();
    }
    else {
        for (int i=1; i<argc; i++){
            if ( (memcmp(argv[i], "-f", 2) == 0) )
                fg = argv[i+1];
            else if ( (memcmp(argv[i], "-b", 2) == 0) )
                bg = argv[i+1];
            else if ( (memcmp(argv[i], "-c", 2) == 0) )
                close = argv[i+1]; 
        }        

        if (!fg)
            help();
        if (!bg)
            help();
        if (!close)
            help();  
    }

bitwise operatori

osnovno
// byte (char type) has 8 smaller bits
// bit can be 1 or 0
// 01100100 
// rightmost bit is low-order bit, leftmost is high-order bit  
// left-most is sign bit, if this bit is 1, number is negative
pozitivno ili negativno
// leftmost bit in signed types represents positive/negative boolean
// 0 is positive, while 1 is negative
// leftmost bit is also called signed bit

00000001 = 1 
10000001 = -1

01111111 = 127
11111111 = -128
int/bin/hex/char byte tablica
INT   BINARY   HEX  CHAR
^^^   ^^^^^^   ^^^  ^^^^
[000] 00000000 0x0  \0
[001] 00000001 0x1  SOH
[002] 00000010 0x2  STX
[003] 00000011 0x3  ETX
[004] 00000100 0x4  EOT
[005] 00000101 0x5  
[006] 00000110 0x6  ACK
[007] 00000111 0x7  
[008] 00001000 0x8  \b
[009] 00001001 0x9  \t
[010] 00001010 0xa  \n
[011] 00001011 0xb  
[012] 00001100 0xc  
[013] 00001101 0xd  \r
[014] 00001110 0xe  
[015] 00001111 0xf  
[016] 00010000 0x10 DLE
[017] 00010001 0x11 DC1
[018] 00010010 0x12 DC2
[019] 00010011 0x13 DC3
[020] 00010100 0x14 DC4
[021] 00010101 0x15 NAK
[022] 00010110 0x16 SYN
[023] 00010111 0x17 ETB
[024] 00011000 0x18 CAN
[025] 00011001 0x19 EM
[026] 00011010 0x1a SUB
[027] 00011011 0x1b ESC
[028] 00011100 0x1c F5
[029] 00011101 0x1d G5
[030] 00011110 0x1e R5
[031] 00011111 0x1f US
[032] 00100000 0x20 WHITESPACE 
[033] 00100001 0x21 !
[034] 00100010 0x22 "
[035] 00100011 0x23 #
[036] 00100100 0x24 $
[037] 00100101 0x25 %
[038] 00100110 0x26 &
[039] 00100111 0x27 '
[040] 00101000 0x28 (
[041] 00101001 0x29 )
[042] 00101010 0x2a *
[043] 00101011 0x2b +
[044] 00101100 0x2c ,
[045] 00101101 0x2d -
[046] 00101110 0x2e .
[047] 00101111 0x2f /
[048] 00110000 0x30 0
[049] 00110001 0x31 1
[050] 00110010 0x32 2
[051] 00110011 0x33 3
[052] 00110100 0x34 4
[053] 00110101 0x35 5
[054] 00110110 0x36 6
[055] 00110111 0x37 7
[056] 00111000 0x38 8
[057] 00111001 0x39 9
[058] 00111010 0x3a :
[059] 00111011 0x3b ;
[060] 00111100 0x3c <
[061] 00111101 0x3d =
[062] 00111110 0x3e >
[063] 00111111 0x3f ?
[064] 01000000 0x40 @
[065] 01000001 0x41 A
[066] 01000010 0x42 B
[067] 01000011 0x43 C
[068] 01000100 0x44 D
[069] 01000101 0x45 E
[070] 01000110 0x46 F
[071] 01000111 0x47 G
[072] 01001000 0x48 H
[073] 01001001 0x49 I
[074] 01001010 0x4a J
[075] 01001011 0x4b K
[076] 01001100 0x4c L
[077] 01001101 0x4d M
[078] 01001110 0x4e N
[079] 01001111 0x4f O
[080] 01010000 0x50 P
[081] 01010001 0x51 Q
[082] 01010010 0x52 R
[083] 01010011 0x53 S
[084] 01010100 0x54 T
[085] 01010101 0x55 U
[086] 01010110 0x56 V
[087] 01010111 0x57 W
[088] 01011000 0x58 X
[089] 01011001 0x59 Y
[090] 01011010 0x5a Z
[091] 01011011 0x5b [
[092] 01011100 0x5c \
[093] 01011101 0x5d ]
[094] 01011110 0x5e ^
[095] 01011111 0x5f _
[096] 01100000 0x60 `
[097] 01100001 0x61 a
[098] 01100010 0x62 b
[099] 01100011 0x63 c
[100] 01100100 0x64 d
[101] 01100101 0x65 e
[102] 01100110 0x66 f
[103] 01100111 0x67 g
[104] 01101000 0x68 h
[105] 01101001 0x69 i
[106] 01101010 0x6a j
[107] 01101011 0x6b k
[108] 01101100 0x6c l
[109] 01101101 0x6d m
[110] 01101110 0x6e n
[111] 01101111 0x6f o
[112] 01110000 0x70 p
[113] 01110001 0x71 q
[114] 01110010 0x72 r
[115] 01110011 0x73 s
[116] 01110100 0x74 t
[117] 01110101 0x75 u
[118] 01110110 0x76 v
[119] 01110111 0x77 w
[120] 01111000 0x78 x
[121] 01111001 0x79 y
[122] 01111010 0x7a z
[123] 01111011 0x7b {
[124] 01111100 0x7c |
[125] 01111101 0x7d }
[126] 01111110 0x7e ~
[127] 01111111 0x7f 
[128] 10000000 0x80 
[129] 10000001 0x81 
[130] 10000010 0x82 
[131] 10000011 0x83 
[132] 10000100 0x84 
[133] 10000101 0x85 
[134] 10000110 0x86 
[135] 10000111 0x87 
[136] 10001000 0x88 
[137] 10001001 0x89 
[138] 10001010 0x8a 
[139] 10001011 0x8b 
[140] 10001100 0x8c 
[141] 10001101 0x8d 
[142] 10001110 0x8e 
[143] 10001111 0x8f 
[144] 10010000 0x90 
[145] 10010001 0x91
[146] 10010010 0x92
[147] 10010011 0x93
[148] 10010100 0x94
[149] 10010101 0x95
[150] 10010110 0x96
[151] 10010111 0x97
[152] 10011000 0x98
[153] 10011001 0x99
[154] 10011010 0x9a
[155] 10011011 0x9b
[156] 10011100 0x9c
[157] 10011101 0x9d
[158] 10011110 0x9e
[159] 10011111 0x9f
[160] 10100000 0xa0
[161] 10100001 0xa1
[162] 10100010 0xa2
[163] 10100011 0xa3
[164] 10100100 0xa4
[165] 10100101 0xa5
[166] 10100110 0xa6
[167] 10100111 0xa7
[168] 10101000 0xa8
[169] 10101001 0xa9
[170] 10101010 0xaa
[171] 10101011 0xab
[172] 10101100 0xac
[173] 10101101 0xad
[174] 10101110 0xae
[175] 10101111 0xaf
[176] 10110000 0xb0
[177] 10110001 0xb1
[178] 10110010 0xb2
[179] 10110011 0xb3
[180] 10110100 0xb4
[181] 10110101 0xb5
[182] 10110110 0xb6
[183] 10110111 0xb7
[184] 10111000 0xb8
[185] 10111001 0xb9
[186] 10111010 0xba
[187] 10111011 0xbb
[188] 10111100 0xbc
[189] 10111101 0xbd
[190] 10111110 0xbe
[191] 10111111 0xbf
[192] 11000000 0xc0 
[193] 11000001 0xc1 
[194] 11000010 0xc2 
[195] 11000011 0xc3 
[196] 11000100 0xc4 
[197] 11000101 0xc5 
[198] 11000110 0xc6 
[199] 11000111 0xc7 
[200] 11001000 0xc8 
[201] 11001001 0xc9 
[202] 11001010 0xca 
[203] 11001011 0xcb 
[204] 11001100 0xcc 
[205] 11001101 0xcd 
[206] 11001110 0xce 
[207] 11001111 0xcf 
[208] 11010000 0xd0 
[209] 11010001 0xd1 
[210] 11010010 0xd2 
[211] 11010011 0xd3 
[212] 11010100 0xd4 
[213] 11010101 0xd5 
[214] 11010110 0xd6 
[215] 11010111 0xd7 
[216] 11011000 0xd8 
[217] 11011001 0xd9 
[218] 11011010 0xda 
[219] 11011011 0xdb 
[220] 11011100 0xdc 
[221] 11011101 0xdd 
[222] 11011110 0xde 
[223] 11011111 0xdf 
[224] 11100000 0xe0 
[225] 11100001 0xe1 
[226] 11100010 0xe2 
[227] 11100011 0xe3 
[228] 11100100 0xe4 
[229] 11100101 0xe5 
[230] 11100110 0xe6 
[231] 11100111 0xe7 
[232] 11101000 0xe8 
[233] 11101001 0xe9 
[234] 11101010 0xea 
[235] 11101011 0xeb 
[236] 11101100 0xec 
[237] 11101101 0xed 
[238] 11101110 0xee 
[239] 11101111 0xef 
[240] 11110000 0xf0 
[241] 11110001 0xf1 
[242] 11110010 0xf2 
[243] 11110011 0xf3 
[244] 11110100 0xf4 
[245] 11110101 0xf5 
[246] 11110110 0xf6 
[247] 11110111 0xf7 
[248] 11111000 0xf8 
[249] 11111001 0xf9 
[250] 11111010 0xfa 
[251] 11111011 0xfb 
[252] 11111100 0xfc 
[253] 11111101 0xfd 
[254] 11111110 0xfe 
[255] 11111111 0xff 
binarno s predznakom 256
00000001  1
00000011  3
00000111  7
00001111  15
00011111  31
00111111  63
01111111  127
11111111  255

10000000  128
11000000  192
11100000  224
11110000  240
11111000  248
11111100  252
11111110  254
11111111  255
AND operator &
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0
1 & 1 = 1

  00011001  25
& 01001101  77 
  --------
  00001001   9

To test this use python console:
>>> bin(0b00011001 & 0b01001101)
'0b1001'

'0's are removed
Inclusive OR operator |
0|0 bits are 0 other combos are 1

0 | 0 = 0
1 | 0 = 0
0 | 1 = 1
1 | 1 = 1
Exclusive OR operator ^ (XOR)
same bits are 0 mixed combos are 1

0 | 0 = 0
1 | 0 = 1
0 | 1 = 1
1 | 1 = 0
Ones complement operator ~ (unary)
bit flip

b1  ~b1
^^^^^^^
0    1
1    0

python console test:
>>> ~0b11111111
-256
>>> 0b11111111
255
>>> 
Shift operators <<, >>
char a = 1; //00000001
a <<= 7;    //10000000
a >>= 7;    //11111111
structure bit fields
struct packed_struct{
    unsigned int :3;    //3 unamed bits
    unsigned int f1:1;  //1 bool bit
    unsigned int f2:1; 
    unsigned int f3:1;
    unsigned int type:8;  //type is 8 bits
    unsigned int index:18; //index is 18
};
display byte as binary
#include <stdio.h>    
#include <stdlib.h>
#include <string.h>

char *das_toByteBinary(unsigned char n)
{
    if (n == 0){
        char *s = malloc(sizeof (char) * (8+1));
        if (!s)
            return NULL;        
        bzero(s, 9); //nullify all 
        memset(s, 48, 8); //set string zeros "0" 
        return s;
    }
    
    int t = n;
    int r = 0, c = 0;    

    //how much digits do you have?
    r = n % 2;
    c++;
    while (t >= 2){
        t = t / 2;
        r = t % 2;
        c++;
        r = 0;
    }
 
    //malloc and store chars
    char *s = malloc(sizeof (char) * (8+1));
    if (!s)
        return NULL;        
    bzero(s, 9); //nullify all 
    memset(s, 48, 8); //set string zeros "0" 
    
    c = 7; 
    t = n;
    r = n % 2;
    
    s[c--] = ('0' + r);
    while (t >= 2){
        t = t / 2;
        r = t % 2;
        s[c--] = ('0' + r); 
        r = 0;
    }
    return s;
}

unsigned char das_fromByteBinary(char *s) {
  return (unsigned char) strtol(s, NULL, 2);
}

int main(void)
{
    char a = 123;
    printf("%s\n", das_toByteBinary(a));

}
moving bits
[   1] 00000001 //char a=1;
[  64] 01000000 // a <<= 6; 
[   2] 00000010 // a >>= 5; 
[-128] 10000000 // a <<= 6;  
[  -4] 11111100 // a >>= 5; 
[  -1] 11111111 // a >>= 5; 
flags as function arguments
#define ONE   0x01 // 00000001
#define TWO   0x02 // 00000010
#define FOUR  0x04 // 00000100
#define EIGHT 0x08 // 00001000
#define TEN   0x10 // 00010000
#define TWTY  0x20 // 00100000
#define FRTY  0x40 // 01000000
#define EITY  0x80 // 10000000

void func(char __flags){

    char flag = 0;
    flag |= __flags;

    if ((flag & ONE) != 0)
        printf("ONE \n");
    if ((flag & TWO) != 0)
        printf("TWO \n");
    if ((flag & FOUR) != 0)
        printf("FOUR \n");
}

int main(){
    func(TWO|FRTY);
}
accept only arguments algorithm
//more useful for weaktyped (js/php) but can be handy with ADTs in C
if (!(typeof arg === 'boolean' || arg === undefined)) return null;

Array

osnove
//arrays are dereferenced pointers 
int *heap_iptr = malloc(sizeof (int) * 10); // make room for 10 ints on heap 
int stack_arr[10]; // make room for 10 ints on stack 

heap_iptr[0] = 100; 
//is same as: 
*(heap_iptr+0) = 101;

//address &heap_iptr[0] == heap_iptr 
real number vs index number
//reserve 32 spaces of size double*32 
double dbla[32] = {0};
 
//so index starts at 0 but ends at 31
dbla[0] = 523.566;
dbla[31] = 41.23;

//so when using in for loop, use < with real number and <= with index
 for (int i=0; i<32; i++)
    printf("%g\n", dbla[i]);
init array
double dbla[24] = {0};
 
double dbla[24];
memset(&dbla, 0, (sizeof(double) * 24));

void *a = malloc(sizeof(int)*3);
a = (int [3]) {12, 16, 3};
printf("%d\n", ((int*) a)[1] );
//it's easier to dereference void pointer and then use it as array ie:
int *a_ptr = (int*) a;    
printf("%d\n", a_ptr[1] );
resizable array (heap memory)
typedef struct Vector{
    size_t array_length;
    double data[1];
}Vector;
size_t item_number = 256;
size_t malloc_size = sizeof (Vector) + ((sizeof (double)) * item_number-1);
Vector *vec = malloc(malloc_size);
//use realloc to resize
size_t new_size = sizeof (Vector) + ((sizeof (double)) * (512-1));
vec = realloc(vec, malloc_size);
pass array to function
void funarray(int *array)
{
    printf("%d\n", array[0]);
}

int main()
{
    int a[3] = {0};
    a[0] = 124;
    funarray(a);
}
pass in function data
void accept_double_ptr(double *arg){
    printf("%g\n", arg[2]);
}
accept_double_ptr((double*) &(double []) {.234, 42.24, 123.32, 2.5});
multi-dimensional array
const int array_2d[3][3] = {
    {0,1,2}, 
    {0,1,2}, 
    {0,1,2}
};
malloc for array of pointers/strings
static char **strdata; 
strdata = malloc(sizeof(char*));

strdata[0] = "string";

MEMORY ALLOCATION

work with any memory
// header + data structure 
// data is 1 char which is 1 byte. size tells you where chunk ends

//memory chunk with size
//size after data[] is empty and can fit any type if you alloc enough space

typedef struct Chunk{
    size_t size; //size of chunk
    char data[1];   
} Chunk;

char *somedata = "Some string but it can be data type just cast it to char.";
size_t malloc_size = sizeof(Chunk) + strlen(somedata) +1;   //+1 to set last byte to NULL 
Chunk *cnk = malloc(malloc_size);                           //allocate heap memory
memset(chk, '\0', malloc_size);                             //nullify all
memcpy(chk, somedata, malloc_size);                         //copy data


//you can then make more complex structure where header will point to 
//__data. that way you are working only with one chunk.

typedef struct Chunk{
    char* key;
    double* number;
    size_t size;
    char __data[1];
} Chunk;


//or more complex grouping
typedef struct Element{
    unsigned int size;
    struct color{
        int red;
        int green;
        int blue;
    } color[1];
} Element;
memory units
bit         - 0/1
byte (char) - 8 bits

byte:
 7  6  5  4  3  2  1  0
 *  *  *  *  *  *  *  *
128 64 32 16 8  4  2  1

On Linux 4.3 x86_64:
char:      1 byte
short:     2 bytes  2 x 8 bits = 16 bit
int:       4 bytes  4 x 8 bits = 32 bit
long:      8 bytes  8 x 8 bits = 32 bit
long long: 8 bytes  8 x 8 bits = 64 bit
float:     4 bytes  4 x 8 bits = 32 bit
double:    8 bytes  8 x 8 bits = 64 bit
memory editing
//copy float to float byte by byte
typedef char byte;
float f_src = 23.32f;
float f_dst = 0;

byte *f_src_b = (byte*) &f_src;
byte *f_dst_b = (byte*) &f_dst;

f_dst_b[0] = f_src_b[0];
f_dst_b[1] = f_src_b[1];
f_dst_b[2] = f_src_b[2];
f_dst_b[3] = f_src_b[3];

printf("%g\n", f_dst);
size_t / sizeof
// The size_t type is defined in terms of the standard C types. It is the type
// returned by the sizeof operator. Typically, it is unsigned int, but an
// implementation can choose another type. 

// sizeof is not an function but a keyword, parenthesis are cast
size_t double_siz = sizeof (double);

// get size for 1000 double numbers
size_t double_siz = sizeof (double) * 1000;

// get size for string
char *str = "hello world";
size_t string_siz = strlen(str) + 1; // +1 for null terminator '\0'
malloc
#include <stdlib.h>
void *malloc(size_t size);

// you can allocate memory on anything pointer 
void *chunk = malloc(1); //allocates 1 byte (char), argument is size_t type

// sizeof, sizeof is not a function, parenthesis are for cast.
double *chunk = malloc(sizeof (double));

// other common way is pointer deref
double *chunk = malloc(sizeof (*chunk)); // don't forget *, or you will allocate only size of pointer 

// after malloc check for memory error
char *str = malloc(256);
if (str == NULL){
    fprintf(stderr, "Couldn't allocate memory.\n");
    exit(EXIT_FAILURE);
}
// when done you should free memory back to system: 
free(str);
// after free() set pointer to NULL. Security reasons 
str = NULL;
calloc
// same as malloc but usefull for allocating arrays 
int *heap_array = calloc(100, sizeof(int));
// arg0 is amount, arg1 is size_t
realloc
// resize allocated chunk 
void *realloc(void *ptr, size_t size);

int *chunky = malloc(sizeof (int) * 200);
int *resized = NULL;

resized = realloc(chunky, sizeof (int) * 400);
if (!resized){
    fprintf(stderr, "Memory error!\n");
    exit(EXIT_FAILURE);
}

// cleaner version that use function:
void *reallocate(void *arg_data, size_t arg_size)
{
    void *return_value;
    return_value = realloc(arg_data, arg_size); 
    if (!return_value){
        fprintf(stderr, "Memory error!\n");
        exit(EXIT_FAILURE);
    }  
    return return_value;
}
alloca (unix)
// alloca() allocates memory chunk on stack memory
// memory gets automatically freed at function end
// DON'T USE free() on alloca chunk
#include <alloca.h>
void *alloca(size_t size);
free
int *chunky = malloc(sizeof (int) * 200);
// when done you should free memory back to system: 
free(chunky);
// after free() set pointer to NULL. Security reasons 
chunky = NULL;
// you can reuse pointer for another allocation 
chunky = malloc(sizeof (int) * 50);
memset
#include <string.h>
// sets memory range to int number 
// void *memset(void *s, int c, size_t n); 
int *list = malloc(sizeof (int) * 200);
memset(list, 0, sizeof (int) * 200);
memcpy
#include <string.h>
// copies memory range to other memory range 
// void *memcpy(void *dest, const void *src, size_t n);
double d[] = {34.31, 12.32};
double *d_p = calloc(2, sizeof (double));
memcpy(d_p, d, sizeof (double) * 2);
printf("%g\n", d_p[1]);
get size of inner struct
typedef struct Element{
    unsigned int size;
    struct color{
        int red;
        int green;
        int blue;
    } color[1];
} Element;

int main(){
    Element *elem = NULL;
    printf("Size of inner struct 'color': %d\n", sizeof (elem->color) );
}

struct

declare struct
 // DataGroup is template tag
struct DataGroup{
    char key[32];
    double value;
}; // DON'T FORGET ';'

// declare/create 'images' structure using DataGroup template
struct DataGroup images;

// or multiple
struct DataGroup images, sounds, *vectors;

// combine declaration and variable (Images)
struct DataGroup{
    char key[32];
    double value;
}Images;

// without tag, structure can't be used as template 
struct{
    char key[32];
    double value;
}Images;
init struct
// nullify 
struct DataGroup Images = {0};
 
// old school 
struct DataGroup Images = {
    "Here be key", //char *key; 
    32.422         //double value; 
};

// c99 designated initializers 
struct DataGroup Images = {
    .key = "Here be key",
    .value = 32.422        
};

// or combination 
struct Elem {
    int a;
    int b;
} elem = {
    .a = 1,
    .b = 2,
};
function argument/return struct
// basic 
struct Element elem;
func(&elem);

// pass struct as argument (compound literal)
struct_func((struct DataGroup) {"title", 2.34 });

// pass struct ptr as argument
struct_func(&(struct DataGroup) {"title", 2.34 });
 
// structs are returned as copy of data
struct DataGroup return_images()
{
    return (struct DataGroup) {"title", 2.34 }; //compound literal
}

struct in struct
struct {
    struct {
        int day;
        int month;
        int year;
    } dob;
    int a;
    int b;
} Element;
opaque type
typedef struct String{
    size_t length;
    char string[1]; 
}String;

String *string = newString("io ox");
SEE: ABSTRACT DATATYPES 
union in struct
enum{
    NUMBER = 1,
    STRING = 2,
};
 
struct Data {
    int type; //enum
    union{        
        double dbl;
        char *str;
    };    
};
// int type; is header which holds info on which type union hold 
struct Data number;
number.type = NUMBER;
number.dbl = 2343.2234;

// so if (number.type == NUMBER) you know that it holds number
linked structures
struct Data {
    double data;
    struct Data *next;
};

//create two structs in heap
struct Data *dat00 = malloc(sizeof (*dat00));
dat->data = 23.123;
dat->next = NULL;

struct Data *dat01 = malloc(sizeof (*dat01));
dat->data = 3.4;
dat->next = NULL;

//link one to another
dat00->next = dat01;

//access 01 data from 00
printf("%g\n", dat00->next->data);
array of structures
//create array of 256 items form Data template
struct Data dat[256] = {0};

//variable only
struct{
    char *key;
    double value;  
} hash[1024];
hash[0].key = "window size"; 
hash[0].value = 100; 

printf("%g\n", hash[0].value);

////////////////////////////////////////////////////

typedef struct Argument{
    char *key;
    int (*action)(void); //return err code, pass in w/e 
}Argument;

int dummy(){ printf("%s\n","wakka!");}

Argument argmnt[] = {
    {.key="fg", .action=dummy },
    {.key="bg", .action=dummy },
    {.key="close", .action=dummy },
    {.key=NULL, .action=NULL } //terminator
};
copy stack to heap
//<string.h> for memcpy
typedef struct Element{
    char *key;
    double value;  
}Element;

//create struct on stack
Element stack_elem;
stack_elem.key = "main() only";
stack_elem.value = 23.122;

//copy to heap
Element *heap_elem = malloc(sizeof (Element));
memcpy(heap_elem, &stack_elem, sizeof (Element));
short stack data grouping
struct {int a; double b;} list01 = {1221, 13.31};
passing anonymous struct to function
int func(void *data){
    struct {int c; double d;} *p = data;
    printf("%g\n", p->d);
}

int main(){
    struct {int a; double b;} list01 = {1221, 13.13};
    func(&list01);    
    printf("%g\n", list01.b);
}

Linked list

basic structure
//linked list
typedef struct Node{
	struct Node *next;
	void *value;
	char key[1];
}Node;

//double-linked list
typedef struct Node{
	struct Node *next;
	struct Node *prev;
	void *value;
	char key[1];
}Node;

//node header
typedef struct Header{
	struct Node *head;
	unsigned int length;
	char header_name[1];
}Header;
free list
void freeNode(Node **arg_node){
    if (!(*arg_node)->next){
        free(*arg_node);
        *arg_node = NULL;
    }
    else {
        Node *node = *arg_node;
        Node *freenode = NULL;
        while (!node){
            freenode = node;
            node = node->next;
            free(freenode);
            freenode = NULL;
        }
    }
}

Modules and naming

module structure
[module.c] //module functions
[module.h] //external interface
[module.private] //private header for datatypes...

[module.private] <-- [module.c] --> [module.h] --> [main.c]
naming
Module name example:  topaz 
Datatype name: Topaz
Function name: (note 'item' and 'Append' order)
tpz_create();
tpz_itemAppend();
tpz_itemRemove();
tpz_destroy();
Macro name: TPZ_MACRO_NAME
function argument name: arg_handle
hidding
MAKING FUNCTIONS LOCAL TO FILE
[module.c] static int privateFunction(){...};
 
DATATYPE HIDDING
[module.private]: typedef struct Topaz{int data; ...}Topaz;
[module.h]: typedef void Topaz;
header defined only once
#ifndef UTIL_H
#define UTIL_H
  your header code goes here...
#endif

//enable module features
#ifdef MY_MOD_ENABLE_FEATURE
 #define SIZE_FEATURE 1212
#endif

//then compile your code with -D:
gcc proggy.c -DMY_MOD_ENABLE_FEATURE

Const

examples
int const a;        //a constant integer
int const *b;       //a (variable) pointer to a constant integer

int *const c;       // a constant pointer to a (variable) integer
int *const *d;      // a pointer to a constant pointer to an integer
int const **e;      // a pointer to a pointer to a constant integer
int const *const *f;    // a pointer to a constant pointer to a constant integer

//ptr

const float *pf;    // pf points to a constant float value 
float *const pt;    // pt is a const pointer 

Comments

examples
// use c++ comments in code so that you can encapsulate large parts of code by c's /* */ 
/*
    int a = 0;
    uint32_t b = 0x20; //comment
*/

/****************************************************************************\
                                SECTION
\****************************************************************************/

/* --------------- Minor Section Marker --------------- */

/********************************************************
* This is a boxed comment. the box draws attention      *
* to it. This type of comment is used for programs,     *
* module and function headings.                         *
********************************************************/

/*
**  Yes, this would be almight one-liner comment.
*/

/*
**  Yes, this would be almight one-liner comment.
**  And, I got another one, (the line that is) bellow. 
*/

/*--------------------*\
 * Another box style  *
\*--------------------*/

/*---------------*
| Section Header |
*----------------*/

stdarg

primjer
#include <stdarg.h>
#include <stdio.h>

double sum(int arg_length, ...)
{
    double total = 0;
    va_list arg_list;       // declare object to hold arguments
    va_start(arg_list, arg_length); // initialize arg_list to argument list
    
    int i;
    for (i = 0; i < arg_length; i++)
        total += va_arg(arg_list, double);  // access each item in argument list
        
    va_end(arg_list);       //clean up
    return total;
}

int main()
{
    double number_sum;

    number_sum = sum(3, 1.1, 2.5, 13.3);
    printf("sum numbers: %g\n", number_sum);
}

String

string types
//read-only stack string, this should be written as 'const char *string' 
char *string = "I'm a string in stack.";

//read-write stack string 
char str[7] = "String"; /* add one extra spot for '\0' terminator */
char str[7] = {'S', 't', 'r', 'i', 'n', 'g', '\0'};
char str[] = "String";

//read-write heap string 
char str[] = "String";
char *heapstr = malloc(strlen(str) + 1); //+1 for '\0'
memcpy(heapstr, str, strlen(str));
heapstr[strlen(str)] = '\0';
array of strings (string pointers)
void mod_str(char ***return_str, char *arg_str1, char *arg_str2)
{ 
    *return_str = malloc( (sizeof (char**)) *2);
    (*return_str)[0] = arg_str1;
    (*return_str)[1] = arg_str2;     
    printf("%s\n", (*return_str)[0] ); 
}
 
int main()
{
    char *s1 = "alpha";
    char *s2 = "beta";
    char **work_str = NULL;     
    mod_str(&work_str, s1, s2);
    printf("w: %s\n", work_str[1] );
}
pass array of strings to function
void parse_file(char **pattern)
{
    printf("%s\n", pattern[1]);
}
 
char *pattern[] = {"/*", "*/", "//", "\n"};
parse_file(pattern);
struct container
typedef struct String{
    char *last_item;
    size_t length;
    char data[1]; //null terminator / string will just use memory space after
}String;

String *String_new(char *arg_string)
{
    size_t string_size = strlen(arg_string);
    String *new = malloc(sizof(String) + string_size);
    new->length = string_size;
    memcpy(new, arg_string, string_size);
    new[string_size] = 0;
    return new;
}
string list
const char *mytal[] = { /* array of 5 strings */
    "Adding numbers swiftly",
    "Multiplying accurately", "Stashing data",
    "Following instructions to the letter",
    "Understanding the C language"
};
heap string
char *heapstrm(char *s){
    size_t len = strlen(s);
    size_t i = 0;
    char *r = malloc(len+1);
    
    memcpy(r, s, len);   
    r[len] = '\0'; // NULL at end !!!!
    
    return r;
}

char *heapstr(char *s){
    size_t len = strlen(s);
    size_t i = 0;
    char *r = malloc(len+1);
        
    for (; i<len; i++){
        r[i] = s[i];       
    }   
    
    r[len] = '\0';
    
    return r;
}

////////////////////

char *s = heapstr("abcdefgh");

/*    
[0] a
[1] b
[2] c
[3] d
[4] e
[5] f
[6] g
[7] h
[8] '\0' - malloc(len+1); ie 8+1
*/

GDB – debugger

compile for gdb use
gcc -g -O0 prg.c
usage
// clean up
// enter repeats last command
gdb ./a.out
type:
start
list 10 lines of source (enter with list 10 more):
list 
print variable:
p in_prog_var 
step through whole program:
s
move to next line only in main(), not sub-routines:
n
    
// examine 
low level print (address: raw bytes), hit x again will examine at next addr+4:
x in_prog_var
lowlevel print singlebyte:
x/b in_prog_var
10 bytes in order
x/10b in_prog_var   
examine bytes at address:
x/b 0x7fffffffe404

// watch 
watch variable and report when it changes
watch in_prog_var
to get report when variable gets reed use:
rwatch in_prog_var
continue till hit watch | rwatch
cont 
see all watchpoints  
info watch

re-starting exe clears watchpoints    

// breakpoints 
to create breakpoint use, number is line number:
break 13 
continue till hit break (runs and stops at line 13):
cont 
see all breakpoints  
info break 
delete breakpoint
dele 13 

// callframe 
to see callframe use backtrace cmd:
bt 
to check frames (context/scope):
frame 0 

// set variable 
set var in_prog_var=23 

// quit 
q 
without debug symbols (-g)
// without debug symbols (regular exes)
gdb ./a.out
examine 20 instructions starting at the program counter:
x/20i $pc 
ie.
<main+9> 9 bytes from beginning of prog

String

find substring, strstr()
#include <string.h>
char *strstr(const char *haystack, const char *needle);

//The strstr() function finds the first occurrence of the substring needle
//in the string haystack.
//Function returns a pointer to the beginning of the located substring,
//or NULL if the substring is not found.
//nonstandard strcasestr() is same but ignores case
find byte: memchr(), memrchr(), rawmemchr(), memmem()
#include <string.h>
void *memchr(const void *s, int c, size_t n);
void *memrchr(const void *s, int c, size_t n);
void *rawmemchr(const void *s, int c);

The  memchr()  function  scans  the  initial n bytes of the memory area
pointed to by s for the first instance of c.  Both c and the  bytes  of
the memory area pointed to by s are interpreted as unsigned char.

The  memrchr()  function  is like the memchr() function, except that it
searches backward from the end of the n bytes pointed to by  s  instead
of forward from the beginning.

The  rawmemchr() function is similar to memchr(): it assumes (i.e., the
programmer knows for certain) that an instance of c lies  somewhere  in
the  memory  area starting at the location pointed to by s, and so per‐
forms an optimized search for c (i.e., no use of a  count  argument  to
limit  the range of the search).  If an instance of c is not found, the
results are unpredictable.

//to look for group of bytes use:
void *memmem(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen);
ctype.h
#include <ctype.h>
ialnum(c)  Returns a non-zero if c is alphabetic or numeric
isalpha(c) Returns a non-zero if c is alphabetic
scntrl(c)  Returns a non-zero if c is a control character
isdigit(c) Returns a non-zero if c is a digit, 0 – 9
isgraph(c) Returns a non-zero if c is a non-blank but printing character
islower(c) Returns a non-zero if c is a lowercase alphabetic character, i.e., a – z
isprint(c) Returns a non-zero if c is printable, non-blanks and white space included
ispunct(c) Returns a non-zero if c is a printable character, but not alpha, numeric, or blank
isspace(c) Returns a non-zero for blanks and these escape sequences: ‘\f’, ‘\n’, ‘\r’, ‘\t’, and ‘\v’
isupper(c) Returns a non-zero if c is a capital letter, i.e., A – Z
isxdigit(c) Returns a non-zero if c is a hexadecimal character: 0 – 9, a – f, or A – F
tolower(c) Returns the lowercase version if c is a capital letter; otherwise returns c
toupper(c) Returns the capital letter version if c is a lowercase character; otherwise returns c
strtol, string hex to long, with base
#include <stdlib.h>
long int strtol(const char *nptr, char **endptr, int base);

char *b = "11110000";
printf("%d\n", strtol(b, NULL, 2)); // 240

char *h = "fefefe";
printf("%d\n", strtol(h, NULL, 16)); // 16711422
int to hex string
int a = 16711422;
char hex[6] = {0};
snprintf(hex, 7, "%x", a);
printf("%s\n", hex); //fefefe
hex2rgb
//_array is ptr to int rgb[3], _hex is "fefefe" color string
int das_hex2rgb(unsigned int *_array, char *_hex){
    if (strlen(_hex) !=6)
        return -1;

    //is hex char?
    for (int i=0; i<strlen(_hex); i++){
        if (!( (!(_hex[i]<48) && !(_hex[i]>57)) || (!(_hex[i]<65) && !(_hex[i]>70)) || (!(_hex[i]<97) && !(_hex[i]>102)) )){
            printf("%s\n","Not hex!");
            return -1;
        }
    }
    
    char r[3] = {0}, g[3] = {0}, b[3] = {0};
    r[0] = _hex[0];
    r[1] = _hex[1];
    g[0] = _hex[2];
    g[1] = _hex[3];
    b[0] = _hex[4];
    b[1] = _hex[5];

    printf("%s\n", g);

    _array[0] = strtol(r, NULL, 16);
    _array[1] = strtol(g, NULL, 16);
    _array[2] = strtol(b, NULL, 16);

    return 0;
}

Assert

about
void assert(int exprs);

If exprs evaluates to nonzero (or true), the macro does nothing. If it
evaluates to zero (false), assert() displays expression, the line number for
the assert() statement, and the name of the file containing the statement.
Then it calls abort().
example
#include <stdio.h>
#include <assert.h>

int main()
{
    int a = 3;
    //abort() if expression is false, so:
    assert(a<0); //a is less then 0 => false => abort&report
}
NDEBUG
Defining the macro identifier NDEBUG before including the assert.h header
file deactivates the assert() macro.

#define NDEBUG
#include <assert.h>

or:
$ gcc proggy.c -DNDEBUG