Ir ao conteúdo
  • Cadastre-se

C Inserir nome e mostrar


Posts recomendados

Bom dia

O meu objetivo era com que o programa perguntasse ao utilizador o nome, o website e o email mas quando pergunta a primeira vez passa á frente o nome.

#include <stdio.h>
#include <stdlib.h>

void main()
{
    int i , y , m , n;

    printf("Quantos clientes sao?");
    scanf("%d",&y);

    struct cliente
    {
     char nome[50];
         char website[100];
            char email[100];
    }c[5];

    for(i=0 ; i<y ; i++)
    {
    printf("Insere o nome do cliente-->");
    gets(c[i].nome);
        printf("Insira o website do Cliente-->");
        gets(c[i].website);
            printf("Insira o email do Cliente-->");
            gets(c[i].email);
                system("cls");
    }

    struct sm{
     char servico[50];
         char data[10];
            char montante[100];
    }sm[5];

    for(i=0 ; i<y ; i++)
    {
    printf("Insira o serviço mensal do Cliente-->");
    gets(sm[i].servico);
        printf("Insira a data do serviço mensal do Cliente-->");
        gets(sm[i].data);
            printf("Insira o montante do serviço mensal do Cliente-->");
            gets(sm[i].montante);
                system("cls");
    }
    printf("Atualmente existem %d clientes e os nomes dos mesmos são:",y);
    for(i=0 ; i<y ; i++)
    printf("     |%s\n",c[i].nome);
}

e quando corro o programa acontece isto-->

image.png.aad548df550d98755f8ecdb8a2c0e73d.png

Alguem me pode ajudar?
Agradeço toda a ajuda possível :)

Link para o comentário
Compartilhar em outros sites

@thefill Não use o primeiro método de "limpar" entrada desse link, está usando fflush para algo que ele não foi feito (ele é apenas para fluxos de saída) logo terá comportamento indefinido, ou seja não dá pra garantir que funcione. Use apenas o segundo pois funciona em todas as situações.

Link para o comentário
Compartilhar em outros sites

26 minutos atrás, Lucca Rodrigues disse:

@isrnick

Funciona só se o buffer não estiver vazio.

Mas aí você pode tentar garantir que sempre sobre pelo menos o caractere nova linha na entrada antes de chamar a função para limpar a entrada.

 

Do contrário vai ter que usar algo que nunca deixe nada sobrando na entrada, como a função getline do padrão PÒSIX, ou minha função nscanf:

 

OBS: getline não é uma função padrão ISO da linguagem C, então se não estiver disponível no seu compilador pode ter que achar uma implementação pronta na internet, ou implementar você mesmo.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

1 hora atrás, isrnick disse:

Mas aí você pode tentar garantir que sempre sobre pelo menos o caractere nova linha na entrada antes de chamar a função para limpar a entrada.

Ou pode ler e ignorar o '\n', acredito que o melhor seja não sobrar nada depois da chamada da scanf(), porém o usuário tem teclas de sobra de liberdade, enfim...

Pode usar ungetc() para inserir algum caractere no fluxo antes de começar a ler, daí este nunca estará vazio em nenhuma situação, independente de onde chamar a função para ler o que resta no fluxo, a famigerada "limpa buffer" :D

 

1 hora atrás, isrnick disse:

ou minha função nscanf

Acho que eu tinha apontado um problema, pelo menos nesta versão que postou.

Usando scanset ou scanset negado na scanf() de modo a permitir o '\n' no conjunto de caracteres, o usuário pode em teoria digitá-lo à vontade, porém nscanf() usa a fgets() que usualmente aguarda um Enter para encerrar a leitura, como resultado:

image.png.f1ecf1e8ea0ae9f428e3272e82896b54.png

Com scanf():

image.png.8e7506b3fb84ca35a964e500e5a652e0.png

Pode estar meio sem contexto esses prints das saídas, mas no tópico sobre a nscanf() está bem contextualizado.

 

Acho que o ponto principal de uma função para consumir o que resta no fluxo é sempre ter algo de sobra para ser lido, por isso acho interessante a ungetc(). A partir disso é baba :)

Link para o comentário
Compartilhar em outros sites

6 horas atrás, Lucca Rodrigues disse:

scanset ou scanset negado na scanf()

 

:D cruel isso como resposta em relação a um programa de iniciante que usa 

17 horas atrás, Joel Martins disse:

scanf("%d",&y);

 

para ler um int e nem testa se leu mesmo algo.

 

Talvez pudesse explicar que scanset é uma denominação geral para um especificador (aquelas coisas que começam por um '%' e não são seguidas por outro %) em uso em funções da família scanf() e que tenha um conjunto de letras entre '[' e ']'.

 

scanset negado então parece alguma palavra mágica, uma gíria dos conhecedores :D Não me leve a mal, eu sei que você está certo. @Lucca Rodrigues

 

E o que seria um trem desses?

 

Exemplo

 

Um exemplo direto da documentação mas um pouco melhorado
 

#include <stdio.h>
#include <string.h>

