summaryrefslogtreecommitdiffhomepage
path: root/pt-br/c-pt.html.markdown
blob: 9575007a566e8f73900566d07a72a1244750ff35 (plain)
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
---
language: C
filename: learnc-pt.c
contributors:
    - ["Adam Bard", "http://adambard.com/"]
    - ["Árpád Goretity", "http://twitter.com/H2CO3_iOS"]
translators:
    - ["João Farias", "https://github.com/JoaoGFarias"]
    - ["Elton Viana", "https://github.com/eltonvs"]
    - ["Cássio Böck", "https://github.com/cassiobsilva"]
    - ["Heitor P. de Bittencourt", "https://github.com/heitorPB/"]
lang: pt-br
---

Ah, C. Ainda é **a** linguagem de computação de alta performance.

C é a linguagem de mais baixo nível que a maioria dos programadores
utilizarão, e isso dá a ela uma grande velocidade bruta. Apenas fique
atento se este manual de gerenciamento de memória e C vai te levar
tão longe quanto precisa.

```c
// Comentários de uma linha iniciam-se com // - apenas disponível a partir do C99

/*
Comentários de múltiplas linhas se parecem com este.
Funcionam no C89 também.
*/

// Constantes: #define <palavra-chave>
#define DAY_IN_YEAR 365

//enumerações também são modos de definir constantes.
enum day {DOM = 1, SEG, TER, QUA, QUI, SEX, SAB};
// SEG recebe 2 automaticamente, TER recebe 3, etc.

// Cabeçalhos são inclusos com #include
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

// (Nomes dos arquivos entre <colchetes> são cabeçalhos para bibliotecas padrão de C.)
// Para cabeçalhos próprios, use aspas ao invés de colchetes:
#include "minha_biblioteca.h"

// Declare assinaturas das funções no início do arquivo .h ou no topo
// do seu arquivo .c.
void funcao_1(char c);
int funcao_2(void);

// Deve-se declarar um 'protótipo de função' antes do main() quando as ocorrências
// dessas funções estão após sua função main()
int soma_dois_ints(int x1, int x2); // protótipo de função

// O ponto de entrada do teu programa é uma função
// chamada main, com tipo de retorno inteiro
int main() {
	// Usa-se printf para escrever na tela,
	// para "saída formatada"
	// %d é um inteiro, \n é uma nova linha
    printf("%d\n", 0); // => Imprime 0
	// Todos as declarações devem acabar com
	// ponto e vírgula

    ///////////////////////////////////////
    // Tipos
    ///////////////////////////////////////

    // ints normalmente tem 4 bytes
    int x_int = 0;

    // shorts normalmente tem 2 bytes
    short x_short = 0;

    // chars sempre tem um byte
    char x_char = 0;
    char y_char = 'y'; // Literais de caracter são cercados por '

    // longs tem entre 4 e 8 bytes; longs long tem garantia
    // de ter pelo menos 64 bits
    long x_long = 0;
    long long x_long_long = 0;

    // floats são normalmente números de ponto flutuante
	// com 32 bits
    float x_float = 0.0;

    // doubles são normalmente números de ponto flutuante
	// com 64 bits
    double x_double = 0.0;

    // Tipos inteiros podem ser sem sinal.
    unsigned short ux_short;
    unsigned int ux_int;
    unsigned long long ux_long_long;

	// caracteres dentro de aspas simples são inteiros
	// no conjunto de caracteres da máquina.
    '0' // => 48 na tabela ASCII.
    'A' // => 65 na tabela ASCII.

	// sizeof(T) devolve o tamanho de uma variável do tipo T em bytes
	// sizeof(obj) devolve o tamanho de uma expressão (variável, literal, etc.).
    printf("%zu\n", sizeof(int)); // => 4 (na maioria das máquinas com palavras de 4 bytes)

	// Se o argumento do operador `sizeof` é uma expressão, então seus argumentos
	// não são avaliados (exceto em VLAs (veja abaixo)).
	// O valor devolve, neste caso, é uma constante de tempo de compilação.
    int a = 1;
	// size_t é um inteiro sem sinal com pelo menos 2 bytes que representa
	// o tamanho de um objeto.
    size_t size = sizeof(a++); // a++ não é avaliada.
    printf("sizeof(a++) = %zu where a = %d\n", size, a);
    // imprime "sizeof(a++) = 4 onde a = 1" (quando em uma arquitetura de 32 bits)

	// Arrays precisam ser inicializados com um tamanho concreto
    char meu_char_array[20]; // Este array ocupa 1 * 20 = 20 bytes
    int meu_int_array[20]; // Este array ocupa 4 * 20 = 80 bytes
                           // (assumindo palavras de 4 bytes)

	// Você pode inicializar um array com 0 desta forma:
    char meu_array[20] = {0};

	// Indexar um array é semelhante a outras linguagens
	// Melhor dizendo, outras linguagens são semelhantes a C
    meu_array[0]; // => 0

	// Array são mutáveis; são apenas memória!
    meu_array[1] = 2;
    printf("%d\n", meu_array[1]); // => 2

	// No C99 (e como uma features opcional em C11), arrays de tamanho variável
	// VLA (do inglês), podem ser declarados também. O tamanho destes arrays
	// não precisam ser uma constante de tempo de compilação:
    printf("Entre o tamanho do array: "); // Pergunta ao usuário pelo tamanho
    char buf[0x100];
    fgets(buf, sizeof buf, stdin);

    // strtoul transforma a string em um inteiro sem sinal
    size_t size = strtoul(buf, NULL, 10);
    int var_length_array[size]; // declara o VLA
    printf("sizeof array = %zu\n", sizeof var_length_array);

    // Uma possível saída para esse programa seria:
    // > Entre o tamanho do array: 10
    // > sizeof array = 40

	// String são apenas arrays de caracteres terminados por um
	// byte nulo (0x00), representado em string pelo caracter especial '\0'.
	// (Não precisamos incluir o byte nulo em literais de string; o compilador
	// o insere ao final do array para nós.)
    char uma_string[20] = "Isto é uma string";
	// Observe que 'é' não está na tabela ASCII
	// A string vai ser salva, mas a saída vai ser estranha
	// Porém, comentários podem conter acentos
    printf("%s\n", uma_string); // %s formata a string

    printf("%d\n", uma_string[17]); // => 0
    // i.e., byte #18 é 0 (assim como o 19°, 20°, 21°...)

	// Se temos caracteres entre aspas simples, temos um caracter literal.
	// Seu tipo é `int`, *não* `char` (por razões históricas).
    int cha = 'a'; // ok
    char chb = 'a'; // ok também (conversão implícita de int para char)

	// Arrays multi-dimensionais:
    int multi_array[2][5] = {
        {1, 2, 3, 4, 5},
        {6, 7, 8, 9, 0}
    };
    // Acesso a elementos:
    int array_int = multi_array[0][2]; // => 3

    ///////////////////////////////////////
    // Operadores
    ///////////////////////////////////////

    // Atalho para multiplas declarações:
    int i1 = 1, i2 = 2;
    float f1 = 1.0, f2 = 2.0;

    int a, b, c;
    a = b = c = 0;

    // Aritmética é óbvia
    i1 + i2; // => 3
    i2 - i1; // => 1
    i2 * i1; // => 2
    i1 / i2; // => 0 (0.5, porém, é truncado para 0)

    f1 / f2; // => 0.5, mais ou menos epsilon
    // Números e cálculos de ponto flutuante não são exatos

    // Módulo também existe
    11 % 3; // => 2

	// Operadores de comparação provavelmente são familiares,
	// porém não há tipo booleano em C. Usa-se ints no lugar.
	// (Ou _Bool or bool em C99.)
	// 0 é falso e qualquer outra coisa é verdadeiro
	// (Os operadores de comparação devolvem 0 ou 1.)
    // Comparison operators are probably familiar, but
    3 == 2; // => 0 (falso)
    3 != 2; // => 1 (verdadeiro)
    3 > 2; // => 1
    3 < 2; // => 0
    2 <= 2; // => 1
    2 >= 2; // => 1

	// C não é Python - comparações não se encadeiam.
    int a = 1;
    // Errado:
    int entre_0_e_2 = 0 < a < 2;
    // Correto:
    int entre_0_e_2 = 0 < a && a < 2;

    // Lógica funciona sobre ints
    !3; // => 0 (Não lógico)
    !0; // => 1
    1 && 1; // => 1 (E lógico)
    0 && 1; // => 0
    0 || 1; // => 1 (Ou lógico)
    0 || 0; // => 0

    //Expressão condicional ternária ( ? : )
    int a = 5;
    int b = 10;
    int z;
    z = (a > b) ? a : b; // => 10 "se a > b retorne a, senão retorne b."

    //Operadores de incremento e decremento:
    char *s = "iLoveC";
    int j = 0;
    s[j++]; // => "i". Retorna o j-ésimo item de s E DEPOIS incrementa o valor de j.
    j = 0;
    s[++j]; // => "L". Incrementa o valor de j. E DEPOIS retorna o j-ésimo item de s.
    // o mesmo com j-- e --j

    // Operadores bit a bit!
    ~0x0F; // => 0xF0 (negação bit a bit, "complemento de 1")
    0x0F & 0xF0; // => 0x00 (bit a bit E)
    0x0F | 0xF0; // => 0xFF (bit a bit OU)
    0x04 ^ 0x0F; // => 0x0B (bit a bit OU EXCLUSIVO)
    0x01 << 1; // => 0x02 (bit a bit shift para esquerda (por 1))
    0x02 >> 1; // => 0x01 (bit a bit shift para direita (por 1))

	// Cuidado quando fizer shift em inteiro com sinal - o seguinte é indefinido:
	// - Fazer shift sobre um bit de sinal de um inteiro com sinal (int a = 1 << 32)
	// - Fazer shift a esquerda sobre um número negativo (int a = -1 << 2)
	// - Fazer shift maior que a largura do tipo de LHS:
	//   int a = 1 << 32; // Indefinido se int é de tamanho 32 bits

    ///////////////////////////////////////
    // Estruturas de Controle
    ///////////////////////////////////////

    if (0) {
      printf("Nunca rodará\n");
    } else if (0) {
      printf("Também nunca rodará\n");
    } else {
      printf("Eu serei impresso\n");
    }

    // Loops while existem
    int ii = 0;
    while (ii < 10) { //QUALQUER valor diferente de 0 é verdadeiro
        printf("%d, ", ii++); // ii++ incrementa o valor de ii APÓS usá-lo
    } // => imprime "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "

    printf("\n");

    int kk = 0;
    do {
        printf("%d, ", kk);
    } while (++kk < 10); // ++kk incrementa o valor de kk ANTES de usá-lo
    // => imprime "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "

    printf("\n");

    // Loops for também
    int jj;
    for (jj=0; jj < 10; jj++) {
        printf("%d, ", jj);
    } // => imprime "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "

    printf("\n");

    // *****NOTAS*****:
	// Loops e Funções PRECISAM ter um corpo. Se nenhum corpo é necessário:
    int i;
    for (i = 0; i <= 5; i++) {
        ; // Use ponto e vírgula para agir como um corpo (declaração nula)
    }
    // Ou
    for (i = 0; i <= 5; i++);

	// Criando branchs com escolhas múltiplas: switch()
    switch (alguma_expressao_integral) {
    case 0: // labels precisam ser expressões integrais **constantes**
        faca_algo();
        break; // Sem break, o controle continua após a label
    case 1:
        faca_outra_coisa();
        break;
    default:
        // Se `alguma_expressao_integral` não coincidir com nenhuma label
        fputs("erro!\n", stderr);
        exit(-1);
        break;
    }


    ///////////////////////////////////////
    // Cast de tipos
    ///////////////////////////////////////

	// Todo valor em C tem um tipo, mas você pode fazer um cast de um valor em outro tipo
	// se você quiser (com algumas restrições).

    int x_hex = 0x01; // Você pode colocar valores hexadecimais em variáveis

	// Cast entre tipos tentará preservar seus valores numéricos
    printf("%d\n", x_hex); // => Imprime 1
    printf("%d\n", (short) x_hex); // => Imprime 1
    printf("%d\n", (char) x_hex); // => Imprime 1

	// Tipos irão ter overflow sem aviso
    printf("%d\n", (unsigned char) 257); // => 1 (Max char = 255 se char tem 8 bits)

	// Para determinar o valor máximo de um `char`, de um `signed char` e de
	// um `unisigned char`, respectivamente, use as macros CHAR_MAX, SCHAR_MAX
	// e UCHAR_MAX de <limits.h>

	// Tipos inteiros podem sofrer cast para pontos-flutuantes e vice-versa.
    printf("%f\n", (float)100); // %f formata um float
    printf("%lf\n", (double)100); // %lf formata um double
    printf("%d\n", (char)100.0);

    ///////////////////////////////////////
    // Ponteiros
    ///////////////////////////////////////

	// Um ponteiro é uma variável declarada para armazenar um endereço de memória.
	// Sua declaração irá também dizer o tipo de dados para o qual ela aponta. Você
	// Pode usar o endereço de memória de suas variáveis, então, brincar com eles.

    int x = 0;
    printf("%p\n", (void *)&x); // Use & para usar o endereço de uma variável
    // (%p formata um objeto ponteiro do tipo void *)
    // => Imprime algum endereço de memória;

	// Ponteiros começam com * na sua declaração
    int *px, nao_eh_um_ponteiro; // px é um ponteiro para um int
    px = &x; // armazena o endereço de x em px
    printf("%p\n", (void *)px); // => Imprime algum endereço de memória
    printf("%zu, %zu\n", sizeof(px), sizeof(nao_eh_um_ponteiro));
    // => Imprime "8, 4" em um sistema típico de 64 bits

	// Para pegar um valor no endereço apontado por um ponteiro,
	// coloque * na frente para de-referenciá-lo.
	// Nota: sim, é confuso usar '*' _tanto_ para declaração de ponteiro
	// como para de-referenciá-lo.
    printf("%d\n", *px); // => Imprime 0, o valor de x

	// Você também pode mudar o valor que o ponteiro está apontando.
	// Temos que cercar a de-referência entre parênteses, pois
	// ++ tem uma precedência maior que *.
    (*px)++; // Incrementa o valor que px está apontando por 1
    printf("%d\n", *px); // => Imprime 1
    printf("%d\n", x); // => Imprime 1

	// Arrays são uma boa maneira de alocar um bloco contínuo de memória
    int x_array[20]; // Declara um array de tamanho 20 (não pode-se mudar o tamanho
    int xx;
    for (xx = 0; xx < 20; xx++) {
        x_array[xx] = 20 - xx;
    } //Inicializa x_array com 20, 19, 18,... 2, 1

	// Declara um ponteiro do tipo int e inicialize ele para apontar para x_array
    int* x_ptr = x_array;
	// x_ptr agora aponta para o primeiro elemento do array (o inteiro 20).
	// Isto funciona porque arrays são apenas ponteiros para seus primeiros elementos.
	// Por exemplo, quando um array é passado para uma função ou é atribuído a um
	// ponteiro, ele transforma-se (convertido implicitamente) em um ponteiro.
	// Exceções: quando o array é o argumento de um operador `&` (endereço-de):
    int arr[10];
    int (*ptr_to_arr)[10] = &arr; // &arr não é do tipo `int *`!
                                  // É do tipo "ponteiro para array" (de `int`s).
    // ou quando o array é uma string literal usada para inicializar um array de char:
    char arr[] = "foobarbazquirk";
	// ou quando é um argumento dos operadores `sizeof` ou `alignof`:
    int arr[10];
    int *ptr = arr; // equivalente a int *ptr = &arr[0];
    printf("%zu, %zu\n", sizeof arr, sizeof ptr); // provavelmente imprime "40, 4" ou "40, 8"

	// Ponteiros podem ser incrementados ou decrementados baseado no seu tipo
	// (isto é chamado aritmética de ponteiros
    printf("%d\n", *(x_ptr + 1)); // => Imprime 19
    printf("%d\n", x_array[1]); // => Imprime 19

	// Você também pode alocar dinamicamente blocos de memória com a função
	// da biblioteca padrão malloc, a qual recebe um argumento do tipo size_t
	// representando o número de bytes a ser alocado (geralmente da heap, apesar de
	// isto poder não ser verdadeiro em, e.g., sistemas embarcados - o C padrão diz
	// nada sobre isso).
    int *my_ptr = malloc(sizeof(*my_ptr) * 20);
    for (xx = 0; xx < 20; xx++) {
        *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx
    } //Inicializa a memória com 20, 19, 18, 17... 2, 1 (como ints)

	// Dereferenciar memória que você não alocou cria
	// "resultados imprevisíveis" - o programa é dito ter um "comportamento indefinido"
    printf("%d\n", *(my_ptr + 21)); // => Imprime quem-sabe-o-que? Talvez até quebre o programa.

	// Quando se termina de usar um bloco de memória alocado, você pode liberá-lo,
	// ou ninguém mais será capaz de usá-lo até o fim da execução
	// (Isto chama-se "memory leak"):
    free(my_ptr);

	// Strings são arrays de char, mas elas geralmente são representadas
	// como um ponteiro para char (com o apontador para o primeiro elemento do array).
	// É boa prática usar `const char *' quando de-referenciando uma literal string,
	// dado que elas não deverão ser modificadas (i.e. "foo"[0] = 'a' é ILEGAL.)
    const char *my_str = "Esta é a minha literal string";
    printf("%c\n", *my_str); // => 'T'

	// Este não é o caso se a string for um array
	// (potencialmente inicializado com um literal string)
	// que reside em uma memória de escrita, como em:
    char foo[] = "foo";
    foo[0] = 'a'; // Isto é legal, foo agora contém "aoo"

    funcao_1();
} // fim da função main

