Customização de tipos

Até agora você só viu estruturas padrões do próprio C, e como usá-las, mas agora você vai aprender a criar as suas próprias...

Structs e unions

struct é o tipo de dado que cria uma estrutura própria, e é muito útil para criar “objetos” ou seja, criar variáveis com várias características...

E a galera que já conhece um pouco mais deve estar se perguntando “Mas o C é orientado a objetos?” e desde já, não, o máximo que você pode fazer no C é criar um tipo com espaços para armazenar dados, mas não é possível criar objetos ou classes.


struct pessoa {
   char * nome;
   int idade;
   char sexo;
   float peso;
   float altura;
}

Como podem ver no exemplo acima, nós criamos uma estrutura pessoa que pode receber um nome, uma idade, um peso, um sexo e uma altura, assim melhorando e muito nosso armazenamento de dados, “Mas como eu posso acessá-los?”, muito simples:

struct pessoa joao;        // aqui nós criamos uma pessoa "joao".
joao.nome = "Joao";        // aqui nós atribuímos "Joao" ao nome da pessoa.

E como você pôde notar agora existe um tipo struct pessoa, “Mas, eu quero criar um tipo pessoa, é possível?”, sim, é, e para isso você vai usar o typedef, e ele serve para apelidar um tipo.

typedef int MyInt;

MyInt inteiro;

Mas como nós queremos usá-lo com a nossa struct, temos 3 formas de usar:

Criando o struct antes:

struct p { char * name };
typedef struct p pessoa;

Criando ao mesmo tempo:

typedef struct p { char * name } pessoa;

Criando ao mesmo tempo com uma struct anônima:

typedef struct { char * name } pessoa;

E o resultado das sentenças anteriores é:

pessoa joao;
joao.name = "Joao";

E para evitar erros de escopo, sempre declare structs fora do main.

Outra estrutura muito interessante é a union, ela é semelhante a struct, mas a union assume apenas uma variável... “Como assim?” ...observe:

// struct
{
   struct p {
      char * nome;
      int idade;
   };

   // Uso

   struct p joao;
   joao.nome = "Joao";
   joao.idade = 12;
}

// union
{
   union p {
      char * nome;
      int idade;
   };

   // Uso

   union p joao;
   joao.nome = "Joao";       // aqui você escolheu usar a variável nome
   puts(joao.idade);         /* aqui aqui será imprimido "Joao", já que
                                joao.idade está unido com joao.nome
                             */
    // Ou
    union p coisa;
    coisa.idade = 14;
    printf("%i\n", coisa.idade);
}

Um macete legal na atribuíção de uma struct é usar um array para isso, é só colocar os valores na ordem de declaração da struct, “Quê?”:

typedef struct {
    char * nome;
    int idade;
    float peso;
    float altura;
} pessoa;

//                      .nome, .idade, .peso, .altura
pessoa joao = (pessoa){"joao",     13,  40.3,    1.60};

Ou caso você não queira colocar na ordem é só específicar o atributo:

pessoa maria = (pessoa){
    .altura = 1.5
    .idade = 12,
    .nome = "maria",
    .peso = 39.4,
};

E o mesmo vale para arrays de struct:

pessoa * pessoas = (pessoa []){
    (pessoa){ "vanderlei", 25, 90, 1.80 },
    joao,
    (pessoa){
        .peso = 70,
        .altura = 1.90,
        .idade = 42,
        .nome = "rita"
    },
    maria
};

Enum

O enum vem enumeração e nesse você deseje designar valores constantes para as suas estruturas.

typedef enum {
   true = 1,
   false = 0,
} bool;

bool falso = false;

Só pode colocar inteiros em enums.

E acima acabamos de criar o tipo booleano no C.

Como só é possível colocar inteiros em enums, e por isso existe um macete legal para atribuir esses números:

typedef enum {

   zero = 0,        // zero é 0
   um,              // um é zero + 1
   dois,            // dois é um + 1
   tres,            // tres é dois + 1

   sete = 7,        // sete é 7
   oito,            // oito é sete + 1
   nove,            // nove é oito + 1

   quatro = 4,      // quatro é 4
   cinco,           // cinco é quatro + 1
   seis             // seis é seis + 1

} por_extenso;
por_extenso numero = dois;

printf("%i\n", numero)
printf("%i\n", dois)

Saída:

2
2