Recursos interessantes do C
Tags: c, beginners, tip, ptbr
Published: 2020-07-11 00:26:40

A ***linguagem C*** ainda é relevante nesse década, passou e ainda passa pelo teste do tempo, e mostra-se importante no desenvolvimento de software. 

## **Porque aprender C**?
*C* tem interoperabilidade com todas ou quase todas linguagens atualmente. OK! mas o quê isso significa? Significa que você pode turbinar sua linguagem favorita usando C, chamando funções escritas em uma linguagem de sistema em linguagens de alto nível como Python ou usando Webassembly com JavaScript.

### Índice 
- **[Ponteiro](#ponteiros)**
  * [Ponteiro pra função](#Ponteiro pra função)
  * [Ponteiro pra função com ***struct***](#Ponteiro pra função com struct)
  * [Ponteiro pra ***void***](#Ponteiro pra void)
- **[Argumentos variáveis](#Argumentos variáveis)**


## **Recursos**

OBS: caso tenha interesse em executar os exemplos utilize um compilador online: **[GDB online Debugger](https://www.onlinegdb.com/)**

<a name="ponteiros"></a>


### **Ponteiros**

Trabalhar livremente com a memória pode ser considera uma arma bem poderosa do C, mas segundo o tio Ben: ***"Com grandes poderes vêm grandes responsabilidades"***, ou seja, você pode torna-se um vilão caso não use direito essa arma.

Por qual motivo eu considero ponteiros interessante? Penso que entender esse recurso pode  facilitar no entendimento de estrutura de dados, além de dá um *overview* ao desenvolvedor sobre como sua linguagem *xodó* fazem as mágicas que tanto ama.


Exemplo:
```c
#include <stdio.h>


/*
 Algoritmo imprimi valor da variável
 antes e depois da modificação
*/ 
 
void change_age(int *age);

int main()
{  
    int age = 16;
    printf("Before: %d\n", age);
    change_age(&age);
    printf("After: %d\n", age);
    return 0;
}

void change_age(int *age)
{
    *age = 21;
}
```

O seu sucesso na linguagem *C* vai depender se você vai ou não entender ponteiros.

[Ver mais](https://www.freecodecamp.org/news/the-c-beginners-handbook/#pointers)

<a name="Ponteiro pra função"></a>
### **Ponteiro pra função**

O exemplo abaixo é uma implementação de ***forEach*** e ***map*** , funções que linguagens como JavaScript e Python possuem e que facilitam a manipulação de coleções de dados. O exemplo tem como base a sintaxe do JavaScript.
```c
#include <stdio.h>
#include <stdlib.h>

/*
 O algoritmo analisa um array e retorna
 um novo array com os dados multiplicados
 por 2, e finaliza imprimindo os novos números.
*/

int *map(int ( *callback )(int value, int index, int *arr ), int *array, int length);
void forEach(void ( *callback )(int value, int index, int *arr ), int *array, int length);

int multiplyBy2(int value, int index, int *arr);
void show(int value, int index, int *arr);


int main()
{
    int numbers[] = {5, 4, 3, 2, 1};
    int length = (int)(sizeof(numbers) / sizeof(int));
    
    int *newArray = map(multiplyBy2, numbers, length);

    printf("Array | Map\n");
    forEach(show, newArray, length);

    free(newArray);

    return 0;
}


int *map(int ( *callback )(int value, int index, int *arr ), int *array, int length)
{
    int *newArray = (int*) calloc(length, sizeof(int));
    
    for(int i = 0; i < length; i++)
        newArray[i] = callback(array[i], i, array);
    
    return newArray;
}


void forEach(void ( *callback )(int value, int index, int *arr ), int *array, int length)
{
   for(int i = 0; i < length; i++)
        callback(array[i], i, array);
}


int multiplyBy2(int value, int index, int *arr)
{
    return value * 2;
}


void show(int value, int index, int *arr)
{
    printf("Valor: %d\n", value);
}
```
[Ver mais](https://www.studytonight.com/c/pointer-with-function-in-c.php#:~:text=A%20function%20pointer%20can%20point,providing%20the%20required%20argument%20values.)

<a name="Ponteiro pra função com struct"></a>
### **Ponteiro pra função com** ***struct***

```c
#include <stdio.h>

/*
 O algoritmo imprime com "intensidade"
 diferente a frase/palavra passada por
 parâmetro para a função com struct. 
*/

typedef struct {
    void (*shouting)(const char *message);
    void (*whispering)(const char *message);
} Speak;

Speak new();


int main()
{
    Speak speak = new();
    
    speak.shouting("Hi");
    speak.whispering("Hi");

    return 0;
}


void shouting(const char *message)
{
    printf("%s !!!!!!!!\n", message);
}


void whispering(const char *message)
{
    printf("... %s ...\n", message);    
}


Speak new()
{
    Speak speak;
    speak.shouting = shouting;
    speak.whispering = whispering;
    
    return speak;
}

```

Mas como isso funciona? Simples, se você imaginar que a função está em algum lugar da memória, seria sensato pressupor que poderíamos "apontar" para a função, semelhante como fazemos com variáveis. Interessante é que a chamada das funções através de ***struct*** se parece com a chamada de métodos de linguagens OOP.

<a name="Ponteiro pra void"></a>
### **Ponteiro pra** ***void*** 

Esse recurso do C pode ser considerando um **generics**, caso não entenda o conceito de **generics** [clique aqui](https://en.wikipedia.org/wiki/Concept_(generic_programming)).
```c
#include <stdio.h>

/*
 Algoritmo imprimi o tipo e valor 
 do endereço passado pra função noType 
*/

void noType(const char* format, void* element);

int main()
{
    int  valueInt = 10;
    char valueChr = 'A';
   
    noType("%d", (void*) &valueInt );
    noType("%c", (void*) &valueChr );
    
    return 0;
}


void noType(const char* format, void* element)
{
    
    while(*format != '\0')
    {
        if(*format == '%')
        {
            char type = *(++format);
            
            switch(type)
            {
                case 'd':{
                   
                    int value = *(int*) element;
                    printf("EH INT: %d\n", value); 
                    break;    
                }
            
                case 'c':{
                    char value = *(char*) element;
                    printf("EH CHAR: %c\n", value);
                    break;
                }
            }
        }
        
        ++format;
    } 
}

```

Observe que a assinatura da função ***noType*** que recebe um *const char* e void*, a constante de caractere ( string ) auxilia a função a saber o tipo do endereço passado no segundo parâmetro, algo semelhante ao ***printf*** e ***scanf***     

Ponteiro pra void é recurso bastante usado, exemplo, olhe as assinaturas de *malloc*, *calloc*, *realloc* e *free*:
```c
void* malloc( size_t size );
void* calloc( size_t num, size_t size );
void* realloc( void* ptr, size_t new_size );
void free( void* ptr );
```
[Ver mais](https://overiq.com/c-programming-101/void-pointers-in-c/)

<a name="Argumentos variáveis"></a>
## **Argumentos variáveis** 

Caso tenha escrito no mínimo um "hello world" em C, saiba que já utilizou esse recurso, não de forma direta, já que não implementou a função ***printf*** . Veja a assinatura da função ***printf***.
```c
int printf( const char *format, ... );
```
As reticências no final, simboliza que a função terá argumentos variáveis, ou seja, a função não sabe quantos parâmetros irá receber. 

A função ***printf*** no primeiro argumento recebe uma constante de caracteres (string) com a formatação pra que seja feito o [**casting**](https://developerinsider.co/type-casting-c-programming/) dos parâmetros, já que a função não conhece o tipo passado. [Acesse aqui e veja como implementar o seu próprio **printf**](http://www.firmcodes.com/write-printf-function-c/).

Temos que inserir a biblioteca ***"stdarg.h"*** e podemos iniciar com o exemplo abaixo.

```c
#include <stdio.h>
#include <stdarg.h>

/*
 O algoritmo soma os números passados
 por parâmetro, exceto o primeiro argumento, 
 pois indica a quantidade de números passados.
*/

int sum(int quantity, ...);


int main()
{
    printf("Sum of 2 + 3 + 6 = %i\n", sum(3, 2, 3, 6));
    return 0;
}


int sum(int quantity, ...)
{
    va_list numbers;
    int accumulator = 0;
    va_start(numbers, quantity);
    
    for(int i = 0; i < quantity; i++)
        accumulator += va_arg(numbers, int);
    
    va_end(numbers);
    
    return accumulator;
}
```
Esse exemplo não serve pra basicamente nada, mas vou mostrar como usei esse recurso para um finalidade que particularmente gostei. Em um [projetinho](https://github.com/dannRocha/snde) de teste, usei argumentos variaveis para controlar as sprites de exibição de um personagem em um "jogo".

```c
void run_animation(Actor *character, double framesperseconds, int select_animation, AnimationControl control);
```

Onde o parâmetro **AnimationControl control** é passada pra realizar o controle de exibição dos sprites usando a função abaixo.

Assinatura: [Documentação](https://github.com/dannRocha/snde#configura%C3%A7%C3%A3o-e-controle-da-anima%C3%A7%C3%A3o)
```c
AnimationControl animation_control(int number_sprites, ...);
```
[Ver mais](https://en.cppreference.com/w/c/variadic)

## Onde posso encontrar conteúdo sobre C?
Há bastante conteúdo pra aprender C/C++ na internet, uma simples "Googlada" e poderá encontrar matérias de estudo, mas fica a alguns links.

- [Learncpp](https://www.learncpp.com/)
- [Cppreference](https://en.cppreference.com/w/)
- [Freecodecamp](https://www.freecodecamp.org/news/the-c-beginners-handbook/)