What's wrong with this C code??

Discussion in 'Mac Programming' started by cybrscot, Dec 31, 2010.

  1. cybrscot, Dec 31, 2010
    Last edited by a moderator: Dec 31, 2010

    cybrscot macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #1
    Help! This is written just like another program I have done which works fine! I have listed variables, all float. My placeholders are all %.2f Compiler error pasted below also. Below the compiler errors, I have pasted my other program that "works". They are similar, only the non working program has an extra line of printf and scanf before outputting the answer. What's wrong??


    Code:
    #include <stdio.h>   
    
    main ( )
    {
    
    	float price ; 
    	float eps ;
    	float pem = (price/eps) ;
    	
    	printf ("Enter Current Stock Price: ") ;
    	scanf  ("%.2f", &price) ;
    	
    	printf ("Enter Current Earnings Per Share: ") ;
    	scanf  ("%.2f", &eps) ;
    	pem =  (price/eps) ;
    	
    	printf ("PEM: %.2f\n", pem) ;
    	
    	return 0 ;
    	
    }	
    
    Scott-Deans-MacBook-Pro:documents scottdean$ gcc ~/documents/pem.c
    /Users/scottdean/documents/pem.c: In function ‘main’:
    /Users/scottdean/documents/pem.c:14: warning: unknown conversion type character ‘.’ in format
    /Users/scottdean/documents/pem.c:17: warning: unknown conversion type character ‘.’ in format
    
    
    Working program:
    
    #include <stdio.h>
    
    main ( )
    {
    
    	int r ;
    	float pi = 3.14 ;
    	float volume = (4.0/3.0)*(pi)*(r*r*r) ;
    	
    	printf ("Enter radius of sphere: ") ;
    	scanf  (" %d" , &r ) ;
    	volume = (4.0/3.0)*(pi)*(r*r*r) ;
    	
    	printf ("Volume of a sphere: %.2f\n" , volume) ;
    	
    	return 0 ;
    }
     
  2. Mitthrawnuruodo Moderator emeritus

    Mitthrawnuruodo

    Joined:
    Mar 10, 2004
    Location:
    Bergen, Norway
    #2
    Many moons have passed since I touched C, so take this with a grain of salt, but I would try to change the two scanf lines from:
    to:
    or
    ...and see if that makes a difference.
     
  3. cybrscot thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #3
    Yep, your first suggestion did the trick. Man, staring at this code for 2 hours and I checked my book and it says that %f shows 6 places after the decimal, and to specify you can use %.1f, or %.2f or %.3f, etc, etc. BUT since your suggestion worked, what I did must only be valid in the call of printf, not scanf.

    Thanks and happy new year! I'm learning this so I can move on to Objective C.
     
  4. Sander macrumors 6502

    Joined:
    Apr 24, 2008
    #4
    The "number of significant digits" modifier works for printf, but not for scanf. Also, your code should read

    Code:
    int main(void)
    {
        // rest of your code here
    }
    Finally, it seems you're coming from an Excel background - you are assigning things to variables by using functions, but C doesn't work that way (i.e., "pem" and "volume" aren't automatically updated as soon as one of the variables it's based on changes). Your code works because you specify the formula again later, but it's still dangerous to do it this way (and there should have been a warning about this): In determining "pem", you devide "price" by "eps", but neither has been assigned a value yet. They might hold zero, so running your program is likely to get a divide-by-zero. Had the variables been ints, that would have given you a program termination.

    Hope that helps,
    Sander
     
  5. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #5
    Format specifier for scanf is different to printf

    Mitthrawnuruodo is right.

    The format specifiers for scanf and printf are not the same. See http://www.cplusplus.com/reference/clibrary/cstdio/scanf/ for details of the allowable format specifiers for scanf.

    I'm also concerned about the line:

    Code:
    float pem = (price/eps) ;
    
    This line is using the price and eps variables before they are initialised. You're basically dividing two unknown numbers at this point. Worse, if eps happens to be zero, you'll be in hell of undefined behaviour. You might find your program crashing randomly at start up.

    The initialisation is not necessary at this point. So I can sleep better tonight, please change it to:

    Code:
    float pem ;
    
     
  6. cybrscot, Dec 31, 2010
    Last edited by a moderator: Dec 31, 2010

    cybrscot thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #6
    Thanks all,

    Jiminaus, when I specify

    float pem = (price / eps), I know the values aren't determined yet, but aren't I just declaring pem at this point (as a float) and declaring it's value, which will be input by the user later?

    Just curious, but it is easer to do it your way.
    Thanks

    No I have no Excel background at all. I have no idea how to use Excel.. I'm teaching myself C so I can move on to Objective C. Just trying to follow my book, C programming by KN King, I'm only on Chapter 3!!

    Thanks and happy new year!

    Sander:

    Your right, when I ran my program again, and entered 0 as the eps, I got an answer of inf.

    However, it seems I can enter a negative eps, such as -2.44, and it outputs a negative number.

    So how can I accommodate a zero input by the user? The call of scanf can include decimals, but doesn't have to. Why can't the user enter a zero?

    Thanks
     
  7. jiminaus, Dec 31, 2010
    Last edited by a moderator: Dec 31, 2010

    jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #7
    This is no later. Unless you do some kind of loop (which you probably haven't encountered yet), code runs from the top to the bottom.

    At any line, the lines before have been done before and won't be done again; and the lines after will be done after and have not bearing on the current line.

    At the time the line declaring pem is executed, only the values of price and eps at that point are used. That line is exactly the same as the following 2 lines:

    Code:
    float pem ;
    pem = (price / eps) ;
    
    So, at the start of your program, the first thing your code does is divide price by eps and store the result in pem. At this point, price and eps have no defined value.

    The code then goes on to do the 2 printf's and 2 scanf's.

    Then again it divides prices by eps and stores the result in pem, replacing the result stored in pem at the start of the program.

    This only happens because you coded that line. It has nothing to do with the fact you put = (price / eps) in declaration of pem.

    The code then does the last printf just before returning (exiting).

    BTW That was my first post in 2011!!!!! Sydney just entered the new year. Happy New Year everyone!!!!!!
     
  8. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #8
    You are not. You are declaring pem and initialising it at the same time to an undefined value which involves dividing two undefined values. This is exceedingly bad. Asking for trouble on a massive scale. Instant fail. Totally unacceptable.
     
  9. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #9
    C is an iterative language. Code is run line by line, and the statements are evaluated using the values of the variables at the time the line executes. There is a class of concurrent languages that acts more like what you are expecting, but you are not using one. You cannot "set" a variable to an expression that is kept up-to-date as elements of the expression change. The right operand of = is evaluated once while the statement is bring evaluated, and the result is stored in the left operand.

    Obviously with loops and the dreaded goto a statement can be run multiple times, but this is still iterative, running the body of the loop iteratively.

    -Lee
     
  10. cybrscot thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #10
    Wow, thanks, you sound so strict, like a teacher!! lol I appreciate the feedback, it is invaluable!! Thanks so much!!
     
  11. Sander macrumors 6502

    Joined:
    Apr 24, 2008
    #11
    You will not exactly get a crash, like jiminaus ominously predicted. Division by zero in floating point is defined behavior (but wrong, as you noticed: Division by zero defaults to "division by positive zero", giving infinity; but division by "unspecified zero" should yield "not-a-number"). Anyway, it's still bad practise to use undefined variables. The compiler might have warned you about this, too.

    As to your later question about the users input: You will have to validate it yourself. If "eps" may not be zero, you should add a check for this. Something like this:

    Code:
    do
    {
        printf("Enter Current Earnings Per Share: ");
        scanf("%f", &eps);
        if (eps == 0)
            printf("Earnings Per Share can not be zero\n");
    } while (eps == 0)
    (Incidentally, some programming languages have a "repeat .. until" construct, which would perhaps be more appropriate in this case).

    A few additional remarks:

    1. Someone will reply to this post saying it's Bad Karma to compare floating point values for equality. However, they are repeating Dogma. In the case above, "eps" is not the result of some calculation which may induce rounding errors, so comparing directly with zero is fine.
    2. I don't think it's really forbidden for "Earnings Per Share" to be zero. So instead of prohibiting the user from entering zero, you should perhaps change the flow of your program and print out something like "PEM is undefined for zero EPS".
     
  12. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #12
    Floats: more than just numbers with a decimal point

    Wow. Division by positive zero versus division by negative zero. Floats can have values for infinity and "not a number" :eek:. Time for me to dive into that IEEE spec that's always talked about. I had no idea of these things. :eek:
     
  13. dmi macrumors regular

    Joined:
    Dec 21, 2010
    #13
    It may be defined by the IEEE 754 or IEC 60559 Standard for Binary Floating-Point Arithmetic, but it is undefined behavior in the ANSI X3.159-1989 or ISO/IEC 9899 C programming language standard

    Whether or not an implementation of the C programming language uses the IEC 60559 floating point standard is implementation defined.
    A conforming program can use IEC 60559 features while guarded by
    #ifdef _ _STDC_IEC_559_ _
    #endif
    When _ _STDC_IEC_559_ _ is defined, conformance to the IEC 60559 annex is indicated.
    the IEC 60559 annex provides for a FE_DIVBYZERO exception according to the state of the FENV_ACCESS pragma unless it is in the initializer for an object with static storage duration

    (if you don't understand all the caveats for when division by 0.0 is defined or permitted. it would be best to avoid it or to not depend on any particular expectation of what may happen)

    And you should avoid computations with uninitialized variables in any case.
    Using the value of an object while it is indeterminate is undefined behavior regardless of any implementation defined exceptions.
     
  14. cybrscot thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #14
    Wow, I'm glad I got my answer, this thread has gotten a bit over my head! I'm only on chapter 3!! But interesting nonetheless, and good to at least expose myself to some of these ideas, as they will come up again in the future I'm sure.
     
  15. mac2x macrumors 65816

    Joined:
    Sep 19, 2009
    #15
    King's book is excellent IMO; I have learned a lot from it (coming from Kochan's book, which is excellent too but less detailed). Stick with King and read it closely; he packs a ton of info in there. :)
     
  16. SidBala macrumors 6502a

    Joined:
    Jun 27, 2010
    #16
    Have you done any VHDL before?

    IIRC, VHDL is one language where I've seen where you can set a relationship like

    a = b+c

    and then update the values for b or c to automatically get the new value for a.

    Obviously, this is all done in hardware, so it is a totally different mechanism.
     
  17. cybrscot thread starter macrumors 6502

    cybrscot

    Joined:
    Dec 7, 2010
    Location:
    Somewhere in Southeast Asia
    #17
    Good feedback, thanks! I'm glad my book is a good one!!
     
  18. dmi macrumors regular

    Joined:
    Dec 21, 2010
    #18
    If you had reason to do that in C, you might use something like
    int a(){ return b+c; } // although using global values this way may not be the best style
    then evaluating a() automatically uses the current value of b and c

    or
    #define a (b+c)
    //which could also create certain maintenance troubles
     

Share This Page