-3

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://i.stack.imgur.com/eudyC.jpg (<- 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;
}

ksimax
  • 1
  • 1
    `rewind(stdin)` is not possible. Once characters have been read from `stdin`, they are lost and can't be retrieved again. – Some programmer dude Sep 24 '22 at 10:08
  • There are other problems as well, like why is `isEnt` an array? Why do you use it as a string when all you need is a single character? And the whole input validation seems just wrong. Why not read a full line, then use e.g. `sscanf` to attempt to parse the input (unless you can get the character(s) directly from the string itself)? And always remember to check what `sscanf` [*returns*](https://en.cppreference.com/w/c/io/fscanf#Return_value). – Some programmer dude Sep 24 '22 at 10:11
  • And please [don't post images of text](https://meta.stackoverflow.com/questions/285551/why-should-i-not-upload-images-of-code-data-errors-when-asking-a-question). Copy-paste text *as text* into your questions. – Some programmer dude Sep 24 '22 at 10:12
  • 1
    @Someprogrammerdude: Re “Once characters have been read from `stdin`, they are lost and can't be retrieved again”: That depends on what `stdin` is connected to. If it is connected to a regular file, as with a shell redirection to a file, `rewind` works fine. Even with a connection to a terminal-like device, it clears the error indicator, which would allow further input after the user has triggered an end-of-file indication. – Eric Postpischil Sep 24 '22 at 10:35
  • You should narrow this question down to one specific problem with one specific piece of code. You have got a bunch of code and have not explained what the whole code is supposed to be doing. So you are expecting readers to examine and interpret all this code and figure out what the original intent might have been. Then they have to figure out where the bug is. Instead, you should examine the code and its execution in detail and find exactly which part is not behaving the way you want. – Eric Postpischil Sep 24 '22 at 10:40
  • Consider using `getchar` to read one char at a time. – stark Sep 24 '22 at 11:18
  • You've got a number of wrong approaches and misconceptions in your code. First, `scanf` works best for interactive user input only if you can assume that the user is going to type "normal" input, and is not out to get you. If you want to write code that can deal gracefully with arbitrary (potentially completely incorrect) input, `scanf` is not the right tool for the job. – Steve Summit Sep 24 '22 at 11:19
  • Second, `scanf` is not a good tool for reading single characters. And using it as `scanf("%1[\040]", &isSpc)`, to read one character but only if it's a space, is an exotic technique which, while extremely imaginative (and I'll give you full points for that!) is unnecessary, and probably never going to work. – Steve Summit Sep 24 '22 at 11:22
  • Third, if you *are* going to use `scanf` successfully, and with any hope of handling incorrect input, you *must* check its return value, so that you now whether a given call succeeded or failed. – Steve Summit Sep 24 '22 at 11:22
  • Fourth, if you're using `scanf` with the hope of handing possibly-incorrect input, you are going to have the problem that the incorrect input tends to stay on the input stream, meaning that if must be "flushed". This is a [completely separate and very troublesome problem](https://stackoverflow.com/questions/7898215) all by itself. – Steve Summit Sep 24 '22 at 11:24
  • Fifth, handling numbers that might be too big — like 11111111111111111111111 — is also a surprisingly difficult problem, and also far beyond what you can reasonably achieve with `scanf`. Any reasonable solution to this problem is almost certainly going to involve `strtol`, and even then it's still surprisingly intricate. – Steve Summit Sep 24 '22 at 11:26
  • Finally, the only real solution here — if robustly handling arbitrarily-wrong input is truly your goal — is to [use something other than `scanf`](https://stackoverflow.com/questions/58403537). – Steve Summit Sep 24 '22 at 12:21

2 Answers2

2

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.)

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
0

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;
    }
ksimax
  • 1
  • Glad you got it working! I k now how that feels, even when your realize the approach maybe wasn't the best. One more tip: if you're going to use that `scanf("%1[\n]", &isEnt)` trick, you probably have to make sure you do `isEnt = 0` right before it, every time. – Steve Summit Sep 24 '22 at 15:24