1

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;
}
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
Gabriel
  • 763
  • 1
  • 10
  • 28
  • 3
    Why did you malloc(num*sizeof(int))? Each element is sizeof(struct CLIENTES), not sizeof(int). – jarmod Jun 18 '15 at 02:41
  • 1
    `vet = (CLIENTES*)malloc(num*sizeof(int));` should be such as `vet = (CLIENTES*)malloc(num*sizeof(*vet));` and `fgets(vet[cont+1].nome, sizeof(vet[cont+1].nome), stdin);` remove `+1`. – BLUEPIXY Jun 18 '15 at 02:42
  • Thank you guys for the help, but I made all the modifications and the program still cannot read my fgets. – Gabriel Jun 18 '15 at 02:45
  • 2
    `scanf("%d", &num);` --> `scanf("%d%*c", &num);` `%*c` for consume newline. – BLUEPIXY Jun 18 '15 at 02:47
  • `printf("CPF: %d", vet[num_2].cpf[j]);` but read one time (`scanf("%d", &vet[cont+1].cpf);`) – BLUEPIXY Jun 18 '15 at 02:50
  • @BLUEPIXY that was a good one, thank you! Now I can read the string, but when I try to print it out, it doesn't work. – Gabriel Jun 18 '15 at 02:51
  • `if(num_2 == num)` this never be true. So never print – BLUEPIXY Jun 18 '15 at 02:52
  • @BLUEPIXY I'm gonna change it! Thank you for the help, do you know why I cannot print the string that I read with fgets? – Gabriel Jun 18 '15 at 02:58
  • `sizeof` doesn't work for malloced memory. – ooga Jun 18 '15 at 03:01
  • 1) in C, do not cast the returned value from malloc (and family) 2) always check (!=NULL) the returned value to assure the operation was successful. – user3629249 Jun 18 '15 at 05:13
  • the malloc needs to acquire a pointer to an item that the size of struct CLIENTES, not 'num* sizeof(int)' – user3629249 Jun 18 '15 at 05:15
  • there is no type named 'CLIENTES'. However there is a type 'struct CLIENTES' suggest replace all 'CLIENTES' with 'struct CLIENTES' – user3629249 Jun 18 '15 at 05:18
  • when calling scanf (and family) always check the returned value (not the parameters) to assure the operation was successful. – user3629249 Jun 18 '15 at 05:20
  • for readability/clarity/maintainability for us humans, only declare one variable per line – user3629249 Jun 18 '15 at 05:23
  • if num_2 == num, then the vet[num_2] will be beyond the end of the malloc'd memory area. This is undefined behaviour and can/will lead to a seg fault event. Suggest: if( num_2 >=0 && num_2 < num) – user3629249 Jun 18 '15 at 05:36
  • the 'nome' field is a multi character array. so this line: 'printf("Nome: %c", vet[num_2].nome );' (because in C, an array name degrades to a pointer to the array) will not compile. Suggest: printf("Nome: %s", vet[num_2].nome ); I.E. use the string format not a char format – user3629249 Jun 18 '15 at 05:39
  • there are some 'magic' numbers in the code that will greatly increase the difficulty of debugging/performing maintenance. Suggest #define, with meaningful names, the numbers (11) and (50) and use those meaningful names through out the code – user3629249 Jun 18 '15 at 05:46
  • when entering the int 'client', either check it for a valid range (1...4) and loop to retry if not a valid range -- or -- in the string of if/else if statements, add a final else that prints an error message. Suggest using a 'switch' statement, with the 'default' case displaying the error message – user3629249 Jun 18 '15 at 05:48
  • the index value: 'cont+1]' will, on the last itteration, access beyond the bounds of the malloc'd memory, This is undefined behaviour and can/will lead to a seg fault event. – user3629249 Jun 18 '15 at 05:56
  • only the first entry in the .cpf[] array is being input, but the output is trying output all 11 integers, so will be outputting one real integer and 10 garbage integers. 'cpf[]' is an array, in C an array name degrades to the address of the array, so this line: 'scanf("%d", &vet[cont].cpf)' will fail to cleanly compile, suggest: 'scanf("%d", vet[cont].cpf)' I.E. not '&' on the parameter name – user3629249 Jun 18 '15 at 05:58
  • regarding this line: 'scanf("%d", &vet[cont].renda_m)' renda_m is declared as a float, so this line will fail to cleanly compile. suggest: 'scanf("%f", &vet[cont].renda_m)' I.E. use the %f format/conversion specifier for a float variable – user3629249 Jun 18 '15 at 06:02

3 Answers3

1

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.

Community
  • 1
  • 1
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Thank you for the help, I had fixed some points you just said but right now I cannot print the string I just wrote and I dont know why, any idea? – Gabriel Jun 18 '15 at 03:09
  • 1
    @GabrielMello, it might be better to start a new question after including my suggested fixes in your code. – R Sahu Jun 18 '15 at 03:12
  • 2
    Another problem (perhaps the main problem) is that he does `scanf("%d"` followed by `fgets` without cleaning up the newline – M.M Jun 18 '15 at 06:55
  • @MattMcNabb That was the problem! Thank you so mcuh for the help! – Gabriel Jun 18 '15 at 19:18
1

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
user3629249
  • 16,402
  • 1
  • 16
  • 17
  • Thank you! I used " fflush (stdin ) " at the beginning of the loop and now the code is working just fine ! – Gabriel Jun 18 '15 at 19:21
0

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
Martino
  • 1
  • 3