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?

user3139744
  • 125
  • 1
  • 1
  • 6
  • 2
    Yes you can. Perhaps not by using scanf. – Noufal Ibrahim Dec 30 '13 at 16:50
  • Get each input in a loop and count the number of the input – Polymorphism Dec 30 '13 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. – Brandin Dec 30 '13 at 19:28

6 Answers6

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)).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • 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 – Brandin Dec 30 '13 at 19:25
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.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
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.

Akshat Singhal
  • 1,801
  • 19
  • 20
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.

Guntram Blohm
  • 9,667
  • 2
  • 24
  • 31
  • No [gets](http://man7.org/linux/man-pages/man3/gets.3.html): it is *deprecated* (since **dangerous** because of [buffer overflow](http://en.wikipedia.org/wiki/Buffer_overflow)) and has been removed from latest standards! – Basile Starynkevitch Dec 30 '13 at 17:16
  • Saying gets() now is almost like swearing in C – Brandin Dec 30 '13 at 19:22
  • 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. – Guntram Blohm Dec 30 '13 at 19:39
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
Jesper Bangsholt
  • 544
  • 4
  • 11
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;
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70