Problema na função

1. Problema na função

Henrique Mezzomo
Henriquerm

(usa Fedora)

Enviado em 19/11/2014 - 22:40h

Olá.
Estou tendo o seguinte problema: Quando executo o programa abaixo, a primeira vez que chamo a função para completar minha estrutra não ocorre nenhum problema, porém, a partir da segunda vez, a linha impressa "Informe o nome do funcionário: " não espera eu escrever algo para armazenar, ele apenas imprime o seguinte:
"Informe o nome do funcionário:"
"Informe o enedereço do funcionário:"
e o que eu gostaria que ocoresse era
"Informe o nome do funcionário: " e que após isso o programa esperasse eu digitar o nome, o que não está ocorrendo, pois o programa apenas imprime e vai direto para o próximo comando de print sem executar o fgets.
Alguém sabeira me informar o problema que está ocorrendo?



#include<stdio.h>
typedef struct{
int dia;
int mes;
int ano;
}data;

typedef struct{
char nome[100];
char endereco[100];
data nascimento;
float salario;
float telefone;
}dados;

dados leitura(){
dados p1;
fflush(stdin);
printf("Informe o nome do funcionario: \n");
fgets(p1.nome,100,stdin);
printf("Informe o endereco do funcionario: \n");
fgets(p1.endereco,100,stdin);
printf("Informe o salario que o funcionário recebe: \n");
scanf("%f",&p1.salario);
printf("Informe o telefone de contato do funcionario: \n");
scanf("%f", &p1.telefone);
printf("Informe o dia de nascimento do funcionario: \n");
scanf("%d", &p1.nascimento.dia);
printf("Informe o mes de nascimento do funcionario: \n");
scanf("%d", &p1.nascimento.mes);
printf("Infome o ano de nascimento do funcionario: \n");
scanf("%d", &p1.nascimento.ano);
return p1;
}

int main(){
dados recursoshumanos[5],maiorsal[1];
int i;
maiorsal[1].salario=0;
for(i=0;i<5;i++){
recursoshumanos[i]=leitura();
if((recursoshumanos[i].salario>maiorsal[1].salario)||(maiorsal[1].salario==0))
maiorsal[1]=recursoshumanos[i];}
printf("Os dados do funcionario de maior salario sao: Nome: %s\n Endereco: %s\n Salario %f\n Telefone %f Data de nascimento %d %d %d \n\n",
maiorsal[1].nome,maiorsal[1].endereco,maiorsal[1].salario,maiorsal[1].telefone,maiorsal[1].nascimento.dia,maiorsal[1].nascimento.mes,maiorsal[1].nascimento.ano);

}



  


2. Re: Problema na função

Paulo
paulo1205

(usa Ubuntu)

Enviado em 20/11/2014 - 18:53h

O mesmo velho problema de não extrair todos os caracteres do buffer de entrada entre uma leitura e outra. Esse assunto deve ser o mais discutido neste fórum e todos os outros existentes no mundo a respeito de C.


O EFEITO:

No seu caso, o caráter não consumido é o indicador de fim de linha após a leitura de um número. Quando você vai ler o próximo nome, esse sinal de fim de linha é percebido imediatamente pela função fgets(), que acaba lendo uma linha vazia.


O PROBLEMA:

A função scanf() é uma função muito complexa. O sufixo “f” no nome da função é para indicar que ela espera uma entrada formatada. Quando você coloca apenas "%d" como string de formatação, está omitindo informações sobre o real formato da entrada. Neste caso particular, está deixando de dizer que existe um fim de linha após ler o número.


A SOLUÇÃO CORRETA:

Leia com muito cuidado a documentação de scanf(). Veja as diversas opções e formas diferentes de interpretar os dados de entrada (por isso que eu digo que é complexa, e considero uma infelicidade que um novato tenha de se deparar com ela logo de cara, e com tão poucas orientações por parte de seus professores)! No entanto, depois de compreender bem seu funcionamento, você verá como ela é poderosa, e como poderá tirar bastante proveito.

Note porém que nem sempre você vai querer usar scanf() para tudo. Se tiver de ler caráter a caráter ou linha a linha de texto, é melhor usar, respectivamente, fgetc()/getchar() e fgets().


SOLUÇÕES RÁPIDAS E QUE NÃO SÃO (MUITO) RUINS:

Se tudo o que estiver pedente no buffer forem marcas de fim de linha ou outro tipo de espaços, você pode removê-los antes da leitura seguinte por meio de um simples espaço na string de formatação de scanf(), como no exemplo abaixo.

printf("Digite seu nome completo: ");
/*
Neste ponto eu não sei se o buffer de entrada está vazio. A linha
abaixo se encarrega de remover eventuais espaços e marcas de fim
de linha, que poderiam atrapalhar a leitura seguinte.
*/
scanf(" "); /* Um espaço entre as aspas. */
/* Agora o fgets() vai pegar uma linha limpa. */
fgets(nome, sizeof nome, stdin);


Outra possibilidade é sempre ler qualquer dado de entrada como se fosse uma linha de texto completa, e depois extrair a informação desejada da linha lida. Uma vantagem dessa abordagem é que fica muito mais fácil tratar erros cometidos pelo usuário (por exemplo: se ele digitar letras quando deveria digitar apenas números).


“SOLUÇÕES” INADEQUADAS E QUE DEVEM SER EVITADAS

- Usar “fflush(stdin)”. Essa ideia, apesar de não ser uma violação direta, é um abuso do padrão do C (que só define o comportamento da função para fluxos de saída de dados, não para os de entrada, e com sentido de tornar os dados permanente, não descartá-los) e, portanto, não há garantias de que vá funcionar em qualquer ambiente. Além disso, a operação de “limpar lixo” é meio complicada porque é difícil definir o que é “lixo”. Um “fflush(stdin)” vai fazer uma porção de escolhas arbitrárias -- e não documentadas -- sobre o formato dos dados de entrada e seu comprimento, e isso pode nem sempre coincidir com o fluxo de dados que você tem em mãos.

- Usar fpurge(), __fpurge() ou equivalentes. Um pouco melhor do que “fflush(stdin)” porque pelo menos não abusa do padrão. No reverso da moeda está o fato de que tais funções, justamente por não serem padronizadas, não estão disponíveis em todos os sistemas. Além disso, valem para tais funções o mesmo que foi discutido acima sobre escolhas arbitrárias e suas possíveis inadequações.

- “Soluções” que interfiram nos buffers internos (usando, por exemplo, setbuf() ou stevbuf()). Também são abusos do padrão. Não existem qualquer garantia de que vá funcionar.

- Laços de repetição que vão lendo caracteres até encontrar um sinal desejado (geralmente a fim de linha '\n') são a ideia menos ruim de todas. No entanto, há de se ter muito cuidado, pois uma situação que a maioria das soluções de tipo não prevê é justamente aquela em que o buffer já está limpo. O programador deve primeiro ter certeza de que há dados em excesso, e só então usar uma dessas soluções. Caso contrário, tentar limpar um buffer já limpo pode efetivamente forçar o descarte de dados válidos, que deveriam ser consumidos e usado pelo programa. Pior do que isso, dependendo de onde e como a limpeza for invocada, o programa pode até “parar”, esperando dados de leitura que vai descartar, sem exibir um prompt para o usuário.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts