Home > Back-end >  How to take integer input with scanf in C without using arrays?
How to take integer input with scanf in C without using arrays?

Time:04-18

I want to take input like the following:

Write: 1 5 3

OR

Write: 1 2

OR

Write: 2 4 9 4

OR

Write: (press Enter directly)

However, problem is that I want to take max 5 integer or less. Therefore, I wrote this expression:

scanf("%d %d %d %d %d",&a,&b,&c,&d,&e);

When I did that, if I write integers, such as 1 4 6, the program continues to want integers until I complete the number of integers to 5.

Also, sometimes, I need to skip this part by pressing enter without writing an integer. But, I can not implement that.

I did that also:

 scanf("%d%c", &firstStore,&control);
    if(control==' ')
    {
        scanf("%d%c", &secondStore,&control);
        if(control==' ')
        {
            scanf("%d%c", &thirdStore,&control);
            if(control==' ')
            {
                scanf("%d%c", &fourthStore,&control);
                if(control==' ')
                {
                    scanf("%d", &fifthStore);
                }
            }
        }
    }

The problem with this code is that I can not skip this part if I want. I mean this code wants to take minimum one integer always.

RULE:

The usage of arrays is banned.

CodePudding user response:

I would suggest to get a whole line and then parse it:

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

int main() {
    char line[1024];
    if (fgets(line, 1024, stdin) == NULL) {
        perror("Error occured");
        return 2;
    }
    if (line[strlen(line)-1] != '\n') {
        while (getchar() != '\n');
    } else {
        line[strlen(line)-1] = '\0';
    }
    int counter = 0;
    for (char * word = strtok(line, " "); word; word = strtok(NULL, " ")) {
        int number = atoi(word);
        // do something with your number
        counter  ;
    }
    if (counter == 0) {
        return 1;
    }
    return 0;
}

CodePudding user response:

Check the return value of scanf().

From the man page of scanf :

On success, these functions return the number of input items successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early matching failure.

So your code should something like :?

#include <stdio.h>

int main(void)
{
    int n;

    while ((scanf("%d")) == 1) {
        /* perform actions */
    }


    return 0;
}

To implement the part in which you don't type anything, you have to use a function other than scanf(). Consider fgets() or getchar().

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

int main(void)
{
    int n;
    char buff[500];

    while (fgets(buff, sizeof buff, stdin) != NULL) {
        if (buff[0] == '\n') { /* empty - just newline character */
            continue;
        }

        if (sscanf(buff, "%d", &n) != 1) { /* unsuccessful conversion */
            exit(1);
        }

    }


    return 0;
}

This will work considering each line has a single number or you type a single number each time. If your line has multiple numbers, you will have to parse it differently, possibly by using strtok() or by modifying sscanf().

You can use the %n format and loop so you can check the whole string using sscanf().

From the man page for %n:

Nothing is expected; instead, the number of characters consumed thus far from the input is stored through the next pointer, which must be a pointer to int, or variant whose size matches the (optionally) supplied integer length modifier.

So you could replace the if block with something like:

    int char_read;
    int start = 0;

    while (start < sizeof(buff) && 
    sscanf(&buff[start], "%d%n", &n, &char_read) == 1) { /* 1 successful conversion */
        printf("%d\n", n);
        start  = char_read;
    }

Working example

CodePudding user response:

Like all of the other answers, the following solution violates the rule of not using arrays, because I cannot think of any clean solution to the problem which does not use them.

The problem with using scanf is that it will treat spaces and newline characters equally. This is not what you want.

For line-based user input, it makes more sense to always read one line at a time, and treat every line individually. In order to read one line of user input as a string, you can use the function fgets. You can then convert this string to numbers using the function sscanf or strtol.

Here is a solution that uses the function sscanf:

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

int main( void )
{
    for (;;) //infinite loop
    {
        char line[200];
        int numbers[5];
        int num_numbers;

        //prompt user for input
        printf( "Please enter up to 5 numbers: " );

        //attempt to read one line of input from user
        if ( fgets( line, sizeof line, stdin ) == NULL )
            break;

        //verify that line was not too long for input buffer
        if ( strchr( line, '\n' ) == NULL && !feof( stdin ) )
        {
            printf( "Line too long for input buffer!\n" );
            exit( EXIT_FAILURE );
        }

        //attempt to convert string to numbers
        num_numbers = sscanf(
            line,
            "%d %d %d %d %d",
            &numbers[0], &numbers[1], &numbers[2],
            &numbers[3], &numbers[4]
        );

        //print result
        if  ( num_numbers == 0 || num_numbers == EOF )
        {
            printf( "Was not able to match any numbers.\n" );
        }
        else
        {
            printf( "Successfully matched %d numbers:\n", num_numbers );
            for ( int i = 0; i < num_numbers; i   )
            {
                printf( "%d\n", numbers[i] );
            }
        }
        printf( "\n" );
    }
}

This program has the following behavior:

Please enter up to 5 numbers: 20 30 35 40
Successfully matched 4 numbers:
20
30
35
40

Please enter up to 5 numbers: 
Was not able to match any numbers.

Please enter up to 5 numbers: 12 17
Successfully matched 2 numbers:
12
17

Please enter up to 5 numbers: 5
Successfully matched 1 numbers:
5

Here is a solution which uses the function strtol instead of sscanf:

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

#define MAX_NUMBERS 5

int main( void )
{
    for (;;) //infinite loop
    {
        char line[200], *p = line, *q;
        long numbers[MAX_NUMBERS];
        int num_numbers = 0;

        //prompt user for input
        printf( "Please enter up to 5 numbers: " );

        //attempt to read one line of input from user
        if ( fgets( line, sizeof line, stdin ) == NULL )
            break;

        //verify that line was not too long for input buffer
        if ( strchr( line, '\n' ) == NULL && !feof( stdin ) )
        {
            printf( "Line too long for input buffer!\n" );
            exit( EXIT_FAILURE );
        }

        //convert as many numbers as possible
        for ( int i = 0; i < MAX_NUMBERS; i   )
        {
            numbers[i] = strtol( p, &q, 10 );
            if ( p == q )
                break;

            p = q;
            num_numbers  ;
        }

        //print result
        if  ( num_numbers == 0 )
        {
            printf( "Was not able to match any numbers.\n" );
        }
        else
        {
            printf( "Successfully matched %d numbers:\n", num_numbers );
            for ( int i = 0; i < num_numbers; i   )
            {
                printf( "%ld\n", numbers[i] );
            }
        }
        printf( "\n" );
    }
}

This second program has exactly the same output as the first program.

  • Related