///////////////////////////////////////
// Funções
///////////////////////////////////////

//Sintaxe de declaração de funções:
// <tipo de retorno> <nome da função>(<argumentos>)

int soma_dois_int(int x1, int x2)
{
    return x1 + x2; // Use return para retornar um valor
}

/*
Funções são chamadas por valor. Quando uma função é chamada, os argumentos passados
para a função são cópias dos argumento originais (a não ser arrays). Qualquer coisa
que você faz nos argumentos de uma função não alteram o valor do argumento original
onde a função foi chamada.

Use ponteiros se você precisa alterar os valores dos argumentos originais

Exemplo: reversão de string in-place
*/

// Uma função void não retorna valor algum
void str_reverse(char *str_in)
{
    char tmp;
    int ii = 0;
    size_t len = strlen(str_in); // `strlen()` é parte da biblioteca padrão C
    for (ii = 0; ii < len / 2; ii++) {
        tmp = str_in[ii];
        str_in[ii] = str_in[len - ii - 1]; // iiº char do final
        str_in[len - ii - 1] = tmp;
    }
}

/*
char c[] = "Isto é um teste.";
str_reverse(c);
printf("%s\n", c); // => ".etset mu é otsI"
*/

// Se estiver referenciando variáveis externas à função, use a palavra-chave extern.
int i = 0;
void testFunc() {
    extern int i; //i aqui agora está usando a variável externa
}

