Why I cannot use "fgets" to read a string to an element of my Struct?

812 Views Asked by At

I'm trying to create a program almost like "bank" using struct, but when the program should have read the string (variable "nome" that is name in portuguese) it totally ignore the "fgets" that I used. This is the part that I was talking about :

printf("\nNome: \n");
fgets(vet[cont+1].nome, sizeof(vet[cont+1].nome), stdin);

And I'm pretty sure that maybe the problem is with the dynamically allocation of my object array. Please, give me a help with this problem, thank you!

PS: I'm sorry but the code is in portuguese (my native language).

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

/*
Programa realiza uma alocacao dinamica por meio 
de uma funcao que recebe a dimensao e retorna o vetor(ponteiro)
*/

struct CLIENTES
{
    int ano_nasc, cpf[11];
    float renda_m;
    char nome[50];
}; //Lista de Objetos

int main(void) 
{
    //Declaracao de Variaveis
    int cont=0, num, num_2, client, i, j;
    CLIENTES *vet;

    //Leitura de Dados
    printf("Digite o numero de Clientes: ");
    scanf("%d", &num);
    vet = (CLIENTES*)malloc(num*sizeof(int));
    printf("Digite os Dados do Cliente.");

    while (cont != num)
    {  
        printf("\nNome: \n");
        fgets(vet[cont+1].nome, sizeof(vet[cont+1].nome), stdin);
        printf("\nAno de Nascimento: ");
        scanf("%d", &vet[cont+1].ano_nasc);
        printf("\nCPF: ");
        scanf("%d", &vet[cont+1].cpf);
        printf("\nRenda Mensal: ");
        scanf("%d", &vet[cont+1].renda_m);
        cont++;
    }

    printf("\nDigite o numero do cliente que voce deseja conferir: ");
    scanf("%d", &num_2);
    for (i=0;i<num;i++)
    {
        if(num_2 == num)
        {
            printf("\nO que deseja saber sobre ele?\n");
            printf("1-Nome\n2-Ano de Nascimento\n3-CPF\n4-Renda Mensal\n\n\n");
            scanf("%d", &client);
            if (client == 1)
            {
                printf("Nome: %c", vet[num_2].nome );
            }
            else if(client == 2)
            {
                printf("Ano de Nascimento: %d", vet[num_2].ano_nasc );
            }
            else if(client == 3)
            {
                for(j=0;j<11;j++)
                {
                    printf("CPF: %d", vet[num_2].cpf[j]);
                }
            }
            else if(client == 4)
            {
                printf("Renda Mensal: %f", vet[num_2].renda_m );
            } 
        }
    }

    //Finalizando o Programa
    printf("\n\nFim do Programa!");
    getch();
    return 0;
}
3

There are 3 best solutions below

4
On BEST ANSWER

Problems that I see:

  1. You are allocating the wrong amount of memory in the line:

    vet = (CLIENTES*)malloc(num*sizeof(int));
    

    That should be:

    vet = malloc(num*sizeof(*vet));
    

    See Do I cast the result of malloc?. The answers explain why you should not cast the return value of malloc.

  2. You are using fgets after a scanf. scanf leaves the newline and other whitespace characters on the stream. When fgets is called right after that, fgets reads just the whitespace and the newline. You need to add code to ignore the rest of the line after the call to scanf and before the call to fgets.

    // Skip everything up to and including the newline.
    int c;
    while ( (c = getc(stdin)) != EOF && c != '\n');
    

    after that,

    fgets(vet[cont+1].nome, sizeof(vet[cont+1].nome), stdin);
    

    should read the data correctly.

  3. You are using the wrong value in the line:

    scanf("%d", &vet[cont+1].cpf);
    

    cpf is an array on ints. If you want to read just one int, you can use:

    scanf("%d", &vet[cont+1].cpf[0]);
    
  4. You are using the wrong format specifier in the line:

    scanf("%d", &vet[cont+1].renda_m);
    

    It should be:

    scanf("%f", &vet[cont+1].renda_m);
        // ^^ %f not %d
    
  5. You are using the wrong index to access the array vet. Everywhere you use vet[cont+1], it should be vet[cont]. By using vet[cont+1], you are not using the first element of the array, vet[0], and accessing memory beyond what you allocated for when by accessing vet[num].

