1

I am getting the user to input 4 numbers. They can be input: 1 2 3 4 or 1234 or 1 2 34 , etc. I am currently using

int array[4];
scanf("%1x%1x%1x%1x", &array[0], &array[1], &array[2], &array[3]);

However, I want to display an error if the user inputs too many numbers: 12345 or 1 2 3 4 5 or 1 2 345 , etc.

How can I do this?

I am very new to C, so please explain as much as possible.

//

Thanks for your help. What I have now tried to do is:

char line[101];
    printf("Please input);
    fgets(line, 101, stdin);
    if (strlen(line)>5)
    {
        printf("Input is too large");
    }
    else
    {
        array[0]=line[0]-'0'; array[1]=line[1]-'0'; array[2]=line[2]-'0'; array[3]=line[3]-'0';
        printf("%d%d%d%d", array[0], array[1], array[2], array[3]);
    }

Is this a sensible and acceptable way? It compiles and appears to work on Visual Studios. Will it compile and run on C?

3
  • 2
    Yes you can. Perhaps not by using scanf. Commented Dec 30, 2013 at 16:50
  • Get each input in a loop and count the number of the input Commented Dec 30, 2013 at 17:00
  • Read each line using fgets like you are doing, but then use sscanf on the line with something like "sscanf(line, "%d %d %d %d %c", &num1, &num2, &num3, &num4, &dummy)" where dummy is a dummy char variable. If the return value is 4, then you successfully got 4 numbers. If it's 5 you've got too many. Commented Dec 30, 2013 at 19:28

6 Answers 6

1

OP is on the right track, but needs adjust to deal with errors.

The current approach, using scanf() can be used to detect problems, but not well recover. Instead, use a fgets()/sscanf() combination.

char line[101];
if (fgets(line, sizeof line, stdin) == NULL) HandleEOForIOError();
unsigned arr[4];
int ch;
int cnt = sscanf(line, "%1x%1x%1x%1x %c", &arr[0], &arr[1], &arr[2],&arr[3],&ch);
if (cnt == 4) JustRight();
if (cnt < 4) Handle_TooFew();
if (cnt > 4) Handle_TooMany();  // cnt == 5 

ch catches any lurking non-whitespace char after the 4 numbers.
Use %1u if looking for 1 decimal digit into an unsigned.
Use %1d if looking for 1 decimal digit into an int.


OP 2nd approach array[0]=line[0]-'0'; ..., is not bad, but has some shortcomings. It does not perform good error checking (non-numeric) nor handles hexadecimal numbers like the first. Further, it does not allow for leading or interspersed spaces.

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

2 Comments

This appears to be working! Thank you! Is it okay to ask the user to input in the main(void) and then check whether their input is valid in a function?
@user3139744 Yes - an excellent way to proceed. Note: user input is evil, best to only used after it has been vetted.
1

Your question might be operating system specific. I am assuming it could be Linux.

You could first read an entire line with getline(3) (or readline(3), or even fgets(3) if you accept to set an upper limit to your input line size) then parse that line (e.g. with sscanf(3) and use the %n format specifier). Don't forget to test the result of sscanf (the number of read items).

So perhaps something like

int a=0,b=0,c=0,d=0;
char* line=NULL;
size_t linesize=0;
int lastpos= -1;
ssize_t linelen=getline(&line,&linesize,stdin);
if (linelen<0) { perror("getline"); exit(EXIT_FAILURE); };
int nbscanned=sscanf(line," %1d%1d%1d%1d %n", &a,&b,&c,&d,&lastpos);
if (nbscanned>=4 && lastpos==linelen) {
  // be happy
  do_something_with(a,b,c,d);
}
else {
  // be unhappy
  fprintf(stderr, "wrong input line %s\n", line);
  exit(EXIT_FAILURE);
}
free(line); line=NULL;

And once you have the entire line, you could parse it by other means like successive calls of strtol(3).

Then, the issue is what happens if the stdin has more than one line. I cannot guess what you want in that case. Maybe feof(3) is relevant.

I believe that my solution might not be Linux specific, but I don't know. It probably should work on Posix 2008 compliant operating systems.

Be careful about the result of sscanf when having a %n conversion specification. The man page tells that standards might be contradictory on that corner case.

If your operating system is not Posix compliant (e.g. Windows) then you should find another way. If you accept to limit line size to e.g. 128 you might code

char line[128];
memset (line, 0, sizeof(line));
fgets(line, sizeof(line), stdin);
ssize_t linelen = strlen(line);

then you do append the sscanf and following code from the previous (i.e. first) code chunk (but without the last line calling free(line)).

1 Comment

Last time I checked, fgets(3) does not set errno. Therefore calling perror afterwards does not really make sense. Also, fgets returns EOF on error, it does not return 0
0

What you are trying to get is 4 digits with or without spaces between them. For that, you can take a string as input and then check that string character by character and count the number of digits(and spaces and other characters) in the string and perform the desired action/ display the required message.

Comments

0

You can't do that with scanf. Problem is, there are ways to make scanf search for something after the 4 numbers, but all of them will just sit there and wait for more user input if the user does NOT enter more. So you'd need to use gets() or fgets() and parse the string to do that.

3 Comments

No gets: it is deprecated (since dangerous because of buffer overflow) and has been removed from latest standards!
Saying gets() now is almost like swearing in C
I'm afraid i reached the age when people hear me swearing, they don't try to correct me, they just smile and say the old man doesn't know any better.
0

It would probably be easier for you to change your program, so that you ask for one number at a time - then you ask 4 times, and you're done with it, so something along these lines, in pseudo code:

i = 0
while i < 4
ask for number
scanf number and save in array at index i

Comments

0

E.g

#include <stdio.h>

int main(void){
    int array[4], ch;
    size_t i, size = sizeof(array)/sizeof(*array);//4  

    i = 0;
    while(i < size){
        if(1!=scanf("%1x", &array[i])){
             //printf("invalid input");
             scanf("%*[^0123456789abcdefABCDEF]");//or "%*[^0-9A-Fa-f]"
        } else {
            ++i;
        }
    }
    if('\n' != (ch = getchar())){
        printf("Extra input !\n");
        scanf("%*[^\n]");//remove extra input
    }
    for(i=0;i<size;++i){
        printf("%x", array[i]);
    }
    printf("\n");
    return 0;
}

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.