Reading Struct Strings with Wrong Scanf

Asked

Viewed 1,105 times

0

Good guys, I am developing a C code that performs data registration in files. However, I have a problem in the function register, which you will see below among the codes.

Struct of the client:

typedef struct
{
        int idCliente;
        char nome[NOME_TAM_MAX];
        char CPF[16];
        char endereco[ENDERECO_TAM_MAX];    
}Cliente;

Macros:

#define NOME_TAM_MAX 51
#define ENDERECO_TAM_MAX 101

Function register:

void cadastrarCliente (void)
{
        Cliente *newCliente = (Cliente *) malloc(sizeof(Cliente));
        if (!newCliente)
        {
                printf("ERRO DE MEMORIA!!!\n");
                exit(-1);
        }
        else
        {
                printf("\n--- PRENCHA OS DADOS DE CADASTRO DO CLIENTE ---\n\n");
                printf("Digite o ID do cliente: ");
                scanf(" %d", &newCliente->idCliente);
                printf("Digite o nome do cliente: ");
                scanf(" %s", newCliente->nome);
                printf("Digite o CPF do cliente: ");
                scanf(" %s", newCliente->CPF);
                printf("Digite o endereco do cliente: ");
                scanf(" %s", newCliente->endereco);

                stream = fopen("cliente.txt", "w+b"); // stream é global
                if (!stream)
                {
                        fputs("ERRO AO TENTAR LER ARQUIVO!!!\n", stderr);
                        exit(-1);
                }
                else
                {
                        fwrite(newCliente, sizeof(Cliente), 1, stream);
                        fclose(stream);
                }
        }

        return;
}

The error is as follows, after typing the client name and hit enter, all other attributes are skipped (showing only the contents of the printf) and the function comes to an end. I inverted the fields, putting the CPF first and then address, after reading the CPF, everything happens successful, but the error repeats when reading the address as well.

  • 3

    The name you are putting has spaces ? Remember that scanf("%s reads only one word, leaving the rest in the input stream. If you want to read an entire line, switch to scanf("%[^\n]

  • It does have spaces, but I thought that this problem could be solved by giving a spacing inside the scanf, as it is in the code. I tried to use it as you suggested, but it doesn’t work.

  • Give an example of the input type you are reading, to be able to say the appropriate way to read it

  • Yuri Coelho Rosario

  • Each of these would be placed at a time separated by enter ? Or would seperation be by the commas ? Your code interprets 1 number followed by 3 texts. I don’t see how this fits in the example you gave

  • The separation would be through enter, after enter, passes to the next. In this case, the first entry is any number, the second the full name, the third the CPF and the fourth the full address.

Show 1 more comment

3 answers

1


I would like to begin by reiterating what I have already said:

It is worth remembering that scanf("%s reads only one word, leaving the rest in the input stream. If you want to read an entire line, switch to scanf("%[^\n]

However, this is the generic example. Looking at your particular case, you get an integer read before, so you’re going to get a line break for reading after the first number, which is going to be the one that gets caught right after you do scanf("%[^\n]. The solution is simply to consume this break with a small space:

scanf(" %[^\n]",
//     ^--aqui

Taking this into account could rewrite your reading code so:

printf("Digite o ID do cliente: ");
scanf("%d", &newCliente->idCliente);
printf("Digite o nome do cliente: ");
scanf(" %[^\n]", newCliente->nome); //mais que uma palavra
printf("Digite o CPF do cliente: ");
scanf(" %s", newCliente->CPF); //uma palavra
printf("Digite o endereco do cliente: ");
scanf(" %[^\n]", newCliente->endereco); //mais que uma palavra

See this example working on Ideone

Another alternative would be to read with fgets that would even be safer, but that has its implications. One of them would be that the fgets leaves the line break read inside the string. In this case I did not suggest it because when using fgets as a general rule it is more appropriate to take all readings with fgets and not interspersed with scanf, which can complicate a little.

Here is another answer I gave that details the reading with fgets: problem-with-gets-e-fgets

  • This time it worked. Thank you very much for the solution and the explanation, Isac. I read the answer in another topic about fgets and now it’s all clear to me. Hugs!

0

Try using scanf(" n %s"), because if not it will read only one string and leave the others behind. And if your name to insert has spaces scanf does not crease, because it closes the reading in the first space or bar 0, if this is your problem try using fgets.

  • I tried as you suggested, but it didn’t work. I thought fgets didn’t read from the keyboard, only from files.

0

Good evening Yuri, I tested your code and apparently managed to solve the problem as follows:

printf("\n--- PRENCHA OS DADOS DE CADASTRO DO CLIENTE ---\n\n");
    printf("Digite o ID do cliente: ");
    scanf(" %d", &newCliente->idCliente);

    fflush(stdin);

    printf("Digite o nome do cliente: ");
    fgets(newCliente->nome,51,stdin);

    fflush(stdin);

    printf("Digite o CPF do cliente: ");
    fgets(newCliente->CPF,16,stdin);

    fflush(stdin);

    printf("Digite o endereco do cliente: ");
    fgets(newCliente->endereco,101,stdin);

I used the fflush(stdin) to clear the buffer, avoiding skipping the fields that come after, in addition it was possible to capture the strings by keyboard using the fgets()

  • Hi Rogi, good night. I didn’t know that fgets read from the keyboard, I just thought it was to read from the archive, that’s good to know. But well, the solution presented did not work, now the name field is being skipped after presenting the ID.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.