// Faça variáveis externas privadas para o código-fonte com static:
static int i = 0; // Outros arquivos usando testFunc() não podem acessar a variável i
void testFunc() {
    extern int i;
}
//**Você pode declarar funções como static para torná-las privadas**


///////////////////////////////////////
// Tipos definidos pelo usuário e structs
///////////////////////////////////////

// Typedefs podem ser usadas para criar apelidos para tipos
typedef int meu_tipo;
meu_tipo var_meu_tipo = 0;

// Structs são apenas coleções de dados, os membros são alocados sequencialmente,
// na ordem que são escritos:
struct retangulo {
    int altura;
    int largura;
};

// Geralmente não é verdade que
// sizeof(struct retangulo) == sizeof(int) + sizeof(int)
// devido ao potencial de preenchimento entre os membros da estrutura
// (isto é por razões de alinhamento). [1]

void funcao_1()
{
    struct retangulo meu_retan;

    // Acesse os membros da estrutura com .
    meu_retan.altura = 10;
    meu_retan.largura = 20;

	// Você pode declarar ponteiros para structs
    struct retangulo *meu_retan_ptr = &meu_retan;

	// Use de-referenciamento para setar os membros da
	// struct apontada...
    (*meu_retan_ptr).altura = 30;

	// ... ou ainda melhor: prefira usar o atalho -> para melhorar legibilidade
    meu_retan_ptr->largura = 10; // O mesmo que (*meu_retan_ptr).largura = 10;
}

