<aside>
Conhecimentos necessários:
Variáveis, entrada e saída de dados, estruturas condicionais e estruturas repetitivas
Dados, bases numéricas e memória
Estruturas de dados homogêneas: array (vetor/matriz)
</aside>
<aside>
Navegação
</aside>
Agora, que tal aprender sobre os dados complexos?
StructStruct é basicamente um bloco de várias variáveis de uma só vez. Com ele, podemos manter nosso código mais eficiente e organizado. Para definir uma struct, basta escrever isso fora e acima das funções:
struct NomeDaStruct {variáveis};
Após isso, declarar uma variável desse tipo:
struct NomeDaStruct NomeDaVariavel;
Aí, para acessar os elementos dentro dela, basta usar um ponto. Um exemplo:
#include <string.h>
struct Aluno {
char nome[100];
int idade;
char turma[5];
char nota;
};
int main() {
struct Aluno joao;
strcpy(joao.nome, "Joao");
joao.idade = 14;
strcpy(joao.turma, "8º D");
joao.nota = 'B';
return 0;
}
Ou, também, podemos colocar tudo de uma vez, parecido com vetores:
struct Aluno {
char nome[100];
int idade;
char turma[5];
char nota;
};
int main() {
struct Aluno joao = {"Joao", 14, "8º D", 'B'};
return 0;
}
Um ponto importante é: Como essa struct possui 4 membros dentro dela (4 tipos de variáveis), ela tem o mesmo peso, em bytes, dessas 4 variáveis juntas. No caso:
100 bytes (do char nome[100]) + 4 bytes (do int idade) + 5 bytes (do char turma[5]) + 1 byte (do char nota) = 110 bytes;
Toda struct possui o peso de todos os elementos somados.
Caso queira, pode criar vetores de structs ou usar structs dentro de structs (que é o que chamamos de aninhamento de structs). Por exemplo:
struct Pessoal {
char nome[100];
int idade;
char cpf[15]; //CPF sempre é em string. Nunca pode ser em int por causa que existem CPFs que começam com zeros
};
struct Data {
int dia;
int mes;
int ano;
};
struct Aluno {
struct Pessoal infoPessoal;
struct Data dataNascimento;
char turma[5];
int notas[3];
};
int main() {
struct Aluno alunos[10];
//primeiro aluno
strcpy(alunos[0].infoPessoal.nome, "Joaquim Pereira");
alunos[0].infoPessoal.idade = 17;
strcpy(alunos[0].infoPessoal.cpf, "123.456.789-09");
alunos[0].dataNascimento.dia = 1;
alunos[0].dataNascimento.mes = 1;
alunos[0].dataNascimento.ano = 2008;
strcpy(alunos[0].turma, "2ºEM");
alunos[0].notas[0] = 10;
alunos[0].notas[1] = 8;
alunos[0].notas[2] = 9;
//depois só fazer o mesmo para os outros alunos, ou dar a possibilidade para o cliente escrever as informações
return 0;
}
Também é possível criarmos funções com retornos das structs que nós mesmos criamos. Tudo funciona de maneira análoga. Um exemplo de uso:
#include <stdio.h>
#include <math.h>
struct Raizes {
float x1;
float x2;
};
struct Raizes FormulaQuadratica(float a, float b, float c){
float delta = b*b - 4*a*c;
float x1 = (-b + sqrt(delta))/(2*a);
float x2 = (-b - sqrt(delta))/(2*a);
struct Raizes solucoes = {x1, x2};
return solucoes;
}
int main() {
struct Raizes funcao = FormulaQuadratica(1, -5, 6); //raízes da função f(x) = x² -5x + 6
printf("As raizes sao: %f e %f.", funcao.x1, funcao.x2); //imprime "As raizes sao: 3.000000 e 2.000000."
return 0;
}
Também é possível fazer ponteiros para structs e usar como usamos um ponteiro normalmente. Por exemplo:
struct Aluno {
char nome[100];
int idade;
char turma[5];
char nota;
};
int main() {
struct Aluno joao;
struct Aluno *ponteiro = &joao;
(*ponteiro).idade = 27; //faz o papel de joao.idade = 27;
return 0;
}
Mas evitar ficar escrevendo assim, podemos também escrever usando ->. Tipo assim:
struct Aluno {
char nome[100];
int idade;
char turma[5];
char nota;
};
int main() {
struct Aluno joao;
struct Aluno *ponteiro = &joao;
ponteiro->idade = 27; // mesma coisa de (*ponteiro).idade = 27;
ponteiro->nota = 'C'; // mesma coisa de (*ponteiro).nota = 'C';
return 0;
}
UnionUnion é parecida com uma struct, mas no lugar de poder armazenar vários tipos de dados ao mesmo tempo, ela só pode armazenar um dado de cada vez. Por exemplo:
#include <stdio.h>
union Teste {
int inteiro;
char caractere;
float flutuante;
};
int main() {
union Teste var;
var.inteiro = 10; //só está armazenando o número 10
var.caractere = 'A'; //só está armazenando o caractere 'A'. O número 10 foi apagado
var.flutuante = 3.14; //só está armazenando o número decimal 3.14. O caractere 'A' foi apagado
printf("%f", var.flutuante); //mostrará "3.140000"
return 0;
}
Ela só armazena um único dado por vez por dividir o mesmo espaço na memória para todas as variáveis, assim, o peso dela, em bytes, é da maior variável dentro da union. Como nesse caso criamos uma union com um int, char e float dentro, ela pesará 4 bytes, pois a variável mais pesada dentro dela (int ou float, nesse caso) possui esse peso.
EnumUma enum é como se fosse um bloco de constantes. Dentro dela, escrevemos alguns nomes que funcionará como números (ou seja, basicamente uma constante mesmo). Um exemplo de uso:
enum DiaDaSemana {
DOMINGO,
SEGUNDA,
TERCA,
QUARTA,
QUINTA,
SEXTA,
SABADO
};
int main() {
enum DiaDaSemana dia1 = DOMINGO;
enum DiaDaSemana dia2 = SEGUNDA;
return 0;
}
É realmente como se estivéssemos criando constantes. Podemos também fazer uma atribuição em números para caso precisamos ter um melhor controle do valor de cada opção. Tipo assim:
enum DiaDaSemana {
DOMINGO = 10,
SEGUNDA = 20,
TERCA = 30,
QUARTA = 40,
QUINTA = 50,
SEXTA = 60,
SABADO = 70
};
int main() {
enum DiaDaSemana dia1 = DOMINGO;
enum DiaDaSemana dia2 = SEGUNDA;
return 0;
}
Caso não façamos essa atribuição, os valores padrões seguem uma contagem começando do zero.
TypedefÉ uma forma de apelidarmos essas estruturas para podermos criá-las mais facilmente depois. Para isso, basta escrever typedef antes de declarar uma estrutura e depois de fechar as chaves - mas antes do ponto e vírgula, escrever o apelido que deseja atribuir. Um exemplo:
#include <stdio.h>
typedef enum DiaDaSemana {
DOMINGO = 10,
SEGUNDA = 20,
TERCA = 30,
QUARTA = 40,
QUINTA = 50,
SEXTA = 60,
SABADO = 70
} DiaDaSemana;
typedef union Dado {
int i;
char c;
float f;
} Dado;
typedef struct Player {
int id;
int hp;
int pts;
} Player;
int main() {
Player jogador1, jogador2;
Dado vida_jogador1;
vida_jogador1.i = 100;
Dado vida_jogador2;
vida_jogador2 = vida_jogador1; //atribuindo um tipo Dado a outro tipo Dado. Como um guarda o int, automaticamente o outro guarda um int também
DiaDaSemana dia_atual = SEGUNDA;
printf("%d", vida_jogador2.i); //mostrará "100"
return 0;
}