Receive more than one value per line with C

Asked

Viewed 57 times

-1

I need to make a code where it is necessary to receive more than one value per line, however I do not know how many values

The initial idea would be to use

scanf("%d", valor);

However, in that case I would only be receiving a value, and it may be 1, 2, 3, 4...

In fact, the user will give me the dimensions of an array and their numbers, I need to read one number at a time, but everything will be "delivered" on the same line, for example:

1 2 3
5 3 1
4 4 1

How to solve this?

  • But how many numbers are in total ? How do you know when to stop ?

  • The scanf can read more than one value per line, since it does not consume the line break if it does not find it necessary. Then simply call several times in a loop, but it is not yet clear what the criteria for stopping

  • at the beginning it will give the amount of columns, so if it is 4 columns it would be 4 numbers

  • So I suggest [Dit] the question and put all these details in the text. So people don’t need to "hunt" information in the comments. But anyway, if you have the amount, just wear a bow and go reading...

1 answer

2

There are many ways to read this but I find it always boring.

As the matrix is int help a little, and I’ll show you a way.

The logic

If you didn’t know how many columns there were until the guy typed the whole line and hit ENTER then you’d have to count the fields and see how many were in the first row.

From there would know how many columns were and in the next rows would be solved.

To count the fields you can read the whole line with fgets(), the simple because then you don’t have to worry about anything else.

Example

If you read the line with fgets(linha,sizeof(linha),stdin); that loop

        char* p    = linha;
        char* next = NULL;
        unsigned nc = 0;
        printf("\n\nLinha: \"%s\"\n", teste[t]);
        while ((*p != 0))
        {
            long numero = strtol(p, &next, 10); 
            if ((next - p) == 0) break;
            p = next;
            printf("%ld  ", numero);
            nc += 1;
        }  // uma coluna
        printf("\nLeu %u campos nessa linha\n", nc);

will read fields 1 to 1 in numero and count in nc how many are.

I will leave a more complete example below.

The difference of reading with strtol() instead of scanf() is that in the first case the function was written with that in mind: strtol() can return a pointer to the string indicating how far it was consumed and so you can go through the string without testing the indexes and looking for the spaces and such.

scanf() and other family functions, such as sscanf(), on the other hand, they were written to consume tabular data and not "walk" along the line unless you are reading a file. But scanf() treats space, TAB and newline generic whitespace and you can’t tell if the line ended when reading a field because the function goes straight: everything is whitespace and cannot distinguish the newline. Only with fscanf() and when you have a delimiter, like a file csv, if you can use this and read easily, because you can test whether the field ended with the delimiter or with the newline, but that is not the case here: such a delimiter cannot be whitespace: nor TAB or space. It can be newline but then your problem would be another :).

An example in C

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "bloco.h"

int main(void)
{
    char* teste[] = // uns testes basicos
    {
        "nada",
        "1 2 3 4 5 6 7 8 9 10",
        "2147483647 -2147483648",
        "21474836472147483648",
        ""
    };

    for (int t = 0; teste[t][0] != 0; t += 1)
    {   // testa uma "linha" do vetor
        char* p    = teste[t];
        char* next = NULL;
        unsigned nc = 0;
        printf("Linha: \"%s\"\n", teste[t]);
        while ((*p != 0))
        {
            long numero = strtol(p, &next, 10);
            if ((numero == LONG_MAX) || (numero == LONG_MIN))
            {
                // e se o cara digitou isso mesmo?
                if (errno == ERANGE)
                {
                    perror("Erro na entrada");
                    break;
                }
            }
            if ((next - p) == 0) break;
            p = next;
            printf("%ld  ", numero);
            nc += 1;
        }  // uma coluna
        printf("\nLeu %u campos nessa linha\n\n", nc);
    };  // for
    return 0;
}

The program uses whatever you have in teste and rotate that loop I showed you.

    char* teste[] = // uns testes basicos
    {
        "nada",
        "1 2 3 4 5 6 7 8 9 10",
        "2147483647 -2147483648",
        "21474836472147483648",
        ""
    };

Every line of teste is like a line typed by the user and so is faster to test the hypotheses. The program stops when any error occurs (overflow of course, since a int has limit) or find an empty string, which is there at the end in the example. A common test technique.

the exit


Linha: "nada"

Leu 0 campos nessa linha

Linha: "1 2 3 4 5 6 7 8 9 10"
1  2  3  4  5  6  7  8  9  10
Leu 10 campos nessa linha

Linha: "2147483647 -2147483648"
2147483647  -2147483648
Leu 2 campos nessa linha

Linha: "21474836472147483648"
Erro na entrada: Result too large

Leu 0 campos nessa linha``none

Note that I left a complete error condition test. And the third line has the largest and smallest value possible to read. The English phrase is from the system saying that error gave in the fourth line because the number is WELL large...

How to put this on your show

How do you know how many columns are can declare an array of int and go placing the numbers of each line in the vector, using exactly the loop I showed you above.

    int colunas = 0;

If the program will read the total of columns just create the array then...

    int* linha = (int*) malloc(colunas * sizeof(int));

And you can allocate one for each row or if you know how many you can allocate direct, just by multiplying rows x columns...

I imagine your doubt isn’t in that part and I’ll focus on the topic.

  • Thank you very much! :)

Browser other questions tagged

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