//Você pode aplicar um typedef para uma struct por conveniência
typedef struct retangulo retan;

int area(retan r)
{
    return r.largura * r.altura;
}

// Se você tiver structs grandes, você pode passá-las "por ponteiro"
// para evitar cópia de toda a struct:
int area(const retan *r)
{
    return r->largura * r->altura;
}

///////////////////////////////////////
// Ponteiros para funções
///////////////////////////////////////
/*
Em tempo de execução, funções são localizadas em endereços de memória
conhecidos. Ponteiros para funções são como qualquer outro ponteiro
(apenas guardam endereços de memória), mas podem ser usados para invocar funções
diretamente e passá-las para por toda parte.
Entretanto, a sintaxe de definição por ser um pouco confusa.

Exemplo: use str_reverso através de um ponteiro
*/
void str_reverso_através_ponteiro(char *str_entrada) {
    // Define uma variável de ponteiro para função, nomeada f.
    void (*f)(char *); //Assinatura deve ser exatamente igual à função alvo.
    f = &str_reverso; //Atribue o endereço da função em si (determinado em tempo de execução.
    // f = str_reverso; Também funciona - função tornam-se ponteiros, assim como arrays
    (*f)(str_entrada); // Chamando a função através do ponteiro
    // f(str_entrada); // Esta é uma sintaxe alternativa, mas equivalente.
}

