tags:

views:

469

answers:

6

I have a piece of code that presents an interesting question (in my opinion).

/*power.c raises numbers to integer powers*/
#include <stdio.h>

double power(double n, int p);

int main(void)
{
    double x, xpow; /*x is the orginal number and xpow is the result*/
    int exp;/*exp is the exponent that x is being raised to */

    printf("Enter a number and the positive integer power to which\n the first number will be raised.\n enter q to quit\n");

    while(scanf("%lf %d", &x, &exp) ==2)
    {
     xpow = power(x, exp);
     printf("%.3g to the power %d is %.5g\n", x, exp, xpow);
     printf("enter the next pair of numbers or q to quit.\n");
    }

    printf("Hope you enjoyed your power trip -- bye!\n");
    return 0;
}

double power(double n, int p)
{
    double pow = 1;
    int i;

    for(i = 1; i <= p; i++)
    {
     pow *= n;
    }
    return pow;
}

If you'll notice the order of numbers to be entered is the floating point number and then the decimal number (base number and then the exponent). But when I enter the input with an integer base and floating point exponent it produces a strange result.

[mike@mike ~/code/powerCode]$ ./power
Enter a number and the positive integer power to which
 the first number will be raised.
 enter q to quit
1 2.3
1 to the power 2 is 1
enter the next pair of numbers or q to quit.
2 3.4
0.3 to the power 2 is 0.09
enter the next pair of numbers or q to quit.

It seems to push the second number of the floating point exponent back onto the next input. I was hoping some one could explain what was going on behind the scenes. I know that this is the work of scanf() not checking its array boundaries but if some one could give me some deeper understanding I'd really appreciate it. Thanks Stack Overflow. -M.I.

Edit. Just wanted to thank everyone for their input. Any other answers are more then welcome. Thanks again, S.O.

+7  A: 

This is because when you're using scanf to read "2.3", the scan is stopping at, but not consuming the "." in ".3". Thus, when you make the next call to scanf, it starts by reading in ".3".

To elaborate, scanf calls are not restricted to one line of text. scanf() skips over whitespace, including tabs, spaces and newlines.

Eric
+2  A: 

When reading the first "2.3" scanf read up to the "." realizes it is no longer a valid integer and stops. So ".3" is left in the buffer, then you type "2 3.4" so ".3\n2 3.4" is in the buffer. When scanf parses that it gets ".3" and "2" just like your example shows.

jcopenha
ok, i see, thanks.
mikeyickey
+2  A: 

In C, scanf() is basically useless for real world input from human users - it is intended for reading fixed format text from data files. If you are using C++, you should be using iostream input, and in either case you should really be writing your own parsing routines for your specific input requirements.

anon
+5  A: 

Others have answered your specific question but I'd like to offer one piece of advice. Never use scanf() or fscanf(). Ever. Seriously.

Failure during a [f]scanf() operation invariably leaves your file pointer at an indeterminate location. Since most input from users is generally based on lines (except in GUIs), the option of using fgets() and sscanf() is always better, in my opinion.

It has the advantage of leaving the input pointer at a known point (the start of the next line) and allowing you to manipulate the line that you just read in in many different ways, not just that dictated by the scanf() family.

In other words, if the sscanf() fails, you still have the line available for other purposes (rescan with a different format string or even simply output it with an error) without having to go through stdio gymnastics to get back to the start of the line in the file (hard with a file, impossible with stdin from a terminal).

paxdiablo
anon
If it weren't for the book that I was reading I'd be using fgets.I've known scanf is bad for a while, I'd never use scanf in a production environment (if I ever get to the point where I have a production environment to write software for). I was just looking for a little more background information.Thanks SO!
mikeyickey
A: 

I would read the lines in and use sscanf for parsing each line. I agree with others, there are better methods than sscanf though.

kenny
A: 

It's called data overflow. Use fflush(stdin); inside the loop.

 while(scanf("%lf %d", &x, &exp) ==2)   
   { 
      fflush(stdin);   
      xpow = power(x, exp);
      printf("%.3g to the power %d is %.5g\n", x, exp, xpow);        
      printf("enter the next pair of numbers or q to quit.\n");    
   }
adatapost
The use of fflush() on an input stream is not portable C.
caf