1
votes

I'm a newbie on c++ and I am encountering some problems. The question to be solved is having 5 inputs, the inputs can include integers and the string "none", try to sum up the integers in the inputs and the result should be a double. Here's what I have done: I put five inputs in the array and use scanf() to turn them into double, but when I enter none and use printf to see the array, I found out that it turns none into two float, does scanf has any restrictions on converting strings to double?

Here's the code :

int main()
{
    double sc[5];

    for (int i = 0; i < 5; i++) {
        sc[i] = 3;
        scanf("%lf", &sc[i]);
        printf("%lf\n", sc[i]);
    }
}

and the output is:

34
34.000000
none
3.000000
3.000000
56
56.000000
89
89.000000
1

1 Answers

0
votes

Calling scanf("%lf", &something) will populate something if and only if the input is a valid floating point number. The string none is not such a valid number.

The reason you're getting two 3 values is probably because nan is a valid floating point number, so scanf finds the n and says "Hah, this will be a nan". But then it finds, much to its disappointment, the o and decides it's no longer valid.

But it has already read the no from the input stream. It then goes back and does the same thing with the ne (a).

After that, you start giving it valid numbers again so it carries on.


If you want to be able to handle strings and numbers, you're going to have to use the least restrictive (string) and then decide. Something like this (though scanf("%s") is dangerous for real code, it's probably okay for classwork):

The following code does that and (as you should) checks the return value from scanf/sscanf to ensure it was correctly scanned:

#include <stdio.h>
#include <string.h>

int main() {
    static char bigstring[1000];
    double sc[5];

    for (int i = 0; i < 5; i++) {
        sc[i] = 3;
        if (scanf("%s", bigstring) != 1) {
            puts("*** Could not get input");
            return 1;
        }

        if (strcmp("none", bigstring) == 0) {
            puts("Got 'none', converting to -999");
            sc[i] = -999;
        } else if (sscanf(bigstring, "%lf", &sc[i]) != 1) {
            printf("*** Could not convert input '%s' to float", bigstring);
            return 1;
        } else {
            printf("Got %f\n", sc[i]);
        }
    }

    puts("\nThe five entered numbers were:");
    for (int i = 0; i < 5; i++) {
        printf("   %lf\n", sc[i]);
    }
}

Running that works properly with basic test data:

pax:~$ printf "34\nnone\n56\n89\n111\n" | ./qq
Got 34.000000
Got 'none', converting to -999
Got 56.000000
Got 89.000000
Got 111.000000

The five entered numbers were:
   34.000000
   -999.000000
   56.000000
   89.000000
   111.000000

(a) Interestingly, it appears this only happens with real user input, not piping data through the program as per my printf statement.

The ideal behaviour, in my opinion, would be to leave the input stream pointing at the invalid data. In other words, unless the exact text is valid (like nan), the pointer should not move at all. However, there's a footnote in the C standard that allows for this behaviour if, for example, the input stream is not seekable:

fscanf pushes back at most one input character onto the input stream.

So, while it may be able to back up further than that on a pipeline, that may not be the case when dealing with terminal input.

When I enter x as input, it appears it does push that back, because every single following array element is populated with 3, meaning it's reading that x continuously. Anything starting with an n seems to consume that and the following character only.