/*
Desde que as assinaturas das funções sejam compatíveis, você pode atribuir qualquer
função ao mesmo ponteiro. Ponteiros para funções são geralmente um typedef por
simplicidade e legibilidade, como segue:
*/

typedef void (*minha_função_type)(char *);

// Declarando o ponteiro:
// ...
// minha_função_type f;

//Caracteres especiais:
'\a' // Alerta (sino)
'\n' // Nova linha
'\t' // Tab (justifica texto a esquerda)
'\v' // Tab vertical
'\f' // Nova linha (formfeed)
'\r' // Retorno de carroça
'\b' // Backspace
'\0' // Caracter nulo. Geralmente colocado ao final de string em C.
     //   oi\n\0. \0 é usado por convenção para marcar o fim da string.
'\\' // Barra invertida
'\?' // Interrogação
'\'' // Aspas simples
'\"' // Aspas duplas
'\xhh' // Número hexadecimal. Exemplo: '\xb' = tab vertical
'\ooo' // Número octal. Exemplo: '\013' = tab vertical

// formatando impressão:
"%d"    // inteiro
"%3d"   // inteiro com pelo menos 3 dígitos (justifica texto a direita)
"%s"    // string
"%f"    // ponto-flutuante
"%ld"   // long
"%3.2f" // ponto-flutuante com pelo menos 3 dígitos a esquerda e 2 a direita
"%7.4s" // (também pode-se fazer com strings)
"%c"    // char
"%p"    // ponteiro
"%x"    // hexadecimal
"%o"    // octal
"%%"    // imprime %

