1

I have a problem how to check if the input is really an integer. My simple program below writes quotes if the input is 1 or 2. In all other cases it should print "luj".

My code:

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

int main(int argc, char **argv) {

  int cislo;

  printf("ml' nob:\n");
  scanf("%d", &cislo);

  if (cislo == 1) {
    printf("Qapla'\n");
    printf("noH QapmeH wo' Qaw'lu'chugh yay chavbe'lu' 'ej wo' choqmeH may' "
           "DoHlu'chugh lujbe'lu'.\n");
  } else if (cislo == 2) {
    printf("Qapla'\n");
    printf("Qu' buSHa'chugh SuvwI', batlhHa' vangchugh, qoj matlhHa'chugh, "
           "pagh ghaH SuvwI''e'.\n");
  } else {
    printf("luj\n");
  }
}

When the input is 1.5 my program read its as 1. But it should print "luj". In python I would do something like isinstance(cislo, int). How can I do it in C, please?

This question did not help me: Checking if input is an integer in C

8
  • Always check scanf's return value. Commented Oct 15, 2021 at 15:12
  • Indeed do check scanf's return value, but that will not directly help in distinguishing 1 from 1.5. Commented Oct 15, 2021 at 15:14
  • If scanf fails, you have no idea what value your cislo variable will have. Maybe better to say int cislo = -1;. Commented Oct 15, 2021 at 15:14
  • 7
    A completely different approach is to read the user's input as a string, then call strtol, then check strtol's returned value and returned "endp" pointer carefully to see if it was able to convert anything, or everything. This is admittedly somewhat tricky to get right. There have been questions about it in the past. There are some hints in this answer. Commented Oct 15, 2021 at 15:16
  • The strtol() approach may be a bit tricky to get right, but not more so than it is to get a scanf-based approach right. I was about to recommend strtol() myself. Commented Oct 15, 2021 at 15:17

2 Answers 2

2

scanf with %d will only read integers - anything that's not an integer won't get read.

Unfortunately, this means you can get partial matches as you've experienced - "1.5" is not an integer, but scanf will read and assign the 1 to cislo and return success.

The way around this is to read the next input as text (not try to read it as an integer or float) and do the conversion separately using a library function like strtol or by doing your own conversion manually. Here's an example using strtol:

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

#define BUFFER_SIZE 11 // up to 10 digits for a 32-bit int plus sign

/**
 * We don't want to use a naked "%s" in our scanf call, since
 * if the user types in more characters than the buffer is sized
 * to hold, we'll write past the end of the buffer.  You can specify
 * the maximum number of characters to read as part of the "%s" 
 * conversion like "%11s", but unlike with printf you can't specify
 * it with a runtime argument - it has to be hardcoded.
 *
 * We're going to create a format string based on the value of BUFFER_SIZE;
 * when we're done, FMT will expand to "%" "11" "s", which will 
 * be interpreted as "%11s".  
 */
#define EXPAND(x) #x
#define STR(x) EXPAND(x)
#define FMT "%" STR(BUFFER_SIZE)  "s" // Make sure we don't read more characters than the buffer can hold

int main( void )
{
  int cislo = 0;

  char buffer[BUFFER_SIZE+1]; // +1 for string terminator
  if ( scanf ( FMT, buffer ) == 1 )
  {
    /**
     * strtol will take a string representation of an integer
     * like "123" and convert it to the corresponding integer
     * value.  chk will point to the first character in the
     * string that *isn't* part of an integer constant.  If that
     * character isn't whitespace or 0 (the string terminator),
     * then the input is not a properly formed integer.
     */
    char *chk;
    int tmp = strtol( buffer, &chk, 10 );
    if ( !isspace( *chk ) && *chk != 0 )
    {
      fprintf( stderr, "%s is not a valid integer input!\n", buffer );
      return -1;
    }
    
    cislo = tmp;
  }

  printf( "cislo = %d\n", cislo );
  return 0;
}

Examples:

$ ./converter 
123
cislo = 123

$ ./converter
abc
abc is not a valid integer input!

$ ./converter
123c
123c is not a valid integer input!

$ ./converter 
12.3
12.3 is not a valid integer input!
Sign up to request clarification or add additional context in comments.

Comments

1

Note that C is not like Python: You want to input a number with a decimal point into a variable whose type is an integer. An integer type variable can only hold integers, so... This number will automatically become an integer and the number behind the dot will not be counted.

So when you trying to insert the value 1.5 into cislo the value is automatically converted to an int value, to 1.


Solution:

#include <stdio.h>

int main(int argc, char** argv) {
    float cislo;
    
    printf("ml' nob:\n");
    
    if (scanf("%f", &cislo) != 1)
        // Problem (Handle it)

    if (cislo == 1) {
        printf("Qapla'\n");
        printf("noH QapmeH wo' Qaw'lu'chugh yay chavbe'lu' 'ej wo' choqmeH may' DoHlu'chugh lujbe'lu'.\n");
    } else if (cislo == 2) {
        printf("Qapla'\n");
        printf("Qu' buSHa'chugh SuvwI', batlhHa' vangchugh, qoj matlhHa'chugh, pagh ghaH SuvwI''e'.\n");  
    } else {
        printf("luj\n");
    }
}

2 Comments

Would this work if the input was "abc"?
@BillLynch cislo will be set to 0.0, And in fact, the else clause will be executed. So yes, it will work. I also see that you edited the question, is my answer still relevant?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.