0

Is there away in which I can get input in one scanf where the user only needs to type a sequence of numbers (separated by something if needed like \n or' '). And it would be automatically stored in the array. The same way there is a possibility in strings? Someone has mentioned to me . %d... with three dots that it's equivalent to %s both in scanf. Is it true?

I haven't seen any similar questions. I think they are simply talking about getting string array. I am talking about int array at once.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
bilanush
  • 139
  • 8
  • 1
    Possible duplicate of [How to read / parse input in C? The FAQ](https://stackoverflow.com/questions/35178520/how-to-read-parse-input-in-c-the-faq) – Yunnosch Apr 22 '18 at 21:00
  • In what way are they similar to my question? I am asking about getting multiple numbers and storing them in INT array not string. For example by using d with three dots. Not sure how those questions you mentioned are related in any way. – bilanush Apr 22 '18 at 21:03
  • Is [this answer](https://stackoverflow.com/questions/6922159/variadic-scanf-in-c/6922290#6922290) useful? – Weather Vane Apr 22 '18 at 21:09
  • Maybe I am missing something but it looks like string. Am asking about int array. Thx. Would appreciate help.. – bilanush Apr 22 '18 at 21:17

2 Answers2

2

I think the answer to your question is no. (but I am wrong see below)

In C you really need to define everything very explicitly.

So if You want 5 numbers in an array you could

scanf("%d %d %d %d %d", array[0], array[1],array[2],array[3],array[4]);

but this is fragile as if the format was not exactly that it would be difficult.

For what you want to achieve I would suggest reading in a whole line as a string and then processing the string to see how many numbers are in it and putting them in your array....

I am wrong in my initial assumption because since C99 there is this function called vscanf, which looks like it does exactly what you need.

I suggest you look at this question which really goes through it for vscanf, but for me I really think even vscanf could be a bit fragile and it would be better to read in data as string line by line using fgets to get data from stdin that will read everything into a string from the keyboard when you hit return provided the keyboard entry does not overflow the number of characters you indicate as a maximum - you can then use sscanf or other functions to scan through the string to pick up the numbers.

tom
  • 1,303
  • 10
  • 17
  • Thank you very much for understanding what I am asking and answering to the point. Only if you can add on something I was told which could be wrong totally. That writing scanf (%do. .. , arr) with three dots and then typing sequence of numbers would enter them accordingly automatically in arr [0] arr [1] etc.. is it true or false? Thursday. – bilanush Apr 22 '18 at 21:16
  • @bengy --- I think it is false - I have never seen anything like it,,, but `vscanf` is something you should look at... I am editing my answer now – tom Apr 22 '18 at 21:18
  • 1
    It is false. . . – rici Apr 22 '18 at 21:19
  • Oh yeah thank you both. Indeed I think it's false. As to the vscanf it isn't clear to me. But anyways. Thank you. – bilanush Apr 22 '18 at 21:45
  • Oh yeah thank you both. Indeed I think it's false. As to the vscanf it isn't clear to me. But anyways. Thank you. – bilanush Apr 22 '18 at 21:45
0

You can quite easily implement such a function yourself.

Let's steal the interface (mostly) from POSIX.1 getline(), as it is known to work well. So:

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

size_t get_ints(int **dataptr, size_t *sizeptr, FILE *in)
{
    int    *data;
    size_t  size, used = 0;
    int     value;

    /* Invalid parameters? None may be NULL. */
    if (!dataptr || !sizeptr || !in) {
        errno = EINVAL;
        return 0;
    }

    /* Has an error in the input stream already occurred? */
    if (ferror(in)) {
        errno = EIO;
        return 0;
    }

    /* Has data already been allocated? */
    if (!*dataptr || !*sizeptr) {
        /* No, not yet. */
        *dataptr = NULL;
        *sizeptr = 0;
    }
    data = *dataptr;
    size = *sizeptr;

    /* Read loop. */
    while (1) {

        /* Try reading one int. */
        if (fscanf(in, " %d", &value) != 1)
            break;

        /* Have one. Make sure data array has room for value. */        
        if (used >= size) {
            /* Reallocation policy. We need at least size = used + 1,
               but realloc() calls are relatively slow, so we want
               to allocate in larger chunks. This is just one typical
               policy. */
            if (used < 255)
                size = 256; /* Minimum allocation is 256 ints. */
            else
            if (used < 1048575)
                size = (3 * used) / 2;  /* Grow by 50% ... */
            else
                size = (used | 1048575) + 1048577; /* up to 1048576, after which round up to next multiple of 1048576. */

            data = realloc(data, size * sizeof data[0]);
            if (!data) {
                /* Note: original data in *data still exists! */
                errno = ENOMEM;
                return 0;
            }

            *dataptr = data;
            *sizeptr = size;
        }

        /* Append to array. */
        data[used++] = value;
    }

    /* An actual I/O error? */
    if (ferror(in)) {
        errno = EIO;
        return 0;
    }

    /* No, either an end of stream, or the next stuff
       in the stream is not an integer. 
       If used == 0, we want to ensure the caller knows
       there was no error. For simplicity, we avoid that
       check, and simply set errno = 0 always. */
    errno = 0;
    return used;
}

The interface to the above get_ints() function is simple: it takes a pointer to a dynamically allocated array, a pointer to the size (in ints) allocated for that array, and the stream handle, and returns the number of ints read from the stream. If an error occurs, it returns 0 with errno set to indicate the error. (getline() returns -1 instead.)

If no error occurs, this particular implementation sets errno = 0, but do note that this behaviour is uncommon; normally, you can only expect errno to have a valid error number when the function returns the error code (usually -1, but zero for this function).

The way you use this function is very easy. For example, let's assume you want to read an array of ints from the standard input:

int main(void)
{
    int    *iarray = NULL; /* No array allocated yet, */
    size_t  isize  = 0;    /* so allocated size is zero, and */
    size_t  icount = 0;    /* no ints in it yet. */

    icount = get_ints(&iarray, &isize, stdin);
    if (!icount) {
        /* No ints read. Error? */
        if (errno)
            fprintf(stderr, "Error reading from standard input: %s.\n", strerror(errno));
        else
            fprintf(stderr, "No integers in standard input.\n");
        return EXIT_FAILURE;
    }

    printf("Read %zu integers from standard input.\n", icount);

    /*
     *  Do something with the integers...
    */

    /* Discard the dynamically allocated array. */
    free(iarray);
    iarray = NULL;
    isize  = 0;
    icount = 0;

    return EXIT_SUCCESS;
}

Note that as long as you initialize your iarray = NULL and isize = 0 when declaring it, the get_ints() function will allocate as much memory as is needed for the ints it reads. It is also then always safe to do free(iarray); iarray = NULL; isize = 0; to discard the array, even if iarray was NULL, because free(NULL) is safe to do (does nothing).

This is an excellent way of doing memory management in C. If you do it this way -- initialize your pointers to NULL, then free() them and reset them to NULL after they are no longer needed -- your programs won't have memory leaks or crash due to use-after-free or similar bugs. Many instructors won't bother, because they erroneously think that sort of carefulness can be tacked on later, if necessary.

(Do note, however, that even in the above program, in the error cases where the program is about to abort/exit/return, there is no such cleanup done. This is because the operating system will release all resources automatically. [Except for shared memory and filesystem objects.] Simply put, if your program is guaranteed to exit, it is not necessary to free dynamically allocated memory.)

Nominal Animal
  • 38,216
  • 5
  • 59
  • 86