1

for 0-9 range in scanset if string is input 12345thisisnice output is 12345 which is correct but for input thisisnice12345 output is a@ which is wrong I think,Why this is wrong ?

/* A simple scanset example */
#include <stdio.h> 

int main(void) 
{ 
    char str[128]; 

    printf("Enter a string: "); 
    scanf("%[9-0]s", str); 

    printf("You entered: %s\n", str); 

    return 0; 
} 

I expect o/p of thisisnice12345 as 12345 but actual o/p is a@

ZeppRock
  • 988
  • 1
  • 10
  • 22
hrishi007
  • 113
  • 2
  • 7

4 Answers4

3

Here is an improved version of your program:

#include <stdio.h> 

int main(void) 
{ 
    char str[128];

    printf("Enter a string: "); 
    if(scanf("%[0-9]", str) == 1)
         printf("You entered: \"%s\"\n", str);
    else printf("You entered nothing.\n");

    return 0; 
} 

The correct scanset is %[0-9], with the digits in order, and without the trailing s. (The trailing s was harmless in this case, but would have caused problems in other situations.) More importantly, if scanf returns 0, this indicates it matched nothing and so stored nothing in str.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
2

Your code has undefined behaviour. You are not initializing str and with your second input scanf is not reading any field ("thisisnice12345" does not start with a number), so not writing to str. If you are then printf-ing str, you are reading an uninitialized variable which is undefined behaviour.

You need to check the return value of scanf. str will only have been written to if scanf returns 1.

Werner Henze
  • 16,404
  • 12
  • 44
  • 69
1

scanf function family is not able to perform complex regex. But it has some capability. If you want to read the first number entered by user, you can use:

  • %[0-9] reads only a number (warning its 0-9, not 9-0)
  • %[^0-9] reads all but a number
  • %*[^0-9] reads all but a number and ignore it.

So you can write:

/* A simple scanset example */
#include <stdio.h> 

int main(void) 
{ 
    char str[128]; 
    int ret;

    printf("Enter a string: "); 

    /* Try to read a number at input start */
    ret = scanf("%[0-9]", str);     

    if (1 != ret){
        /* if reading failed, try to re-read the input, 
           ignoring all that is before the number */
        ret = scanf("%*[^0-9]%[0-9]", str); 
    }

    if (1 != ret)
        printf("no match");
    else
        printf("You entered: %s\n", str); 

    return 0; 
} 

As pointed in comments, this code can be better if read size is limited:

  • %8[0-9] will limit scanf to read only 8 numeric characters.


#include <stdio.h> 

int main(void) 
{ 
    char str[8+1]; 
    int ret;

    printf("Enter a string: "); 

    /* Try to read a number at input start */
    ret = scanf("%8[0-9]", str);     

    if (1 != ret){
        /* if reading failed, try to re-read the input, 
           ignoring all that is before the number */
        ret = scanf("%*[^0-9]%8[0-9]", str); 
    }

    if (1 != ret)
        printf("no match");
    else
        printf("You entered: %s\n", str); 

    return 0; 
} 

But in this code, you will have to handle a new fact: if the user enter a too big number, how to handle it? (strlen can help, or strto[u]l...)

Enter a string: 1234567891011

You entered: 12345678
Mathieu
  • 8,840
  • 7
  • 32
  • 45
1

First of all: the character s does not belong to the scanset specifier. It is %[...], not %[...]s!


Now the C standard says that

  • If a - character is in the scanlist and is not the first, nor the second where the first character is a ^, nor the last character, the behavior is implementation-defined.

So the behaviour of

scanf("%[9-0]", str); 

is implementation-defined. An implementation is allowed to behave like this was %[-09] or in any other implementation-defined manner.

Now, Glibc for example documents that the hyphen means a character range, but POSIX leaves it up to the implementation. Even then, the question whether %[9-0] has all characters in the range or not is questionable. All in all it is preferable to not write any code like that. And scanf is dangerous if you do not specify the buffer length. Since you were bitten by one compatibility bug, it would be best to just stop guessing the behaviour on different platforms and simply write

int rv = scanf("%127[0123456789]", str);
if (rv == 1) {
    ...
}
  • 2
    All good points. But if there are this many things you have to change, this many things you have to be aware of, it's a good reminder to maybe just not use `scanf` at all! It's so hard to use correctly, it's usually more trouble than it's worth. – Steve Summit Aug 06 '19 at 14:01