I don't understand this code.

Discussion in 'C++' started by JS, Mar 14, 2005.

  1. JS

    JS Guest

    #include <ctype.h>
    double atof(char s[]){

    double val, power;
    int i, sign;

    for (i = 0; isspace(s); i++)
    ;
    sign = (s == '-') ? -1 : 1;
    if (s == '+' || s == '-')
    i++;

    for (val = 0.0; isdigit(s); i++)
    val = 10.0 * val + (s - '0');

    if (s == '.')
    i++;

    for (power = 1.0; isdigit(s); i++){
    val = 10.0 * val + (s - '0');
    power *= 10.0;
    }
    return sign * val / power;
    }



    The first for loop never terminates and I guess nothing is executed in its
    body.

    How should (s - '0') be understood? Have never seen a char subtracted
    from another char before.



    JS
    JS, Mar 14, 2005
    #1
    1. Advertising

  2. "JS" <> wrote in message
    news:d14m9k$gmd$-c.dk...
    > #include <ctype.h>
    > double atof(char s[]){
    >
    > double val, power;
    > int i, sign;
    >
    > for (i = 0; isspace(s); i++)
    > ;
    > sign = (s == '-') ? -1 : 1;
    > if (s == '+' || s == '-')
    > i++;
    >
    > for (val = 0.0; isdigit(s); i++)
    > val = 10.0 * val + (s - '0');
    >
    > if (s == '.')
    > i++;
    >
    > for (power = 1.0; isdigit(s); i++){
    > val = 10.0 * val + (s - '0');
    > power *= 10.0;
    > }
    > return sign * val / power;
    > }
    >
    >
    >
    > The first for loop never terminates and I guess nothing is executed in its
    > body.


    It looks to me as if it should terminate in
    some fashion, either by finding a non-space
    or producing an address fault. (I assume
    that the data memory is not all whitespace.)

    Your interpretation of the empty statement
    is correct.

    > How should (s - '0') be understood? Have never seen a char subtracted
    > from another char before.


    That is the usual way of converting a sequential
    set of numeral character codes into their numeric
    equivalents. '0' maps to 0, ..., '9' maps to 9.

    --
    --Larry Brasfield
    email:
    Above views may belong only to me.
    Larry Brasfield, Mar 14, 2005
    #2
    1. Advertising

  3. JS

    Howard Guest

    "JS" <> wrote in message
    news:d14m9k$gmd$-c.dk...
    > #include <ctype.h>
    > double atof(char s[]){
    >
    > double val, power;
    > int i, sign;
    >
    > for (i = 0; isspace(s); i++)
    > ;
    > sign = (s == '-') ? -1 : 1;
    > if (s == '+' || s == '-')
    > i++;
    >
    > for (val = 0.0; isdigit(s); i++)
    > val = 10.0 * val + (s - '0');
    >
    > if (s == '.')
    > i++;
    >
    > for (power = 1.0; isdigit(s); i++){
    > val = 10.0 * val + (s - '0');
    > power *= 10.0;
    > }
    > return sign * val / power;
    > }
    >
    >
    >
    > The first for loop never terminates and I guess nothing is executed in its
    > body.
    >


    That loop moves the starting point of the parsing code up past any leading
    spaces. There is not protection there if the array passed contains only
    spaces and no null terminator at the end, so I assume it's a requirement
    that the function be provided a valid null-terminated string. If it never
    terminates, then you've given it invalid data.

    > How should (s - '0') be understood? Have never seen a char subtracted
    > from another char before.


    That's a common method if getting the values 0 through 9 from the characters
    '0' through '9'. It only works if your character set contains the
    characters '0' through '9' in order (which they all do, from everything I've
    seen, but I don't know if it's a requirement). If you subtract '0' from '0,
    you get 0. If you subtract '0' from '3', you get 3. Etc.

    The code is taking a string containing a representation of a floating-point
    number, and converting into an actual float value.

    -Howard
    Howard, Mar 14, 2005
    #3
  4. JS

    Guest

    There are a couple common idioms in the code you cite, and you have a
    question about each of them. Let's look at them in turn:

    > for (i = 0; isspace(s); i++) ;


    This "fast forwards" over spaces at the beginning of the number. This
    way the function will still work for things like " 1.234". The later
    parts expect the index i to be loooking at a number, so this puts it at
    the beginning.

    Remember that the expressions inside a for loop can have side effects.
    In this case, the index i is changing. I'll rewrite the for loop as a
    while loop that might be a little more clear:

    i = 0
    while( isspace(s) )
    i++;

    So what this does is, starting with the beginning of the string,
    increment the index i until s is not a space.


    > How should (s - '0') be understood? Have never seen a char

    subtracted
    from another char before.

    This is by far the most common way to convert a digit storted in a
    character (e.g. the character '4', as opposed to the character with
    ASCII code 4) to a number. In ASCII and probably most other character
    sets (though not all, so this isn't strictly portable), all the digits
    are together and in order. For instance, I'm pretty sure '0' has ASCII
    code 48. If so, '1' has ASCII code 49, '2' has ASCII code 50, etc. (If
    you're wondering, 48 is 30 hex, so the digits are from 30 to 39 hex.
    Letters start at 41 and 61 hex, or 65 and 97 dec.)

    When you subtract two characters you get the difference in their ASCII
    values. For instance, '2' - '1' translates to 49 - 48, which is 1.
    You'll notice because of the numbers' placement, all the subtractions
    work out "right". '9' - '4' is indeed 5 for example. (Note too that
    that is the integer 5, not '5'.) And so any digit minus '0' is that
    digit as an integer.

    In the atof function, s holds a digit that needs to be converted to
    an integer so that something sane can be done with it.

    A quick run through of the for loop on lines 13-14 might be as follows:
    (this part of the function is converting everything to the left of the
    decimal place to a number; indeed, if you were to look at the function
    atoi, you would probably see the same code up to that point except with
    val as an int instead of a double)

    - The string s contains "135", val starts out as 0 (the first
    expression in the for loop), and i starts as 0 (the for loop explained
    above doesn't iterate at all; the expression is false right from the
    start so i++ is never run)
    - The first iteration, val is multiplied by 10 to get 0, then to that
    is added s - '0' = s[0] - '0' = '1' - '0' = 1, so val = 1 after the
    first iteration
    - The second iteration, val is multiplied by 10 to get 10, then to that
    is added s - '0' = s[1] - '0' = '2' - '0' = 1, so val = 10+2 = 12
    after the second iteration
    - The third iteration, val is multiplied by 10 to get 120, then to that
    is added s - '0' = s[2] - '0' = '3' - '0' = 1, so val = 120+3 = 123
    after the third iteration
    - At this point, i = 4 and s[4] = '\0' (the null character that marks
    the end of every C string), so isdigit(s) is false and the loop
    terminates.

    Does the function make more sense now?
    , Mar 14, 2005
    #4
  5. JS

    Pete Becker Guest

    wrote:
    > In ASCII and probably most other character
    > sets (though not all, so this isn't strictly portable), all the digits
    > are together and in order.


    That's required, in both C and C++.

    --

    Pete Becker
    Dinkumware, Ltd. (http://www.dinkumware.com)
    Pete Becker, Mar 14, 2005
    #5
  6. JS

    JS Guest

    Thanks to all three of you for a very clarifying explanation!

    JS
    JS, Mar 14, 2005
    #6
  7. JS

    Guest

    Oh, I didn't know that. Thanks! You learn something every day! That's
    part of why I read these boards... ;-)
    , Mar 14, 2005
    #7
  8. On 15/3/05 5:55 AM, JS wrote:
    > #include <ctype.h>
    > double atof(char s[]){
    >
    > double val, power;
    > int i, sign;
    >
    > for (i = 0; isspace(s); i++)
    > ;
    > sign = (s == '-') ? -1 : 1;
    > if (s == '+' || s == '-')
    > i++;
    >
    > for (val = 0.0; isdigit(s); i++)
    > val = 10.0 * val + (s - '0');
    >
    > if (s == '.')
    > i++;
    >
    > for (power = 1.0; isdigit(s); i++){
    > val = 10.0 * val + (s - '0');
    > power *= 10.0;
    > }
    > return sign * val / power;
    > }
    >
    >
    >
    > The first for loop never terminates and I guess nothing is executed in its
    > body.


    It has the function of incrementing i to be an offset to the first
    non-whitespace character.

    > How should (s - '0') be understood? Have never seen a char subtracted
    > from another char before.


    Characters are represented by numbers, so that the character '0'
    translates into a particular number. In most if not all character sets,
    the characters that represent numbers are sequential. So whatever
    number '0' translates into, plus 1, will translate back into '1' and so on.
    Richard Cavell, Mar 15, 2005
    #8
  9. JS

    Sven Heyll Guest

    Let me comment on the code:

    > #include <ctype.h>
    > double atof(char s[]){
    >
    > double val, power;
    > int i, sign;
    >


    Eat whitespaces...
    > for (i = 0; isspace(s); i++)
    > ;


    Is the first char a "-"? in that case set sign to -1
    if it is a '+' not a minus do nothing but in either case: eat the char
    (+ or -)...
    > sign = (s == '-') ? -1 : 1;
    > if (s == '+' || s == '-')
    > i++;


    Start processing the digits until a non digit char occures.
    During process the current digit is found by substracing the charachter
    code wich symbolizes the 0, and is added to the variable that
    accumulates all digits. Of course this variable must be multiplied by 10
    before the digit is added, we are decimal format...
    > for (val = 0.0; isdigit(s); i++)
    > val = 10.0 * val + (s - '0');


    Ok all digits eaten.

    Now check for a '.' if there is one an exponent is expected. The '.'
    char is eaten of course.
    > if (s == '.')
    > i++;
    >


    Why does the following work? Very simple:
    There are three actually two possibilities:
    either the string contained
    a '.'
    a number
    or something else
    IT COULD NOT have contained a number as all numbers were eaten.
    That leaves two possibilities to consider:
    there was a '.' char(1)
    there was something else (2)
    Only a '.' char would have been eaten(case 1) not any other(necessaryly
    non-digit) char(case 2).
    It follows directly that the next character is a digit ONLY if a '.'
    char was eaten above.

    So the following loop can safely rely on that, and it also does so by
    (blindly) running as long as the current character is a digit.

    It accumulates the digits into the variable val in the same fashion as
    the first digit eating loop does. It also multiplies another
    variable(power) by 10 each loop, in order to be able to take the digits
    position after decimal point into account.
    > for (power = 1.0; isdigit(s); i++){
    > val = 10.0 * val + (s - '0');
    > power *= 10.0;
    > }


    The parts arer composed and returned...
    > return sign * val / power;
    > }
    >
    >
    >
    > The first for loop never terminates and I guess nothing is executed in its

    false
    > body.

    false also!! i++ belongs the the "body" i++ means "eat a
    character!" (in this case whitespace characters)
    >
    > How should (s - '0') be understood? Have never seen a char subtracted
    > from another char before.

    numbers are represented as a dense sequence in the character symbol
    table. To get 1 from a char containing '1' we can therefor substract
    the symbol table index of '1' from the index at '0':

    char cx = '1';
    int x = cx - '0';

    Hope I could ghelp you.

    Greetings,
    Sven Heyll
    Sven Heyll, Mar 17, 2005
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Simon
    Replies:
    9
    Views:
    307
    Default User
    Jul 18, 2006
  2. Peyman
    Replies:
    4
    Views:
    566
    mlimber
    Oct 31, 2006
  3. xianwei
    Replies:
    2
    Views:
    344
    xianwei
    Sep 20, 2007
  4. Matthew Wilson
    Replies:
    4
    Views:
    261
    Tim Roberts
    Jan 22, 2008
  5. None

    Don't understand these code.

    None, Apr 25, 2008, in forum: Javascript
    Replies:
    2
    Views:
    102
    Lasse Reichstein Nielsen
    Apr 27, 2008
Loading...

Share This Page