Function changes variable address when returning non-positive number

Viewed 58

So I have a function that takes address of a variable and puts number in there(I need this function to make all checks on input as my teacher loves to put something like

    123       ABV00000012 

when it's asked to put just a number). The problem is that when number is negative it somehow changes address of my variable and gives me just zero(1-st screenshot). When I put positive number it works just fine(2-nd screenshot) and I find something else, when I put something too low like -1111111111111111111111 it gives me error that number is too big or too low, then we have to put number again and now it works just fine with non-positive numbers(3-rd screenshot). Also when put something too big 11111111111111111111111 it still don't work with non-positive numbers(4-th screenshot) Code is below. https://imgur.com/a/jBU8664 (<- screenshots, sry can't attach screenshots in here yet)

#include <stdio.h>


int putInt(int*);

int main()
{
    int a = 1;
    printf("a address = %p\n", &a);
    while(!putInt(&a))
    {
        printf("Error! %d - %p\n", a, &a);
    }
    printf("A == %d == %p\n", a, &a);
    printf("%p\n", &a);
    return 0;
}

int putInt(int *a)
{
    char isMin = 0, isZero = 0, isSpc = 0, isNum = 'a', isEnt[2];
    isEnt[0] = 0;
    int num = 123;
    scanf("%1[\040]", &isSpc);
    if(isSpc == ' ')
    {
        printf("Incorrect input! No spaces allowed!\n");
        rewind(stdin);
        return 0;
    }
    scanf("%1[-]", &isMin);
    scanf("%1[\n]", isEnt);
    if(*isEnt == '\n')
    {
        if(isMin == '-')
        {
            printf("Incorrect input!\n");
            rewind(stdin);
            return 0;
        }
        else
        {
            printf("Number is not entered!\n");
            rewind(stdin);
            return 0;
        }
    }
    scanf("%1[\040]", &isSpc);
    if(isSpc == ' ')
    {
        printf("Incorrect input! No spaces allowed!\n");
        rewind(stdin);
        return 0;
    }
    scanf("%1[0]", &isZero);
    scanf("%*[0]");
    scanf("%1[\n]", isEnt);
    if(*isEnt == '\n')
    {
        *a = 0;
        rewind(stdin);
        return 1;
    }
    scanf("%10d", &num);
    scanf("%1[0-9]", &isNum);
    if(isNum != 'a')
    {
        printf("Incorrect input! Too big or too low number!\n");
        rewind(stdin);
        return 0;
    }
    scanf("%1[\040]", &isSpc);
    if(isSpc == ' ')
    {
        printf("Incorrect input! No spaces allowed!\n");
        rewind(stdin);
        return 0;
    }
    scanf("%1[\n]", isEnt);
    printf("Num is %d\n", num);
    if(*isEnt == '\n' && num > 0)
    {
        if(isMin == '-') num = num * -1;
        *a = num;
        printf("a = %d = %p\n", *a, a);
        rewind(stdin);
        return 1;
    }
    printf("Error! Too big or too low number!\n");
    rewind(stdin);
    return 0;
}

2 Answers

I'm not going to try to tell you how to fix the code you have — I'm afraid that's not reasonably possible — but I am going to tell you how I think you should approach this problem.

When you want to read an integer typed by a user, I believe you have three choices:

  1. Use a dirt-simple scanf call: scanf("%d", &number).

  2. Use a dirt-simple scanf call, and check its return value: if(scanf("%d", &number) != 1) { printf("Input error!\n"); exit(1); }

  3. Read a full line of text using fgets, attempt to convert it to an integer using strtol, and check whether strtol succeeded.

Let's consider these in a bit more detail. Number 1 is indeed dirt-simple, but it makes no attempt to check for errors. If the user types anything wrong, anything other than a representable integer, things will probably go badly wrong.

Number 2 is still nice and simple. For many of the wrong things the user might type, it will detect the problem, and print an error message. The disadvantages are that it gives the user no opportunity to retry (it summarily exits instead), and there are still some problems it won't catch, including things like "111x" and "11111111111111111111111".

And then we get to number 3. This may seem like a pretty big, perhaps forbidding departure at first. scanf seems easy, and fgets may seem hard. But lots of people have faced the problem of trying to do robust user input, and just about everyone has concluded: reading full lines is the only way to go.

It seems like there ought to be an intermediate way, somewhere between numbers 2 and 3. It seems like it ought to be possible to keep using scanf, in a slightly more complicated way, to achieve truly robust user input, catching all possible errors, while still retaining the nice simplicity of scanf. But I believe that it is false. I believe that if you try to achieve truly robust user input using scanf alone, either you'll end up working three times as hard as you would have worked for number 3, or you still won't handle every possible case. (Or both.)

Found the answer! The problem was in code below. I didn't have scanf("%1[\n]", &isEnt); before if! Now it works, thanks everybody for comments, now I know that my solution is a shit(will learn how to do better!), at least it works!

    scanf("%1[\n]", &isEnt);
    if(isEnt == '\n' && num > 0)
    {
        if(isMin == '-') num = num * -1;
        *a = num;
        //printf("a == %d == %p\n", *a, a);
        rewind(stdin);
        return 1;
    }
Related