Programar em C/Estruturas
Estruturas
As estruturas (structs) permitem com que possamos ter variáveis de vários tipos aglomerados sob o mesmo nome. E esse mesmo nome vai passar a ser um novo tipo de dados tal como o int ou float.
Mas o uso disto é que podemos ter valores que tenham alguma relação lógica, por exemplo guardar um int de idade e um string de nome. Isto pode ser atributos de uma pessoa. Ou seja podemos empacotar várias variáveis de vários tipos com o objetivo de representar o mundo real e dar um nome a essas variáveis todas.
Ao fazer isto criamos um tipo de dados da mesma forma como fazemos em relação ao int ou ao float.
Declarar uma estrutura
A sintaxe é:
struct <identificador> {
<tipo> campo_um ;
<tipo> campo_dois ;
};
Aqui o tipo struct indica que vamos criar uma estrutura. O nome ou identificador pode ser alunos, família, etc . (têm de ser válidos identifiers) Não esquecer o ponto e vírgula “;” no fim da declaração. Campo_um e Campo_dois são variáveis membro – member variables – ou campo da estrutura.
Assim criamos novos tipos de dados.
Primeiro método:
struct minha_estrutura
{
int variavel_um;
int campo_dois;
char fruta[40];
} ;
Aqui o identificador do tipo "struct" é "minha_estrutura" dentro dessa estrutura temos três campos o ultimo é "fruta"
Agora podemos usar esse tipo "struct" para definir variáveis.
struct minha_estrutura nova_estructura;
Para ter acesso aos membros definidos dentro da estrutura utilizamos um operador de seleçao de membro "."(um ponto).
nova_estrutura.fruta[0];
Nos dá o primeiro caracter da palavra contida dentro do membro "fruta".
Para inicializar um campo da estrutura o processo é o mesmo que usamos com as variáveis.
nova_estrutura.campo_dois = 100;
Matrizes de estruturas
Uma estrutura é como qualquer outro tipo de dado no C. Podemos, portanto, criar matrizes de estruturas. Vamos ver como ficaria a declaração de um vetor de 100 fichas pessoais:
struct minha_estrutura fichas [100];
Poderíamos então acessar um campo dando um índice do vetor fichas:
fichas[12].variavel_um;
Declarar instâncias (objetos) da estrutura
Podemos declarar os objetos de duas formas:
- Ao mesmo tempo que declaramos a estrutura
struct product {
int weight;
float price;
} apple, banana, melon;
- Ou como uma variável normal
struct product
{
..
}
int main()
{
struct product apple, banana, melon;
}
E até podemos declarar um array delas
Person p[20];
Pergunta: como é que é feito exatamente os objetos?
Para cada objeto vão ser feito uma cópia dos elementos da estrutura.
Agora isso significa que os objetos são distintos entre si em termos de reserva de memória? ie, à medida que enumero os objetos vão ser reservado para cada objeto o tamanho x de bytes? ou somam-se todos os objetos e reserva-se para todos os objetos de uma forma seguida? Penso que deve ser a 1ª opção.
Se tivermos apenas um objeto (ou variável da estrutura) não é necessário darmos o nome da estrutura
struct {
char item[40]; // name of item
double cost; // cost
double retail; // retail price
int on_hand; // amount on hand
int lead_time; // number of days before resupply
} temp;
Acessar as variáveis membro das estruturas
Agora queremos dar valores a cada uma das pessoas, queremos dar o nome e a altura, para isso faríamos;
strcpy(p1.name, "Tiago");
p1.altura =1.9;
A forma genérica é:
structure-varname.member-name
ou seja
[objecto_estrutura][member_estrutura]
Exemplo
#include <stdio.h>
const int MAX = 3;
struct Person
{
char name[100];
int height;
};
int main ()
{
Person p[MAX];
for (int x = 0; x < MAX; x++)
{
printf("Enter person's name: ");
getline(cin, p[x].name);
printf("Enter height in meters: ");
scanf("%d\n", &p[x].height);
}
printf("Outputting person data\n");
printf("======================\n");
for (int x = 0; x < MAX; x++){
printf("Person #%d's name is %s and height is %d.\n", x + 1, p[x].name, p[x].height);
}
return 0;
}
Iniciar uma estrutura
Podemos iniciar uma estrutura usando uma lista de iniciação, que seria algo como:
Person p1 = {"Jeff Kent", 72};
isto basicamente é igual a arrays, apenas com a diferença de termos tipos diferentes. Logo a ordem vai interessar, por exemplo se escrevêssemos
Person p1 = {72, "Jeff Kent"}; //não iria funcionar- erro de compilação
Ponteiros para estruturas
struct movies_t
{
string title;
int year;
};
movies_t amovie;
movies_t * pmovie;
Nós criámos algo
movies_t title year
amovie
* pmovie
Vejamos que temos um ponteiro como instância.
// pointers to structures
#include <stdio.h>
struct movies_t
{
char title[100];
int year;
};
int main ()
{
string mystr;
movies_t amovie;
movies_t *pmovie;
pmovie = &amovie; //atribuímos valor ao ponteiro
printf("Enter title: ");
fgets(pmovie->title, 100, stdin); //operador ->
printf("Enter year: ";
scanf("%d", &pmovie->year);
printf("\nYou have entered:\n");
printf("%s (%d)\n", pmovie->title, pmovie->year); //operador ->
return 0;
}
Como já devem ter deduzido o operador -> será muito similar a pmovie->title é equivalente a (*pmovie).title
Mas olhem que é diferente a:
*pmovie.title que equivalente a *(pmovie.title)
Passando estruturas como argumento de funções
A estrutura é passada como ponteiro.
#include <stdio.h>
#include <string.h>
struct Person
{
string name;
int height;
};
void setValues(Person*);
void getValues(const Person*);
int main ()
{
Person p1;
setValues(&p1);
printf("Outputting person data\n");
printf("======================\n");
getValues(&p1);
return 0;
}
void setValues(Person* pers)
{
printf("Enter person's name: ");
fgets(pers.name, 100, stdin);
printf("Enter height in inches: ");
scanf("%d", &pers.height);
}
void getValues(const Person* pers)
{
printf("Person's name is %s and height is %d.", pers.name, pers.height);
}
Estruturas aninhadas
A ideia é ter uma estrutura dentro de outra estrutura.
#include <stdio.h>
struct Date //estrutura chamada de date
{
int day;
int month;
int year;
};
struct Person
{
char name[100];
int height;
Date bDay; //temos uma nova variável, mas notem o tipo
};
void setValues(Person*);
void getValues(const Person*);
int main ()
{
Person p1;
setValues(&p1);
printf("Outputting person data\n");
printf("======================\n");
getValues(&p1);
return 0;
}
void setValues(Person* pers)
{
printf("Enter person's name: ");
fgets(pers.name, 100, stdin);
printf("Enter height in inches: ");
scanf("%d", &pers.height);
printf("Enter day, month and year of birthday separated by spaces: ");
scanf("%d %d %d\n", &pers.bDay.day, &pers.bDay.month, &pers.bDay.year );
}
void getValues(const Person* pers)
{
printf("Person's name: %s\n", pers.name);
printf("Person's height in inches is: %d\n", pers.height);
printf("Person's birthday in dd/mm/yyyy format is: %d/%d/%d\n", pers.bDay.day, pers.bDay.month, pers.bDay.year );
}
Reparem que a estrutura Date tem de ser declarada antes da estrutura Person, pois caso contrário o compilador não entenderia o tipo declarado na estrutura Person.
Pergunta: Por que não podemos acrescentar mais membros (campos) nas estruturas?
Porque elas são compiladas estaticamente com posição de memória já alocada e tipo já conhecido em tempo de compilação
Pergunta: Ao invés de termos apenas variáveis nas estruturas, poderíamos ter também funções?
Sim, como ponteiros para funções.