Why doesn’t scanf(“%d %d”) complain about decimal input?

Why when I run this code:

#include <stdio.h>

int main () {
    int a, b;
    if (scanf("%d %d", &a, &b) == 2)
        printf("%d %d", a, b);
    else 
        printf("Something went wrong");
    return 0;
}

and input for example:

1 1.5

output is:

1 1

Why scanf reads both numbers before ‘.’ and ignores ‘.5’? How do you check that the last number is not a float and string ends?

OS: MacOS/linux
Compiler: gcc

I just want runs something like above code

input:

1 1.5234

(some float number)

output:

Something went wrong

New contributor

Ilya is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

3

The short answer is that you can’t really figure out what’s going on with scanf. Its man page unhelpfully states:

It is very difficult to use these functions correctly, and it is preferable to read entire lines with fgets(3) or getline(3) and parse them later with sscanf(3) or more specialized functions such as strtol(3).

It is very easy for scanf (and fscanf) to get out of sync with the input. I use fgets and sscanf. With those I can greatly improve your input validation as follows:

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

int main () {
    char iline[80];
    int a, b;
    char extra[2];
    int result;

    if (fgets(iline, sizeof(iline), stdin) == NULL) {
        printf("Need an input line.n"); exit(1);
    }

    result = sscanf(iline, "%d %d%1s", &a, &b, extra);
    if (result == 2) {
        printf("%d %dn", a, b);  // Success!
    } else  if (result == 3) {
        printf("Extra stuff starting at '%s'n", extra);
    } else if (result < 2) {
        printf("Could not find two integersn");
    }
    return 0;
}

Here’s some test runs:

$ gcc x.c
$ echo "1" | ./a.out
Could not find two integers
$ echo "1 2" | ./a.out
1 2
$ echo "1 2.5" | ./a.out
Extra stuff starting at '.'
$ echo "1.5 2" | ./a.out
Could not find two integers
$ echo "1 2 5" | ./a.out
Extra stuff starting at '5'

By reading the line separately from scanning it, you can add the “extra” string to test if the scan prematurely ended before the line was consumed. If I use scanf in my code above, it will refuse to return until it actually finds something extra to scan.

New contributor

Streve Ford is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

fgets: Reads the entire line of input, ensuring that you capture everything the user types until they press Enter. This avoids scanf’s limitation of stopping at the first non-matching character.

sscanf: Parses the input stored in input. It tries to read two integers (%d %d). After that, it tries to read one more character (%c) which should be whitespace (like a space or newline).

Validation:

if (sscanf(input, "%d %d %c", &a, &b, &leftover) == 2)
Checks if exactly two integers were successfully read.
isspace(leftover): Checks if the character after the second integer is whitespace (ensuring there are no additional characters like a decimal point).

Output: If the input format matches (scanf successfully reads two integers followed by whitespace), it prints the integers. Otherwise, it prints an error message.

New contributor

srinithi mahalakshmi A is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

0

