40

The catch is that I cannot use atoi or any other function like that (I'm pretty sure we're supposed to rely on mathematical operations).

 int num; 
 scanf("%d",&num);
 if(/* num is not integer */) {
  printf("enter integer");
  return;
 }

I've tried:

(num*2)/2 == num
num%1==0
if(scanf("%d",&num)!=1)

but none of these worked.

Any ideas?

The Archetypal Paul
  • 39,479
  • 18
  • 96
  • 128
Gal
  • 20,759
  • 30
  • 92
  • 114
  • What do you mean "none of these worked"? And how did you try the last one? – David Thornley Nov 01 '10 at 19:52
  • @David I placed them in if statement, what is confusing about it? – Gal Nov 01 '10 at 19:54
  • What kind of input is "integer type"? One consisting only of digits? Is a minus sign allowed in the front? – eq- Nov 01 '10 at 20:05
  • You list two conditions and an if statement. I assume you didn't include an if statement in an if statement, so I don't know what you did there. (Did you just replace the if statement, or was it more significant than that?) Nor do you provide any clue to failure mode other than "none of these worked". Didn't compile? Run-time error? Didn't work the way you expected (and, if so, what did you expect?)? – David Thornley Nov 01 '10 at 21:10
  • @Gal are you asking if lets say some one gave 5.5 as an input and got a 5 ? because i'm not sure if that can be checked , and if so i would like to know how .. – eran otzap Apr 11 '12 at 14:51
  • I know I'm late to the party but I suppose you "cannot" (meaning: are not allowed to) use `atoi()` because the idea is that you do the check "manually" by walking through the characters and checking whether they are in the range 0-9. It's therefore likely `scanf()` shouldn't be used either. – Peter - Reinstate Monica Jan 07 '19 at 12:44

15 Answers15

46