int         main(void)
{
    int i;
    float x;
    char name[250];
    printf("\no exemplo do manual sugere a entrada \"56789 0123 56a72\" para testar\n\n\n");
    int res = fscanf(stdin, "%2d%f%*d %[0-3456-9]", &i, &x, name);
    printf( "\n\ta chamada:\n\tfscanf(stdin, \"%%2d%%f%%*d %%[0123456789]\",\
, &i, &x, name);\t\n\tretornou %d e leu\n\n", res);
    printf("\ti = %d, x = %f, name = \"%s\"\n", i, x, name);
    char* p = fgets(name,250,stdin);
    if ( p == NULL ) 
    {
        printf("\tfgets() não leu mais nada\n");
        return 0;
    }
    printf("\tfgets() ainda leu %zd bytes do resto da linha:\n", strlen(name));
    puts(name);
    if ( name[strlen(name) - 1] == '\n') 
    printf("\te tem um '\\n' ao final da string lida por fgets()\n\n");
    return 0;
}

 

"Melhorado" apenas porque o standard (manual) é um pouco direto e o programa acima é mais gentil com quem está aprendendo.

 

O exemplo discute a entrada "56789 0123 56a72"

 

O especificador é "%2d%f%*d %[0123456789]"

 

O tal scanset é "%[0123456789]"

 

Então:

  • tem 4 especificadores: %2d %f %*d e %[0123456789]
    • %2d lê um int com dois dígitos
    • %f lê um float, um número com ponto decimal
    • %*d lê um inteiro, como o %d faria, mas como tem o * depois do % descarta o que conseguir ler: vai pular um número
    • %[0123456789] lê uma sequência desses números, parando assim que ver algo diferente
  • fscanf() pode então retornar
    • -1 se der erro
    • 0 se não ler nadinha
    • 1,2,3 se ler algo. Não vai retornar 4 porque tem um asterisco no terceiro especificador então vai ignorar o que ler. Não vai retornar nada diferente disso.

E consumindo a entrada do exemplo, "56789 0123 56a72"

  • vai retornar 3. Teste sempre isso. É ingênuo não testar e seguir adiante, mesmo em um programa de estudante.
  • o %2d vai ler 56
  • o %f vai ler 789 e parar no espaço. espaços, TAB e '\n' são descartados na leitura, e qualquer número deles entre o 9 e o 0 vai sumir. TESTE isso.
  • o %*d vai ler e descartar o grupo 0123, e de novo qualquer conjunto de espaços TAB ou  '\n' que venham em seguida, e vai parar no 56
  • o tal scanset vai aceitar todos os dígitos a seguir, e vai ler até o 'a' então, e nome vai ficar com "56"
  • o mesmo efeito seria obtido por ^[0-9]. O hífen indica um intervalo, com os extremos inclusos. Isso quer dizer que %[0-3456-9] também faria a mesma coisa.

E o tal scanset negado?

 

Então um tal scanset, o grupo de símbolos que será aceito para compor a leitura, se começar por um '^' indica que vai aceitar qualquer coisa EXCETO os símbolos do conjunto. Esse é o tal scanset negado. No exemplo %[^0-9] aceitaria qualquer coisa até ler um dígito.

 

E a saída do programa para aquela linha do exemplo do manual?

 

clube> gcc -o tst -Wall  ts.c
clube> ./tst

o exemplo do manual sugere a entrada "56789 0123 56a72" para testar


56789 0123 56a72

        a chamada:
        fscanf(stdin, "%2d%f%*d %[0123456789]",, &i, &x, name);
        retornou 3 e leu

        i = 56, x = 789.000000, name = "56"
        fgets() ainda leu 4 bytes do resto da linha:
a72

        e tem um '\n' ao final da string lida por fgets()

 

Pois é.

 

É ruim misturar scanf() e fgets() no programa porque cada função tem suas regras. Vendo o exemplo acima acho que dá pra entender.

Entenda que o que sobrou do scanf() foi consumido pela chamada de fgets() que vem a seguir. Você @Joel Martinspode usar isso a seu favor ou contra. Use essa lógica em seu programa. Lendo isso talvez dê idéias de uma maneira segura de ler esses campos. 

 

Ou use apenas fgets() e leia linha a linha. E aí trate o que for lido. Essa linguagem não foi escrita com esse uso em mente, ler coisas do teclado. E o modo como funciona o tratamento de teclado e arquivos de texto não ajuda muito. Programas em C raramente leem do teclado exceto nos cursos. O problema --- não é um problema, o problema é o modo como isso é ensinado --- está no modo normal de funcionamento do teclado, que opera num modo chamado LINE INPUT no Windows (Cooked Mode no Mac Linux Unix), porque você pode usar coisas como backspace para corrigir, as setas, delete, control-C e control-V para compor o que está digitando, e a fila só anda ao teclar o tal ENTER.

 

Outra opção segura é usar fgets() para ler linha a linha e sscanf() para tratar o que foi lido. Assim não sobra nada entre uma leitura e outra. Acho que já mostrei exemplos assim aqui.

 

Outra opção é ler direto do sistema, para ter controle total. E não usar nenhuma dessas funções.

 

Outra opção é ler letra a letra e desligar o LINE INPUT e o eco e só mostrar cada letra depois de testar e tratar.

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

 

GRÁTIS: ebook Redes Wi-Fi – 2ª Edição

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!