The %d conversion specifier tells scanf to read and discard any leading whitespace, then read up to the first non-digit character (anything that isn’t in the range ['0'-'9'].

Assume your input stream contains the sequence:

{'1', ' ', '1', '.', '5', 'n'}

the first %d reads first '1', stops reading at the space, leaving it in the input stream:

{' ', '1', '.', '5', 'n'}

then converts and assigns 1 to a.

The second %d reads and discards the space, reads the second '1' and stops reading at the ., leaving it in the input stream:

{'.', '5', 'n'}

then converts and assigns 1 to b.

As far as scanf is concerned it successfully read two integer inputs. The %d conversion specifier doesn’t know or care that 1.5 is a valid floating-point constant; it only cares that '.' is a non-digit character, so it stops reading at that point.

Same thing if you enter something like 12s4 and read it with %dscanf will successfully convert and assign the 12 and leave s4 to foul up the next read.

There are several ways around this, none of them terribly elegant. My preferred method is to read the input as a string with fgets, then tokenize and convert using strtol for integers and strtod for floats:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

/**
 * This program demonstrates some of the gymnastics you have to go through
 * to validate numeric input.
 *
 * Validation steps:
 *
 *  1.  Make sure the fgets operation did not see an EOF or 
 *      input error;
 *
 *  2.  Make sure there's a newline character in the input
 *      buffer, otherwise the input was too long;
 *
 *  3.  Make sure the strtol operation didn't over/underflow;
 *
 *  4.  Make sure that the first character not converted by
 *      strtol is either whitespace or a terminator;
 *
 *  5.  Make sure the value returned by strtol (which is a long) can be
 *      stored in a 32-bit int. 
 */
int main( void )
{
  /**
   * Input buffer
   *
   * Using fixed-size buffers is always risky, but for the purpose of this
   * demonstration should be good enough.  A 32-bit integer can represent 
   * up to 10 decimal digits, plus sign, so to store two integer inputs
   * we need a buffer that's *at least* 25 elements wide (two integers 
   * plus space plus newline plus terminator); rounding up 
   * to the next power of 2. 
   */
  char buf[32] = {0};

  printf( "Gimme two integer values: " );
  if ( !fgets( buf, sizeof buf, stdin ) )
  {
    if ( feof( stdin ) )
      fprintf( stderr, "EOF signaled on standard input...n"  );
    else
      fprintf( stderr, "Error on standard input...n" );
    return EXIT_FAILURE;
  }

  if ( !strchr( buf, 'n' ) )
  {
    fprintf( stderr, "Input too longn" );
    return EXIT_FAILURE;
  }

  int a = 0, b = 0;
  char *chk = NULL;
  static const char *whitespace = " nrtf";

  /**
   * Break the input into tokens separated by whitespace, then
   * attempt to convert each token to an integer with strtol.
   * The chk parameter will point to the first character *not*
   * converted; if that character is anything other than whitespace
   * or a terminator, then the input is not a valid integer.
   */
  for ( char *tok = strtok( buf, whitespace ), cnt = 0; tok != NULL && cnt < 2; tok = strtok( NULL, whitespace ), cnt++ )
  {
    errno = 0;
    long tmp = strtol( tok, &chk, 10 );
    if ( !(isspace( *chk ) || *chk != 0) ) 
    {
      fprintf( stderr, ""%s" is not a valid integer, exiting...n", tok );
      return EXIT_FAILURE;
    }
    else if ( (tmp == LONG_MIN || tmp == LONG_MAX) && errno == ERANGE )
    {
      fprintf( stderr, "Overflow detected while converting "%s" to long, exiting...n", tok );
      return EXIT_FAILURE;
    }
    else if ( tmp > INT_MAX || tmp < INT_MIN )
    {
      fprintf( stderr, ""%s" cannot be represented in an int...n", tok );
      return EXIT_FAILURE;
    }
    else if ( cnt == 0 )
    {
      a = tmp;
    }
    else
    {
      b = tmp;
    }
  }

  printf( "a = %d, b = %dn", a, b );  
      
  return EXIT_SUCCESS;
}  

Yeah. Welcome to programming in C. And this code has some severe weaknesses; strtok is destructive and non-threadsafe, using fixed-size buffers is always risky, I’m relying on long having greater range than int (not necessarily true on some systems), etc.

Some sample runs:

% ./input5
Gimme two integer values: ^D EOF signaled on standard input...

% ./input5
Gimme two integer values: 1234567890123456789012345678901234567890
Input too long

% ./input5
Gimme two integer values: 1234567890123456789012345
Overflow detected while converting "1234567890123456789012345" to long, exiting...

% ./input5
Gimme two integer values: 12345678901234
"12345678901234" cannot be represented in an int...

% ./input5
Gimme two integer values: 123 4.56
"4.56" is not a valid integer, exiting...

% ./input5
Gimme two integer values: 123 456
a = 123, b = 456

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật