1

I've been trying to scan integers with sscanf() from strings with leading zeros (e.g. '03').

However, it works fine but only until '07'. Starting with '08', the strings will be read as 0.

Below you'll find my code and the output. Thank you for your help!

#include <stdio.h>
#include <stdlib.h>

int main() {

    char string_six[3] = "06";
    char string_seven[3] = "07";
    char string_eight[3] = "08";
    char string_nine[3] = "09";

    int six = -1;
    int seven = -1;
    int eight = -1;
    int nine = -1;

    sscanf(string_six, "%i", &six);
    sscanf(string_seven, "%i", &seven);
    sscanf(string_eight, "%i", &eight);
    sscanf(string_nine, "%i", &nine);

    printf("Six: %i\n",six);
    printf("Seven: %i\n",seven);
    printf("Eight: %i\n",eight);
    printf("Nine: %i\n",nine);

    return 0;    
}

Output:

Six: 6
Seven: 7
Eight: 0
Nine: 0
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
stulli
  • 21
  • 3
  • 3
    Leading zero means the number is octal. An octal number can't have 8 or 9 in it. – Barmar Jan 12 '22 at 18:14
  • If you have trouble with scanf and family, do not ignore what they are trying to tell you. I.e. interpret the return value (not the scanned value). You are aware that they have a helpful return value, aren't you? – Yunnosch Jan 12 '22 at 18:15
  • 1
    @Yunnosch I don't think that will help in this case. It will return `1` because it successfully parsed the `0`. – Barmar Jan 12 '22 at 18:16
  • Yes exactly. It means "successfully scanned", i.e. "the 0 is intentional". But even if it does not help here, ignoring it while asking a question on using scanf is ... noteable. You know "I have trouble understanding this. The availabe information I chose to ignore." – Yunnosch Jan 12 '22 at 18:18
  • Didn't know that since I am absolutely new to C. Thank you for the hint. – stulli Jan 12 '22 at 18:22

2 Answers2

6

You need to use the conversion specifier %d instead of %i.

From the C Standard (7.21.6.2 The fscanf function)

d Matches an optionally signed decimal integer, whose format is the same as expected for the subject sequence of the strtol function with the value 10 for the base argument. The corresponding argument shall be a pointer to signed integer.

i Matches an optionally signed integer, whose format is the same as expected for the subject sequence of the strtol function with the value 0 for the base argument. The corresponding argument shall be a pointer to signed integer.

And (7.22.1.4 The strtol, strtoll, strtoul, and strtoull functions)

3 If the value of base is zero, the expected form of the subject sequence is that of an integer constant as described in 6.4.4.1, optionally preceded by a plus or minus sign, but not including an integer suffix.

And at last (6.4.4.1 Integer constants)

integer-constant:
    decimal-constant integer-suffixopt
    octal-constant integer-suffixopt
    hexadecimal-constant integer-suffixopt
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
2

"08" is being interpreted as the octal number 0, followed by a character that cannot be part of an octal number. If you do this instead:

   int n;
   char c;
   sscanf("08", "%i%c", &n, &c);

you should observe n being set to 0 and c to '8'.

This behavior is by design: %i accepts decimal, octal, and hexadecimal numbers in the input, using the same syntax as C source code (that is, leading '0' means octal, leading '0x' or '0X' means hexadecimal).

If you don't want to accept octal or hexadecimal numbers, you can use %d instead; 'd' means to accept only decimal numbers. Similarly, %o accepts only octal numbers (but the '0' prefix is not required) and %x accepts only hexadecimal (but the '0x' or '0X' prefix is not required). There is no way to get sscanf to accept decimal and 0x-prefix hex but not also 0-prefix octal.

However, because the *scanf functions are broken as specified and should never be used at all, what you should really be doing is using strtol with third argument 10. (Pay careful attention to the part of the strtol manpage about checking for invalid input.) (There is no way to get strtol to accept decimal and 0x-prefix hex but not also 0-prefix octal, either.)

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
zwol
  • 135,547
  • 38
  • 252
  • 361