Baixe o app para aproveitar ainda mais
Prévia do material em texto
A21: Estruturas e Ponteiros - parâmetros por referência Algoritmos e Programação Julio Toss jtoss@inf.ufrgs.br INF01202 – Algoritmos e Programação, 2018/01, Turmas G, H, K e L *baseado no material da prof. Mariana e do prof. Marcelo Walter Atenção: O material aqui contido não substitui a leitura do livro texto e é incompleto sem a apresentação do professor em aula. 2 Estruturas: prototipação, declaração e manipulação Estruturas e funções: retorno e parâmetro por valor Aula passada struct nome_estrutura funcao() { struct nome_estrutura var; (...) return var; } void funcao(struct nome_estrutura par) { int x = par.campo1; par.campo2 = …; (...) } 3 // continuando… int main() { struct ponto_st p1, p2; float dist; printf("\nCoordenadas do Ponto 1: "); scanf("%f %f", &p1.x, &p1.y); printf("\nCoordenadas do Ponto 2: "); scanf("%f %f", &p2.x, &p2.y); dist = sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2)); printf("\nDistancia: %f\n", dist); return 0; } Aula passada: exemplo simples Faça um programa para calcular a distância entre dois pontos bidimensionais. Represente um ponto como uma estrutura. #include <stdio.h> #include <math.h> struct ponto_st { float x; float y; }; // continua… 4 Aula passada: exemplo arranjos nos campos #include<stdio.h> struct funcionario_st { int cod; char nome[30]; char cargo[10]; float salario[10]; }; // continua… // continuando… int main () { struct funcionario_st funcionario; int i; printf("\nCodigo: "); scanf("%d", &funcionario.cod); printf("\nNome: "); fgets(funcionario.nome, 30, stdin); printf("\nCargo: "); fgets(funcionario.cargo, 10, stdin); printf("\nDigite os 10 ultimos salarios: "); for (i=0; i<10; i++) scanf("%f", &funcionario.salario[i]); return 0; } 5 #include<stdio.h> struct endereco_st { char rua[50]; int numero; char bairro[20]; char cidade[30]; char sigla_estado[3]; // 2 letras + '\0' char cep[10]; }; struct ficha_st { char nome[50]; char telefone[16]; struct endereco_st end; }; // continua… int main( ) { struct ficha_st ficha; printf("\nNome: "); fgets(ficha.nome, 50, stdin ); printf("\nTelefone: "); fgets(ficha.telefone, 16, stdin ); printf("\nRua: "); fgets(ficha.end.rua, 50, stdin ); printf("\nNumero: "); scanf ("%d", &ficha.end.numero); printf("\nBairro: "); fgets(ficha.end.bairro, 20, stdin ); printf("\nCidade: "); fgets(ficha.end.cidade, 30, stdin ); printf("\nSigla do estado: "); fgets(ficha.end.sigla_estado, 3, stdin ); printf("\nCEP: "); fgets(ficha.end.cep, 10, stdin ); (…) } Aula passada: exemplo aninhamento 6 // (...) for (i=0; i<NALUNOS; i++) { scanf("%d", &alunos[i].cartao); scanf("%f", &alunos[i].provas[0]); scanf("%f", &alunos[i].provas[1]); scanf("%f", &alunos[i].pratica); scanf("%f", &alunos[i].trabalho); } for (i=0; i<NALUNOS; i++) { soma1 += alunos[i].provas[0]; soma2 += alunos[i].provas[1]; } printf("Media P1: %f", soma1/NALUNOS); printf("Media P2: %f", soma2/NALUNOS); return 0; } #include<stdio.h> #define NALUNOS 30 struct estudantes_st { int cartao; float provas[2], pratica, trabalho; }; int main( ) { int i; float soma1 = 0, soma2 = 0; struct estudantes_st alunos[NALUNOS]; // (...) Exemplo extra: arranjo de estruturas 7 Exercício da aula passada Considere a seguinte estrutura de um registro: PRODUTO: CODIGO TIPO QUANTIDADE[6] MEDIA Suponha que ela deva armazenar os dados referentes ao nome de um PRODUTO (peça de vestuário) de uma empresa, o TIPO do produto (tipos disponíveis: pequeno, médio e grande), a QUANTIDADE vendida para cada um dos 6 dias de uma semana e a quantidade MÉDIA vendida na semana (média dos 6 dias). Considere que os dados relativos a 50 produtos** vendidos pela empresa são armazenados em um arranjo cujos elementos correspondem a esta estrutura. [** utilize constante para testar o programa com um número menor de itens!!] Faça um programa que processe as vendas efetuadas, armazenando os dados referentes à estrutura acima para 6 dias de uma semana. O programa deverá ler todos os dados de cada produto (incluindo a quantidade vendida nos 6 dias) através de uma função que retorna uma estrutura preenchida. Na função principal, seu programa deverá calcular as médias da semana para cada produto e imprimir um relatório com os dados finais da estrutura: para cada produto, total vendido por dia e a média da semana. A impressão dos dados na tela deve ser feita com uma função que recebe uma única estrutura como parâmetro e imprime seus dados na tela com formatação adequada Protótipos das funções: struct struct_produto le_dados_produto() void imprime_dados(struct struct_produto) 8 Exercício da aula passada 9 #include <stdio.h> #include <string.h> #include <stdlib.h> #define QTDPROD 50 #define DIAS 6 struct produto_st { char nome[31]; char tipo[8]; int quantidade[DIAS]; float media; }; // continua... // continuando… struct produto_st leProduto(){ struct produto_st produto; int i; float soma=0; printf("Digite nome do produto: "); fgets(produto.nome, 30, stdin); printf("Digite o tipo (Peq/Med/Gra): "); scanf("%s",produto.tipo); printf("Qtd vendida nos %d dias da semana: ", DIAS); for(i=0;i<DIAS;i++) { scanf("%d",&produto.quantidade[i]); soma = soma+produto.quantidade[i]; } return produto; } Exercício da aula passada 10 // continuando… void imprimeProduto(struct produto_st produto, int idx){ int i; printf("\n--- PRODUTO %d ---\n", idx+1); printf("\t Nome: %s\n", produto.nome); printf("\t Tipo: %s\n", produto.tipo); printf("\t Vendas nos ultimos %d dias: ", DIAS); for(i=0;i<DIAS;i++) printf("%5d ",produto.quantidade[i]); printf("\n"); printf("\t Media de vendas: %.2f\n",produto.media); } // continuando… int main(){ struct produto_st produtos[QTDPROD]; int cont; for (cont=0; cont<QTDPROD;cont++){ produtos[cont]= leProduto(); //calculo da media produtos[cont].media = 0; for ( j = 0 ; j < DIAS ; j++){ produtos[cont].media += (float) produtos[cont].quantidade[j] / DIAS; } } for (cont=0; cont<QTDPROD;cont++) imprimeProduto(produtos[cont], cont); return 0; } Tipos, Estruturas e Ponteiros 11 Renomeação de tipos: typedef Por vezes, para deixar o código mais legível, é desejável renomear os tipos definidos no programa. A linguagem C provê um mecanismo para criarmos novos nomes para tipos de dados com o comando typedef. Sintaxe: typedef nome_antigo novo_nome; - nome_antigo é o nome de um tipo (ex: int, char, double, float, …). - nome_antigo pode ser composto por vários nomes (ex: unsigned int, long long int, struct nome_estrutura, …) 12 #include<stdio.h> typedef int inteiro; typedef unsigned int natural; typedef double real; typedef char simbolo; int main() { inteiro meta; natural id; real dinheiro; simbolo letra; scanf("%d", &meta); scanf("%u", &id); scanf("%f", &dinheiro); scanf("%c", &letra); return 0; } #include<stdio.h> typedef char byte; typedef unsigned int uint; typedef unsigned long int ulint; typedef unsigned long long int ullint; typedef float flt; typedef double dbl; int main() { byte codigo[100]; ullint num, i; dbl fatorial = 1.0; fgets(codigo, 100, stdin); scanf("%u", &num); for (i=1; i<num; i++) fatorial *= i; (…) Renomeação de tipos: typedef 13 // continuando… int main(){ ponto_t p1, p2; float dist; printf("\nCoordenadas do Ponto 1: "); scanf("%f %f", &p1.x, &p1.y); printf("\nCoordenadas do Ponto 2: "); scanf("%f %f", &p2.x, &p2.y); dist = sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2)); printf("\nDistancia: %f\n", dist); return 0; } Renomeação de tipos: typedef Faça um programa para calcular a distância entre dois pontos bidimensionais. Represente um ponto como uma estrutura. #include <stdio.h> #include <math.h> struct ponto_st { float x; float y; }; typedef struct ponto_st ponto_t; // continua… 14 Renomeação de tipos: typedef #include<stdio.h> struct funcionario_st { int cod; char nome[30]; char cargo[10]; int depto; float salario; }; typedef struct funcionario_st func_t; // continua… // continuando… int main () { func_t funcionario; printf("\nCodigo: "); scanf("%d", &funcionario.cod); printf("\nNome: "); fgets(funcionario.nome, 30, stdin); printf("\nCargo: "); fgets(funcionario.cargo, 10, stdin); printf("\nDepto: "); scanf("%d", &funcionario.depto); printf("\nSalario: "); scanf("%f", &funcionario.salario); return 0; } 15 #include<stdio.h> struct endereco_st { char rua[50]; int numero; char bairro[20]; char cidade[30]; char sigla_estado[3]; // 2 letras + '\0' char cep[10]; }; typedef struct endereco_st end_t; struct ficha_st { char nome[50]; char telefone[16]; end_t end; }; typedef struct ficha_st ficha_t; int main( ) { ficha_t ficha; printf("\nNome: "); fgets(ficha.nome, 50, stdin ); printf("\nTelefone: "); fgets(ficha.telefone, 16, stdin ); printf("\nRua: "); fgets(ficha.end.rua, 50, stdin ); printf("\nNumero: "); scanf ("%d", &ficha.end.numero); printf("\nBairro: "); fgets(ficha.end.bairro, 20, stdin ); printf("\nCidade: "); fgets(ficha.end.cidade, 30, stdin ); printf("\nSigla do estado: "); fgets(ficha.end.sigla_estado, 3, stdin ); printf("\nCEP: "); fgets(ficha.end.cep, 10, stdin ); (…) Renomeação de tipos: typedef 16 // (...) for (i=0; i<NALUNOS; i++) { scanf("%d", &alunos[i].cartao); scanf("%f", &alunos[i].provas[0]); scanf("%f", &alunos[i].provas[1]); scanf("%f", &alunos[i].pratica); scanf("%f", &alunos[i].trabalho); } float soma1 = 0, soma2 = 0; for (i=0; i<NALUNOS; i++) { soma1 += alunos[i].provas[0]; soma2 += alunos[i].provas[1]; } printf("Media P1: %f", soma1/NALUNOS); printf("Media P2: %f", soma2/NALUNOS); return 0; } #include<stdio.h> #define NALUNOS 30 struct estudantes_st { int cartao; float provas[2], pratica, trabalho; }; typedef struct estudantes_st estud_t; int main( ) { int i; estud_t alunos[NALUNOS]; // (...) Renomeação de tipos: typedef 17 Renomeação de tipos: typedef Pode ser combinado com struct para deixar o código mais enxuto. typedef struct ponto_st { float x; float y; } ponto_t; int main() { ponto_t p1, p2; (...) 18 Renomeação de tipos: typedef Pode substituir o nome da estrutura. typedef struct { float x; float y; } ponto_t; int main() { ponto_t p1, p2; (...) 19 Estruturas: protótipo sem nome Aliás, estruturas podem ser declaradas sem nome. Porém, nesse caso é preciso declarar uma ou mais variáveis para utilizá-la. int main() { struct { float x; float y; } p1, p2; p1.x = 10; (...) } 20 Estruturas: protótipo sem nome Aliás, estruturas podem ser declaradas sem nome. Porém, nesse caso é preciso declarar uma ou mais variáveis para utilizá-la. int main() { struct { float x; float y; } p1, p2; p1.x = 10; (...) } 21 p1 e p2 são variáveis locais, assim como o “tipo” estrutura a partir do qual foram definidas. Perceba que neste caso não há um tipo estrutura explicitamente declarado no programa. Sendo assim, não poder ser reutilizado em outros trechos do programa! Estruturas: protótipo sem nome 22 Ponteiros: estruturas Sintaxe: declaração: struct nome_estrutura *ptr; struct ponto_st { int x; int y; }; int main() { struct ponto_st p1, p2, *ptr_ponto; ptr_ponto = &p1; (...) 23 Ponteiros: estruturas Sintaxe: declaração: struct nome_estrutura *ptr; typedef struct ponto_st { int x; int y; } ponto_t; int main() { ponto_t p1, p2, *ptr_ponto; ptr_ponto = &p1; (...) 24 Ponteiros: estruturas Sintaxe: declaração: struct nome_estrutura *ptr; typedef struct ponto_st { int x; int y; } ponto_t; int main() { ponto_t p1, p2; struct ponto_st *ptr_ponto; ptr_ponto = &p1; (...) 25 typedef struct ponto_st { int x; int y; } ponto_t; int main() { ponto_t p1, p2; struct ponto_st *ptr_ponto; ptr_ponto = &p1; (...) Ponteiros: estruturas Com uso de typedef, estas três formas são equivalentes: struct ponto_st { int x; int y; }; int main() { struct ponto_st p1, p2, *ptr_ponto; ptr_ponto = &p1; (...) typedef struct ponto_st { int x; int y; } ponto_t; int main() { ponto_t p1, p2, *ptr_ponto; ptr_ponto = &p1; (...) 26 Ponteiros: estruturas Sintaxe: uso: (*ptr).campo; Operador Ponto tem maior precedência do que o Ponteiro, por isso é preciso usar parênteses! Caso contrário, se fizermos apenas *ptr.campo, o compilador vai interpretar como *(ptr.campo) , mas ptr não é do tipo estrutura, é tipo ponteiro para estrutura. Ou seja… ERRO!! 27 Ponteiros: estruturas Sintaxe: uso: (*ptr).campo; uso: ptr->campo; Ambos são equivalentes. O operador seta -> é uma outra forma de escrever o acesso a um campo por meio um ponteiro para estrutura (é a forma mais comumente utilizada). 28 Em leitura de dados simples (float, char, int…) para campos de estruturas passadas por referência, é preciso acrescentar o ‘&’. Exemplo: scanf(“%d”, &ptr->inteiro); // ou scanf(“%d”, &(*ptr).inteiro); Ponteiros: estruturas Sintaxe: uso: (*ptr).campo; uso: ptr->campo; Ambos são equivalentes. O operador seta -> é uma outra forma de escrever o acesso a um campo por meio um ponteiro para estrutura. 29 Ponteiros: parâmetro estrutura por referência #include <stdio.h> #include <math.h> typedef struct ponto_st { float x; float y; } ponto; void le_ponto(ponto*); float calcula_dist(ponto*, ponto*); int main() { ponto p1, p2; float dist; le_ponto(&p1); le_ponto(&p2); dist = calcula_dist(&p1, &p2); printf("\nDistancia: %f\n", dist); return 0; } void le_ponto(ponto* pnt) { printf("\nCoordenadas do Ponto: "); scanf("%f %f", &pnt->x, &pnt->y); // ou scanf("%f %f", &(*pnt).x, &(*pnt).y); } float calcula_dist(ponto* a, ponto* b) { float quadX, quadY; quadX = pow(a->x - b->x, 2); // ou quadX = pow((*a).x - (*b).x, 2); quadY = pow(a->y - b->y, 2); // ou quadY = pow((*a).y - (*b).y, 2); return sqrt(quadX + quadY); } 30 Exercício: ponteiros e estruturas 31 Como ficaria o exemplo da aula passada, de leitura de dados de um aluno, passando a variável tipo estrutura para a função e com uso de typedef? #include <stdio.h> #include <string.h> #define NRNOTAS 3 struct struct_aluno { char nome[16]; float nota[NRNOTAS]; float media; char conceito; }; struct struct_aluno le_dados_aluno() { struct struct_aluno aluno; int i; printf ( "\n Nome: "); fgets(aluno.nome, 15, stdin); aluno.media = 0; //le notas e calcula media for (i = 0; i < NRNOTAS ; i++) { scanf(“%f”,&aluno.nota[i]); aluno.media += aluno.nota[i]; } //estabelece conceito ... return aluno; } // continua programa... Exercício: ponteiros e estruturas 32 Como ficaria o exemplo da aula passada, de leiturade dados de um aluno, passando a variável tipo estrutura para a função e com uso de typedef? #include <stdio.h> #include <string.h> #define NRNOTAS 3 typedef struct struct_aluno { char nome[16]; float nota[NRNOTAS]; float media; char conceito; } aluno_st; void le_dados_aluno(aluno_st* aluno) { int i; printf ( "\n Nome: "); fgets(aluno->nome, 15, stdin); aluno->media = 0; printf(“Digite as %d notas: ”, NRNOTAS); for (i = 0; i < NRNOTAS ; i++) { scanf(“%f”, &aluno->nota[i]); // continua... // continuando… while (aluno->nota[i] < 0 || aluno->nota[i]> 10) { printf(“Nota invalida\n”); scanf(“%f”, &aluno->nota[i]); } aluno->media += aluno->nota[i]; } aluno->media = aluno->media/NRNOTAS; if (aluno->media >= 9.0) aluno->conceito = 'A'; else if (aluno->media >= 7.5) aluno->conceito = 'B'; else if (aluno->media >= 6.0) aluno->conceito = 'C'; else aluno->conceito = 'D'; } Exercício: ponteiros e estruturas 33 Como ficaria o exemplo da aula passada, de leitura de dados de um aluno, passando a variável tipo estrutura para a função e com uso de typedef? // continuando… void imprime_dados_aluno(aluno_st aluno) { int i; printf("\n\nResultado:\n"); // para não ter que digitar espaços //formata string literal: printf("\n%-15s prova1 prova2 prova3 media conc", "Nome do aluno"); printf ( "\n%-15s ", aluno.nome); for (i = 0; i < NRNOTAS ; i++) printf ("%6.2f ", aluno.nota[ i ] ) ; printf ("%6.2f ", aluno.media); printf ( " %c\n\n ", aluno.conceito); } int main() { aluno_st aluno; le_dados_aluno(&aluno); imprime_dados_aluno(aluno); return 0; } E para ler um vetor de variáveis do tipo “aluno”, com passagem de parâmetro por referência? Exercício: ponteiros e estruturas 34 Como ficaria o exemplo da aula passada, de leitura de dados de um aluno, passando um arranjo de tipo estrutura para a função e com uso de typedef? #include <stdio.h> #include <string.h> #define NRNOTAS 3 #define NALUNOS 30 typedef struct struct_aluno { char nome[16]; float nota[NRNOTAS]; float media; char conceito; } aluno_st; void le_dados_alunos(aluno_st* alunos, int tam) { int i, j; for (j=0; j < tam; j++) { printf ( "\nALUNO %d: ",j+1); printf ( "\n Nome: "); fgets(alunos[j].nome, 15, stdin); alunos[j].media = 0; printf(“Digite as %d notas: ”, NRNOTAS); for (i = 0; i < NRNOTAS ; i++) { scanf(“%f”, &alunos[j].nota[i]); while (alunos[j].nota[i] < 0 || alunos[j].nota[i]> 10) { printf(“Nota invalida\n”); scanf(“%f”, &alunos[j].nota[i]); } alunos[j].media += alunos[j].nota[i]; } alunos[j].media = alunos[j].media/NRNOTAS; if (alunos[j].media >= 9.0) alunos[j].conceito = 'A'; else if (alunos[j].media >= 7.5) alunos[j].conceito = 'B'; else if (alunos[j].media >= 6.0) alunos[j].conceito = 'C'; else alunos[j].conceito = 'D'; } } //continua... Exercício: ponteiros e estruturas 35 Como ficaria o exemplo da aula passada, de leitura de dados de um aluno, passando um arranjo de tipo estrutura para a função e com uso de typedef? // continuando… void imprime_dados(aluno_st* alunos, int tam) { int i, j; for (j=0; j < tam; j++) { printf("\n\nResultado aluno %d:\n",j+1); // para não ter que digitar espaços // formata string literal: printf("\n%-15s prova1 prova2 prova3 media conc", "Nome do aluno"); printf ( "\n%-15s ", alunos[j].nome); for (i = 0; i < NRNOTAS ; i++) printf ("%6.2f ", alunos[j].nota[i]); printf ("%6.2f ", alunos[j].media); printf ( " %c\n\n ", alunos[j].conceito); } } int main() { aluno_st listaAlunos[NALUNOS]; le_dados_aluno(listaAlunos, NALUNOS); imprime_dados_aluno(listaAlunos, NALUNOS); return 0; } Para pensar em casa... 1. Defina em C um novo tipo denominado Passagem, conforme layout do bilhete de passagem de ônibus mostrado ao lado. Os campos data e horário são estruturas que possuem, respectivamente, 3 e 2 campos. 36 2. A partir da estrutura definida no item 1, implemente as funções ler_bilhete e mostrar_bilhete, que permitem, respectivamente, ler e mostrar todos os dados relativos a um determinado bilhete. A função ler_bilhete poderia ser implementada através de uma função sem parâmetros que retorna um struct, ou através de uma função void (ou seja, sem retorno) que recebe o struct como parâmetro por referência. Tente implementar e testar os dois casos para praticar! 3. Na main(), declare um vetor de estruturas tipo Passagem, que irá armazenar todos os Bilhetes vendidos em um determinado período pela Viação Viaje Bem (assuma um máximo de 200 bilhetes). Leia e posteriormente imprima as informações de N passagens usando as funções declaradas, onde N será informado pelo usuário e deve ser validado (N < 200). 4. Por fim, faça uma função que receba o vetor de estruturas tipo Passagem, o número de passagens vendidas (N) e imprima na tela os dados de todas as passagens vendidas em um determinado mês, também informado como parâmetro da função (por exemplo, “Janeiro”, ‘J’ ou 0). Teste a chamada desta função na main().
Compartilhar