Até o momento, vimos agrupamentos de dados de um mesmo tipo: vetores e matrizes.
Frequentemente, no entanto, precisamos agrupar um conjunto de dados relacionados, de tipos não necessariamente iguais.
Por exemplo:
Para isso, utilizamos registros (também conhecido como structs).
Um registro é novo tipo, definido pelo programador, formado por um ou mais campos, que podem ter tipos diferentes de dados.
Por esse motivo, registros também são chamados de variáveis compostas heterogêneas.
Vamos supor que vamos criar um registro para um determinado monstro, criando a tebela dos dados, será maios ou menos assim:
Podemos ver que a variável Nome é do tipo vetor de char (string); que Código, Level, Vida, Ataque e Defesa são do tipo int; que Taxa de Captura é do tipo float; e que Paralisado é do tipo booleano.
Todas essas variáveis são relacionadas, e estão agrupadas em um novo domínio.
Dizemos então que, da mesma maneira que existem os tipos inteiro, real, literal, etc, agora existe um novo tipo, Dados do Monstro, e também podemos criar variáveis desse novo tipo.
struct DadosMonstro { int cod; char nome[30]; float txcap; int level, vida, atq, def; int paralis; };
Com a struct criada, basta declarar um variável com um nome qualquer, do tipo struct DadosMonstro como por exemplo:
struct DadosMonstro pikachu; struct DadosMonstro chikorita;
Também é possível declarar um vetor deste tipo de dados.
struct DadosMonstro monstros[100];
int main(){ struct { int cod; char nome[30]; float txcap; int level, vida, atq, def; int paralis; } pikachu, chikorita; // cria as variáveis pikachu e chikorita conforme definição. }
typedef struct { int cod; char nome[30]; float txcap; int level, vida, atq, def; int paralis; } DadosMonstro; // associando "DadosMonstro" à definição da struct int main() { DadosMonstro pikachu, chikorita; // não precisa de struct antes }
Para acessar uma das variáveis internas do registro, ou seja, um de seus campos, fazemos da seguinte maneira :
DadosMonstro monstros[3]; for(i = 0; i < 3; i++){ printf("Digite o nome do monstro %d : ",i+1); scanf("%s", monstros[i].nome); printf("Digite o level do monstro %s : ",monstros[i].nome); scanf("%d", &monstros[i].level); } for(i = 0; i < 3; i++) printf("O monstro %s tem level : %d\n", monstros[i].nome, monstros[i].level);
Um ponteiro de registro é declarado da mesma maneira que um ponteiro para qualquer outra variável, usando o operador asterisco.
Também podemos acessar os conteúdos da struct desrreferenciando seu ponteiro.
DadosMonstro* pt = &pikachu; // ponteiro para pikachu int codPikachu = (*pt).code; // código do pikachu float txPikachu = (*pt).txcap;
Mas existe um operador especial para acessar variáveis internas de um ponteiro de struct, o operador seta (->).
DadosMonstro* pt = &pikachu; // ponteiro para pikachu int codPikachu = pt->code; // código do pikachu float txPikachu = pt->txcap;
Ponteiros para registros são bastante úteis para alterar um registro em uma função diferente. Existem também estruturas de dados que envolvem structs que precisam de um ponteiro para a próxima struct da sequência, como listas, árvores, etc. Essas structs serão vistas em detalhes na matéria de Estruturas de Dados.
Para mais exemplos de declaração, acesso à elementos e uso de ponteiros veja este site.
Vamos observar alguns exemplos mais elaborados do uso de structs.
typedef struct { char nome[50]; char sexo; float salario; int matricula; char endereco[100]; char cargo[50]; } Funcionario; void cadastrarFuncionario(Funcionario f[], int idx){ getchar(); printf("Qual o nome do funcionario?\n"); scanf(" %[^\n]", f[idx].nome); getchar(); printf("Qual o sexo do funcionario?\n"); scanf(" %c", &f[idx].sexo); printf("Qual o salario do funcionario?\n"); scanf("%f", &f[idx].salario); printf("Qual a matricula do funcionario?\n"); scanf("%d", &f[idx].matricula); printf("Qual o endereco do funcionario?\n"); scanf(" %[^\n]", f[idx].endereco); printf("Qual o cargo do funcionario?\n"); scanf("%[^\n]", f[idx].cargo); } int main(){ Funcionario array[100]; // max de 100 funcionarios int cadastrados = 0, done = 0; while((!done) && (cadastrados < 100)){ printf("Funcionarios cadastrados: %d\n", cadastrados); printf("(1) - Cadastrar novo funcionario\n(2) - Finalizar\n"); int op; scanf("%d", &op); while((op != 1) && (op != 2)){ printf("Opcao invalida\n"); scanf("%d", &op); } if(op == 1){ cadastrarFuncionario(array, cadastrados); cadastrados++; } else done = 1; } int i; for(i = 0; i < cadastrados; i++){ printf("Funcionario %d\n", i); printf("Nome: %s (%c)\n", array[i].nome, array[i].sexo); printf("Endereco: %s\n", array[i].endereco); printf("Matricula: %d\n", array[i].matricula); printf("Cargo: %s\n", array[i].cargo); printf("Salario: %f\n", array[i].salario); printf("============================================\n"); } }Download Code
#define PI 3.1415 typedef struct { double x,y; } Pcart; typedef struct { double r, angle; } Ppolar; Pcart polar2cart(Ppolar p){ Pcart r; float rad = (p.angle*PI)/180.0; r.x = p.r * cos(rad); r.y = p.r * sin(rad); return r; } Ppolar cart2polar(Pcart p){ Ppolar asw; asw.r = sqrt(pow(p.x,2) + pow(p.y,2)); float rad = atan(p.y/p.x); asw.angle = (rad*180)/PI; return asw; } int main(){ Ppolar p = {13, 22.6}; Pcart q = polar2cart(p); Ppolar o = cart2polar(q); printf("Ponto cartesiano: (%.2lf, %.2lf)\n", q.x, q.y); printf("Ponto polar: (%.2lf, %.2lf)\n", o.r, o.angle); } // TERMINAL OUTPUT // [aula10]$ ./ponto // Ponto cartesiano: (12.00, 5.00) // Ponto polar: (13.00, 22.60)Download Code
#include <stdlib.h> typedef struct { int mat; int pNum; float nota; int peso; } Nota; void matNome(int idx){ switch (idx) { case 0: printf("APC\n"); break; case 1: printf("ISC\n"); break; case 2: printf("C1\n"); break; case 3: printf("FTC\n"); break; case 4: printf("InfoSoc\n"); break; default: printf("Lembro dessa materia nao..\n"); } } // funcao de comparacao entre Notas int ehMenor(Nota* a, Nota* b){ float n_a = a->nota; float n_b = b->nota; if(n_a <= n_b) return 1; else return 0; } void showNota(Nota* n){ printf("Materia: "); matNome(n->mat); printf("Prova numero %d\n", n->pNum); printf("Nota: %.2f, peso: %d\n", n->nota, n->peso); } void stats(Nota* arr, int n){ // funcao para ordenar vetores. Faz parte da stdlib.h Nota pior = arr[0]; Nota melhor = arr[0]; int i; for(i = 1; i < n; i++){ if(ehMenor(&arr[i], &pior)) pior = arr[i]; else if(ehMenor(&melhor, &arr[i])) melhor = arr[i]; } printf("MELHOR NOTA\n"); showNota(&melhor); printf("=============================\n"); printf("PIOR NOTA\n"); showNota(&pior); } int main(){ Nota vetor[10]; int sub[] = {0,0,1,1,2,2,3,3,4,4}; float nota[] = {10,10,6.5,8.2,4.5,7.9,4.2,6.5,7.8,8.5}; int i; for(i = 0; i < 10; i++){ Nota a = {sub[i], (i%2)+1, nota[i], (i%3)+2}; vetor[i] = a; } stats(vetor, 10); }Code Execution Download Code
Sabemos usar structs, mas como elas estão armazenadas na mamória? De maneira interessante, elas são semelhantes aos vetores neste quesito também: os atributos da struct estão em endereços adjacentes da memória, conforme mostra a imagem.