0

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.

4
  • 1
    Don't tag a question that asks about "scanf() in C" with the C++ tag; it will only earn you opprobrium and downvotes. Commented Apr 17, 2022 at 23:52
  • 3
    Do you have in mind reading up to 5 integers from a single line? Remember that scanf() cares not in the slightest about newlines — they are just white space to be consumed. If you want line-based input, read the line (e.g. with standard C fgets() or POSIX getline()) and then parse it with sscanf(). And then you can check the return value from sscanf() to work out how many integers were read. The blanks in the format string are unnecessary (%d will skip white space anyway) but harmless. Commented Apr 17, 2022 at 23:56
  • @JonathanLeffler: Using fgets or getline violates OP's restriction of not being allowed to use arrays. However, violating this rule is probably unavoidable, as all 3 answers to this question (including my own) violate this rule. I am unable to think of any clean solultion which does not violate this rule. Commented Apr 18, 2022 at 0:56
  • 1
    @AndreasWenzel — ugh! Yes, there is no clean solution not using a character array to store the line. There are unclean solutions reading a character at a time and doing conversions as needed and so on — the function would have to be prepared to diagnose "blank/tab delimiter", "newline delimiter", "other delimiter" and EOF, as well as non-number and any other problems. Definitely not nice! But, using scanf() completely precludes control over newlines — the %d format skips leading white space (including newlines) regardless of what you'd like. Commented Apr 18, 2022 at 1:23

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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;
}

2 Comments

You should check that fgets() did not return NULL before using the result. It is often better (more nearly bullet-proof) to use line[strcspn(line, "\n")] = '\0'; to zap the newline at the end of the string — it works correctly if there is no newline, whereas what you've got zaps the last character of the string, which might not be a newline if the input line was too long.
Yep, you are totally right. I will fix it right away.
1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.