num will always contain an integer because it's an int. The real problem with your code is that you don't check the scanf return value. scanf returns the number of successfully read items, so in this case it must return 1 for valid values. If not, an invalid integer value was entered and the num variable did probably not get changed (i.e. still has an arbitrary value because you didn't initialize it).

As of your comment, you only want to allow the user to enter an integer followed by the enter key. Unfortunately, this can't be simply achieved by scanf("%d\n"), but here's a trick to do it:

int num;
char term;
if(scanf("%d%c", &num, &term) != 2 || term != '\n')
    printf("failure\n");
else
    printf("valid integer followed by enter key\n");
AndiDog
  • 62,237
  • 17
  • 152
  • 196
26

You need to read your input as a string first, then parse the string to see if it contains valid numeric characters. If it does then you can convert it to an integer.

char s[MAX_LINE];

valid = FALSE;
fgets(s, sizeof(s), stdin);
len = strlen(s);
while (len > 0 && isspace(s[len - 1]))
    len--;     // strip trailing newline or other white space
if (len > 0)
{
    valid = TRUE;
    for (i = 0; i < len; ++i)
    {
        if (!isdigit(s[i]))
        {
            valid = FALSE;
            break;
        }
    }
}
Paul R
  • 195,989
  • 32
  • 353
  • 519
15

There are several problems with using scanf with the %d conversion specifier to do this:

  1. If the input string starts with a valid integer (such as "12abc"), then the "12" will be read from the input stream and converted and assigned to num, and scanf will return 1, so you'll indicate success when you (probably) shouldn't;

  2. If the input string doesn't start with a digit, then scanf will not read any characters from the input stream, num will not be changed, and the return value will be 0;

  3. You don't specify if you need to handle non-decimal formats, but this won't work if you have to handle integer values in octal or hexadecimal formats (0x1a). The %i conversion specifier handles decimal, octal, and hexadecimal formats, but you still have the first two problems.

First of all, you'll need to read the input as a string (preferably using fgets). If you aren't allowed to use atoi, you probably aren't allowed to use strtol either. So you'll need to examine each character in the string. The safe way to check for digit values is to use the isdigit library function (there are also the isodigit and isxdigit functions for checking octal and hexadecimal digits, respectively), such as

while (*input && isdigit(*input))
   input++;    

(if you're not even allowed to use isdigit, isodigit, or isxdigit, then slap your teacher/professor for making the assignment harder than it really needs to be).

If you need to be able to handle octal or hex formats, then it gets a little more complicated. The C convention is for octal formats to have a leading 0 digit and for hex formats to have a leading 0x. So, if the first non-whitespace character is a 0, you have to check the next character before you can know which non-decimal format to use.

The basic outline is

  1. If the first non-whitespace character is not a '-', '+', '0', or non-zero decimal digit, then this is not a valid integer string;
  2. If the first non-whitespace character is '-', then this is a negative value, otherwise we assume a positive value;
  3. If the first character is '+', then this is a positive value;
  4. If the first non-whitespace and non-sign character is a non-zero decimal digit, then the input is in decimal format, and you will use isdigit to check the remaining characters;
  5. If the first non-whitespace and non-sign character is a '0', then the input is in either octal or hexadecimal format;
  6. If the first non-whitespace and non-sign character was a '0' and the next character is a digit from '0' to '7', then the input is in octal format, and you will use isodigit to check the remaining characters;
  7. If the first non-whitespace and non-sign character was a 0 and the second character is x or X, then the input is in hexadecimal format and you will use isxdigit to check the remaining characters;
  8. If any of the remaining characters do not satisfy the check function specified above, then this is not a valid integer string.
John Bode
  • 106,204
  • 16
  • 103
  • 178
5

First ask yourself how you would ever expect this code to NOT return an integer:

int num; 
scanf("%d",&num);

You specified the variable as type integer, then you scanf, but only for an integer (%d).

What else could it possibly contain at this point?

abelenky
  • 58,532
  • 22
  • 99
  • 149
  • Sorry, people seem to be raving over this answer, but I expected exactly what you wrote from the algorithm but it didn't work. I'm supposed to check the value so that it's never a non-integer, and your solution doesn't cut it. Am I missing something? please explain. – Gal Nov 01 '10 at 19:56
  • 1
    @sombe: what you are missing is that `scanf("%d",&num)` will only ever store an integer value to `num` **by definition**; *whether that value bears any relationship to the input string is an open issue*. If you enter something with leading digits (like "12efg"), `scanf` will read, convert, and assign the leading "12", leaving the "efg" in the input stream. If the input string doesn't start with a digit (such as "ab123"), *none* of the input string will be read, and `num` will contain whatever value it had before the call (which is still an integer). – John Bode Nov 01 '10 at 20:28
  • "What else could it possibly contain at this point?" --> a trap value - although I have not seen `int` employing traps for years. – chux - Reinstate Monica Jun 09 '20 at 22:53
0

I looked over everyone's input above, which was very useful, and made a function which was appropriate for my own application. The function is really only evaluating that the user's input is not a "0", but it was good enough for my purpose. Hope this helps!

#include<stdio.h>

int iFunctErrorCheck(int iLowerBound, int iUpperBound){

int iUserInput=0;
while (iUserInput==0){
    scanf("%i", &iUserInput);
    if (iUserInput==0){
        printf("Please enter an integer (%i-%i).\n", iLowerBound, iUpperBound);
        getchar();
    }
    if ((iUserInput!=0) && (iUserInput<iLowerBound || iUserInput>iUpperBound)){
        printf("Please make a valid selection (%i-%i).\n", iLowerBound, iUpperBound);
        iUserInput=0;
    }
}
return iUserInput;
}
Nick
  • 1
  • 1
0

Try this...

#include <stdio.h>

int main (void)
{
    float a;
    int q;

    printf("\nInsert number\t");
    scanf("%f",&a);

    q=(int)a;
    ++q;

    if((q - a) != 1)
        printf("\nThe number is not an integer\n\n");
    else
        printf("\nThe number is an integer\n\n");

    return 0;
}
Unihedron
  • 10,251
  • 13
  • 53
  • 66
OscaRoCa
  • 9
  • 2
  • 1
    With invalid numeric input for `scanf("%f",&a);` and `a` uninitialized, `q=(int)a;` is not defined. Code should check the return value of `scanf("%f",&a)` before using `a`. – chux - Reinstate Monica Jan 07 '17 at 23:40
0

This is a more user-friendly one I guess :

#include<stdio.h>

/* This program checks if the entered input is an integer
 * or provides an option for the user to re-enter.
 */

int getint()
{
  int x;
  char c;
  printf("\nEnter an integer (say -1 or 26 or so ): ");
  while( scanf("%d",&x) != 1 )
  {
    c=getchar();

    printf("You have entered ");
    putchar(c);
    printf(" in the input which is not an integer");

    while ( getchar() != '\n' )
     ; //wasting the buffer till the next new line

    printf("\nEnter an integer (say -1 or 26 or so ): ");

  }

return x;
}


int main(void)
{
  int x;
  x=getint();

  printf("Main Function =>\n");
  printf("Integer : %d\n",x);

 return 0;
}
sjsam
  • 19,686
  • 3
  • 43
  • 88
  • `while( scanf("%d",&x) != 1 )` loop is infinite loop should `stdin` get closed as `scanf("%d",&x)` will forever return `EOF`. As well `while ( getchar() != '\n' )` – chux - Reinstate Monica Jan 07 '17 at 23:38
0

I developed this logic using gets and away from scanf hassle:

void readValidateInput() {

    char str[10] = { '\0' };

    readStdin: fgets(str, 10, stdin);
    //printf("fgets is returning %s\n", str);

    int numerical = 1;
    int i = 0;

    for (i = 0; i < 10; i++) {
        //printf("Digit at str[%d] is %c\n", i, str[i]);
        //printf("numerical = %d\n", numerical);
        if (isdigit(str[i]) == 0) {
            if (str[i] == '\n')break;
            numerical = 0;
            //printf("numerical changed= %d\n", numerical);
            break;
        }
    }
    if (!numerical) {
        printf("This is not a valid number of tasks, you need to enter at least 1 task\n");
        goto readStdin;
    }
    else if (str[i] == '\n') {
        str[i] = '\0';
        numOfTasks = atoi(str);
        //printf("Captured Number of tasks from stdin is %d\n", numOfTasks);
    }
}
0
printf("type a number ");
int converted = scanf("%d", &a);
printf("\n");

if( converted == 0) 
{
    printf("enter integer");
    system("PAUSE \n");
    return 0;
}

scanf() returns the number of format specifiers that match, so will return zero if the text entered cannot be interpreted as a decimal integer

Eduardo
  • 19
  • 5
0

If anyone else comes up with this question, i've written a program, that keeps asking to input a number, if user's input is not integer, and finishes when an integer number is accepted

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

bool digit_check(char key[])
{
    for(int i = 0; i < strlen(key); i++)
    {
        if(isdigit(key[i])==0)
        {
            return false;
        }
    }
    return true;
}

void main()
{
    char stroka[10];
    do{
        printf("Input a number: ");
        scanf("%s",stroka);}
    while (!digit_check(stroka));
    printf("Number is accepted, input finished!\n");
    system("pause");
}
-1

I've been searching for a simpler solution using only loops and if statements, and this is what I came up with. The program also works with negative integers and correctly rejects any mixed inputs that may contain both integers and other characters.


#include <stdio.h>
#include <stdlib.h> // Used for atoi() function
#include <string.h> // Used for strlen() function

#define TRUE 1
#define FALSE 0

int main(void)
{
    char n[10]; // Limits characters to the equivalent of the 32 bits integers limit (10 digits)
    int intTest;
    printf("Give me an int: ");

    do
    {        
        scanf(" %s", n);

        intTest = TRUE; // Sets the default for the integer test variable to TRUE

        int i = 0, l = strlen(n);
        if (n[0] == '-') // Tests for the negative sign to correctly handle negative integer values
            i++;
        while (i < l)
        {            
            if (n[i] < '0' || n[i] > '9') // Tests the string characters for non-integer values
            {              
                intTest = FALSE; // Changes intTest variable from TRUE to FALSE and breaks the loop early
                break;
            }
            i++;
        }
        if (intTest == TRUE)
            printf("%i\n", atoi(n)); // Converts the string to an integer and prints the integer value
        else
            printf("Retry: "); // Prints "Retry:" if tested FALSE
    }
    while (intTest == FALSE); // Continues to ask the user to input a valid integer value
    return 0;
}
de3z1e
  • 245
  • 2
  • 7
-1

Just check is your number has any difference with float version of it, or not.

float num; 
scanf("%f",&num);

if(num != (int)num) {
    printf("it's not an integer");
    return;
}
-2

This method works for everything (integers and even doubles) except zero (it calls it invalid):

The while loop is just for the repetitive user input. Basically it checks if the integer x/x = 1. If it does (as it would with a number), its an integer/double. If it doesn't, it obviously it isn't. Zero fails the test though.

#include <stdio.h> 
#include <math.h>

void main () {
    double x;
    int notDouble;
    int true = 1;
    while(true) {
        printf("Input an integer: \n");
        scanf("%lf", &x);
        if (x/x != 1) {
            notDouble = 1;
            fflush(stdin);
        }
        if (notDouble != 1) {
            printf("Input is valid\n");
        }
        else {
            printf("Input is invalid\n");
        }
        notDouble = 0;
    }
}
-3

I was having the same problem, finally figured out what to do:

#include <stdio.h>
#include <conio.h>

int main ()
{
    int x;
    float check;
    reprocess:
    printf ("enter a integer number:");
    scanf ("%f", &check);
    x=check;
    if (x==check)
    printf("\nYour number is %d", x);
    else 
    {
         printf("\nThis is not an integer number, please insert an integer!\n\n");
         goto reprocess;
    }
    _getch();
    return 0;
}
vtolentino
  • 644
  • 5
  • 11
-3

I found a way to check whether the input given is an integer or not using atoi() function .

Read the input as a string, and use atoi() function to convert the string in to an integer.

atoi() function returns the integer number if the input string contains integer, else it will return 0. You can check the return value of the atoi() function to know whether the input given is an integer or not.

There are lot more functions to convert a string into long, double etc., Check the standard library "stdlib.h" for more.

Note : It works only for non-zero numbers.

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

int main() {
    char *string;
    int number;

    printf("Enter a number :");
    string = scanf("%s", string);

    number = atoi(string);

    if(number != 0)
        printf("The number is %d\n", number);
    else
        printf("Not a number !!!\n");
    return 0;
}
Rishi
  • 13
  • 5