If you fix the above problems, your program might work.

1
On

the following code:

1) corrects all the problems I listed in the comments.

2) drops some of the functionality of the OPs posted code,

Due notice the usage of a while( getchar() ... loop to clean the stdin of any remaining white space.

3) will still fail if the user tries to enter any white space in the nome field

4) the code always checks for errors

5) the code always cleans up (with 'free( vet );' before exiting

when compiling, always enable all the warnings, (for gcc, at a minimum, use '-Wall -Wextra -pedantic')

#include <stdio.h>
//#include <conio.h> // not portable, do not use
#include <stdlib.h>

/*
Programa realiza uma alocacao dinamica por meio
de uma funcao que recebe a dimensao e retorna o vetor(ponteiro)
*/

#define NUM_CPF      (11)
#define MAX_NOME_LEN (50)

struct CLIENTES
{
    int ano_nasc;
    int cpf[NUM_CPF];
    float renda_m;
    char nome[ MAX_NOME_LEN ];
}; //Lista de Objetos


int main(void)
{
    //Declaracao de Variaveis
    int cont=0;
    int num;
    int client;
    int i;
    int j;
    struct CLIENTES *vet = NULL;

    //Leitura de Dados
    printf("Digite o numero de Clientes: ");
    if( 1 != scanf("%d", &num) )
    { // scanf failed
        perror( "scanf for num failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, scanf successful

    // clear stdin
    while( getchar() != '\n' );

    if( NULL == (vet = malloc(num*sizeof(struct CLIENTES)) ) )
    { // then malloc failed
        perror( "malloc for multiple struct CLIENTES failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, malloc successful

    while (cont != num)
    {
        printf("\nNome: ");
        fflush(stdout);
        if( NULL == fgets(vet[cont].nome, MAX_NOME_LEN, stdin) )
        { // fgets failed
            perror( "fgets failed" );
            free( vet );
            exit( EXIT_FAILURE );
        }

        // implied else, fgets successful

       // clear stdin
       //while( getchar() != '\n' );

        printf("\nAno de Nascimento: ");
        if( 1 != scanf("%d", &vet[cont].ano_nasc) )
        { // scanf failed
            perror( "scanf for ano_nasc failed" );
            free( vet );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf successful

        printf("\nCPF: ");
        if( 1 != scanf("%d", vet[cont].cpf) )
        { // scanf failed
            perror( "scanf for cpf failed" );
            free( vet );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf successful

        printf("\nRenda Mensal: ");
        if( 1 != scanf("%f", &vet[cont].renda_m) )
        { // scanf failed
            perror( "scanf for renda_m failed" );
            free( vet );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf successful

        // clear stdin
        while( getchar() != '\n' );

        cont++;
    } // end while



    for (i=0;i<num;i++)
    {
        printf("\nO que deseja saber sobre ele?\n");
        printf("1-Nome\n2-Ano de Nascimento\n3-CPF\n4-Renda Mensal\n\n\n");
        if( 1 != scanf("%d", &client) )
        { // scanf failed
            perror( "scanf for client failed" );
            free( vet );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf successful

        switch( client )
        {
        case 1:
            printf("Nome: %49s", vet[i].nome );
            break;

        case 2:

            printf("Ano de Nascimento: %d", vet[i].ano_nasc );
            break;

        case 3:
            for(j=0; j< NUM_CPF; j++)
            {
                printf("CPF[%d] =  %d", j, vet[i].cpf[j]);
            }
            printf( "\n" );
            break;

        case 4:
            printf("Renda Mensal: %f", vet[i].renda_m );
            break;

        default:
            printf("ERROR: invalid client value, range 1...4\n");
            break;
        }; // end switch
    } // end for

    //Finalizando o Programa
    printf("\n\nFim do Programa!");
    free( vet );
    system( "pause" );
    return 0;
} // end function: main
0
On

One more version, with loops and functional.

#include <stdio.h>
//#include <conio.h> // not portable, do not use
#include <stdlib.h>

/*
Programa realiza uma alocacao dinamica por meio
de uma funcao que recebe a dimensao e retorna o vetor(ponteiro)
*/

#define NUM_CPF      (11)
#define MAX_NOME_LEN (50)

struct CLIENTES
{
    int ano_nasc;
    int cpf[NUM_CPF];
    float renda_m;
    char nome[ MAX_NOME_LEN ];
}; //Lista de Objetos

void soErros(char erro[20]){

    perror(erro);
    exit( EXIT_FAILURE );

}

int main(void)
{
    //Declaracao de Variaveis
    int cont=0;
    int num;
    int client, saida;
    int i;
    int j;
    int k;
    struct CLIENTES *vet = NULL;

    //Leitura de Dados
    printf("Digite o numero de Clientes: ");
    if( 1 != scanf("%d", &num) )
    { // scanf failed
        soErros("scanf for num failed" );
    }

    // implied else, scanf successful

    // clear stdin
    while( getchar() != '\n' );

    if( NULL == (vet = malloc(num*sizeof(struct CLIENTES)) ) )
    { // then malloc failed
        soErros("malloc for multiple struct CLIENTES failed");
    }

    // implied else, malloc successful

    while (cont != num)
    {
        printf("\nNome: ");
        fflush(stdout);
        if( NULL == fgets(vet[cont].nome, MAX_NOME_LEN, stdin) )
        { // fgets failed
            soErros("fgets failed");
        }

        // implied else, fgets successful

       // clear stdin
       //while( getchar() != '\n' );

        printf("\nAno de Nascimento: ");
        if( 1 != scanf("%d", &vet[cont].ano_nasc) )
        { // scanf failed
            soErros("scanf for ano_nasc failed");
        }

        // implied else, scanf successful

        printf("\nCPF: ");
        if( 1 != scanf("%d", vet[cont].cpf) )
        { // scanf failed
            soErros("scanf for cpf failed");
        }

        // implied else, scanf successful

        printf("\nRenda Mensal: ");
        if( 1 != scanf("%f", &vet[cont].renda_m) )
        { // scanf failed
            soErros("scanf for renda_m failed");
        }

        // implied else, scanf successful

        // clear stdin
        while( getchar() != '\n' );

        cont++;
    } // end while
    int escolha = 0;
    do{

        int *esc = &escolha;
        printf("\nDeseja saber sobre qual cliente?: ");

        for (i=0;i<num;i++)
        {
            printf("\n%d --- %s",i , vet[i].nome);
        } // end for

        if( 1 != scanf("%d", &esc) )
        { // scanf failed
            soErros("scanf for ano_nasc failed");
        } // end if

        printf("\nVocê escolheu o cliente %s", vet[escolha].nome);

        for(i=0;i<num;i++)
        {
            if(i == escolha){
                printf("\n0-Sair\n1-Nome\n2-Ano de Nascimento\n3-CPF\n4-Renda Mensal\n");
                if( 1 != scanf("%d", &client) )
                { // scanf failed
                    soErros("scanf for client failed");
                }

                // implied else, scanf successful

                switch( client )
                {
                case 0:
                    printf("Saindo do menu");
                    break;
                case 1:
                    printf("Nome: %49s", vet[i].nome );
                    break;

                case 2:

                    printf("Ano de Nascimento: %d", vet[i].ano_nasc );
                    break;

                case 3:
                    printf("CPF = ");
                    for(j=0; j< NUM_CPF; j++)
                    {
                        printf("%d", vet[i].cpf[j]);
                    }
                    printf( "\n" );
                    break;

                case 4:
                    printf("Renda Mensal: %f", vet[i].renda_m );
                    break;

                default:
                    printf("ERROR: invalid client value, range 1...4\n");
                    system("cls || clear");
                    break;
                }; // end switch
                printf( "\n" );
            } // end if
        } //end for
        printf("Continuar[1]\nSair[0]\n: ");
        if( 1 != scanf("%d", &saida) )
        {
            soErros("Erro de continuidade");
        } // end if

        switch( saida )
        {
        case 0:
            break;
        }
    } // end do
    while (saida);

    //Finalizando o Programa
    printf("\nFim do Programa!\n");
    free( vet );
    system( "pause" );
    return 0;
} // end function: main