Check if user input into an array is too long?

前端 未结 6 2114
执笔经年
执笔经年 2021-01-24 18:19

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\", &ar         


        
相关标签:
6条回答
  • 2021-01-24 18:36

    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;
    }
    
    0 讨论(0)
  • 2021-01-24 18:43

    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.

    0 讨论(0)
  • 2021-01-24 18:57

    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.

    0 讨论(0)
  • 2021-01-24 18:57

    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
    
    0 讨论(0)
  • 2021-01-24 19:01

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

    0 讨论(0)
  • 2021-01-24 19:01

    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.

    0 讨论(0)
提交回复
热议问题