///////////////////////////////////////
// Ordem de avaliação
///////////////////////////////////////

//-----------------------------------------------------------//
//        Operadores                       | Associatividade //
//-----------------------------------------------------------//
// () [] -> .                        | esquerda para direita //
// ! ~ ++ -- + = *(type)sizeof       | direita para esqureda //
// * / %                             | esquerda para direita //
// + -                               | esquerda para direita //
// << >>                             | esquerda para direita //
// < <= > >=                         | esquerda para direita //
// == !=                             | esquerda para direita //
// &                                 | esquerda para direita //
// ^                                 | esquerda para direita //
// |                                 | esquerda para direita //
// &&                                | esquerda para direita //
// ||                                | esquerda para direita //
// ?:                                | direita para esqureda //
// = += -= *= /= %= &= ^= |= <<= >>= | direita para esqureda //
// ,                                 | esquerda para direita //
//-----------------------------------------------------------//
```

## Leitura adicional

É recomendado ter uma cópia de [K&R, aka "The C Programming Language"](https://en.wikipedia.org/wiki/The_C_Programming_Language).
Este é *o* livro sobre C, escrito pelos criadores da linguagem. Mas cuidado - ele é antigo e contém alguns erros (bem,
ideias que não são mais consideradas boas) ou práticas ultrapassadas.

Se você tem uma pergunta, leia [compl.lang.c Frequently Asked Questions](http://c-faq.com).

É importante usar espaços e indentação adequadamente e ser consistente com seu estilo de código em geral.
Código legível é melhor que código 'esperto' e rápido. Para adotar um estilo de código bom e sensato, veja
[Linux kernel coding style](https://www.kernel.org/doc/Documentation/CodingStyle).

[1] [stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member](https://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member)