C++ wft?



  • I was in my c++ class today and my teacher was showing us how to get an integer out of a character from a string, and it smelled fishy.

    d += (bnum.at[i] - '0') * p;

    That was what we had to do, where bnum was a string that held a binary number in string format (after all, a binary number might be larger than an int can hold). This just smells really fishy to me. Anyone care to enlighten me as to the proper way? 



  • int i = 0; total = 0;

    while (i < bnum.length())

    {

        total = (bnum.at(i) - '0') + (total * 10);

        i++;

    }

     

    that might be what you want.  im not sure i understand the full extent of the problem.



  • What do you think is wrong with that? Out of context, there's no apparent problem.



  • I presume p is equal to 2^i and that this is inside a for loop.  In which case it's perfectly acceptable, if not optimal.



  • @bstorer said:

    I presume p is equal to 2^i and that this is inside a for loop.  In which case it's perfectly acceptable, if not optimal.

     

    2 << i would be optimal.



  • ok after actually reading the original post and (hopefully) understanding it correctly:
     

    unsigned int conversion(const string& bnum)
    {
      unsigned int total = 0;
      unsigned int addend = 1;

      for (int i = bnum.length() - 1; i >= 0; i--)
      {
        total += (bnum.at(i) - '0' ? addend : 0);
        addend <<= 1;
      }
      return total;
    }

     

    works for me.  this is also assuming your binary number is unsigned and an integer.  oh and if you dont like ternary shutup i do. 



  • int atoi(const string & num) { return atoi(num.c_str()); }
    
    -- or --
    int atoi(const string & num) {
      int ret = 0;
      string::size_t len = num.length(); // if not it's size or count
      for (string::size_t i = 0; i < len; i++) {
        if (is_numeric(num[i])) { //Note .at() is the same as []
          ret += (num[i] - '0'); // What's with the * P in the OP?
        }else {
          ret = 0; break; errno = WHATEVER_THE_STANDARD_USES;
        }
      }
      return num;
    }
    


  • Incidentally, has anyone else notice that the Subject is "C++ wft" (emphasis mine)?  Is that not, truly, the Real WTF?



  • @bstorer said:

    Incidentally, has anyone else notice that the Subject is "C++ wft" (emphasis mine)?  Is that not, truly, the Real WTF?

    If not, then surely the Real WFT. 



  • What Fa Tuck?



  • The wtf that I think was about the casting of the integer to a character or string. My instructor said we [i]had[/i] to add 0 to it to convert it to a character or string, that there was no other way.



  • @malfist said:

    The wtf that I think was about the casting of the integer to a character or string. My instructor said we [i]had[/i] to add 0 to it to convert it to a character or string, that there was no other way.

    Why would any sane person expect int num = (int)'3'; to set num as 3? Furthmore why does it do such a bizzare thing? It's like asking a bug to happen.



  • @Lingerance said:

    @malfist said:
    The wtf that I think was about the casting of the integer to a character or string. My instructor said we [i]had[/i] to add 0 to it to convert it to a character or string, that there was no other way.
    Why would any sane person expect int num = (int)'3'; to set num as 3? Furthmore why does it do such a bizzare thing? It's like asking a bug to happen.

    It doesn't. It sets it to 51. 



  • i dont see any casting in the original post though.  however, if you want to get the value of the character '3', its '0' + 3 (or just '3'), unless you want to memorize your ascii tables.


     



  • @segmentation fault said:

    i dont see any casting in the original post though.  however, if you want to get the value of the character '3', its '0' + 3 (or just '3'), unless you want to memorize your ascii tables.

    All casting in the original post is implicit. 



  • like i said, i dont "see" any casting ;)

     

    if you have a character which you know is a representation of a digit '0' through '9', subtracting '0' from it is the best way to get the value which it represents.

     

    im still confused though.  is this string supposed to be a number in base 10 or base 2?



  • @segmentation fault said:

    like i said, i dont "see" any casting ;)

     
    if you have a character which you know is a representation of a digit '0' through '9', subtracting '0' from it is the best way to get the value which it represents.

     im still confused though.  is this string supposed to be a number in base 10 or base 2?

    @malfist said:

    where bnum was a string that held a binary number in string format



  • strtoul(s,NULL,2)?



  • Why are you learning C stuff in a C++ class?



  • @Daid said:

    Why are you learning C stuff in a C++ class?

    strings are not C. 

    @Obfuscator said:

    strtoul(s,NULL,2)?

    that will work if you pass bnum.c_str(), but im guessing this is a typical college class in which the teacher wants you to actually learn whats going on by having you reinvent the wheel.  I remember the days of writing countless classes/algorithms that already exist.  good times.  that also answers part of the the "why are you learning C stuff" question.



  • @malfist said:

    bnum.at[i]

    That syntax would only make sense if bnum was an object containing a member variable at (of type either char* or std::string). But what you probably meant is bnum[i].



  • @apetrov87 said:

    That syntax would only make sense if bnum was an object containing a member variable at (of type either char* or std::string). But what you probably meant is bnum[i].

    Or bnum.at(i)  - I forgot that string::at() exists.

     



  • @Lingerance said:

    ret += (num[i] - '0'); // What's with the * P in the OP?

    Because the code doesn't work without multiplying by a multiple of 10 each time. Try your code on something simple like '18':

    1. first it adds 1 to ret, so ret = 1

    2. then it adds 8 to ret, so ret = 9

    Thus it turned '18' into the number 9.

    What it's supposed to do is loop through the string backwards, and multiply the converted number by a multiple of 10. On the first iteration it multiplies by 1, then it multiplies by 10, then 100, then 1000, etc. Let's try it on '18' really quick:

    1. first it adds (8 * 1) to ret, so ret = 8

    2. then it adds (1 * 10) to ret, so ret = 18

     

    See? That's why it multiplies by p. I'm guessing there's a line that says p *= 10 at the end of the loop, and p is initially set to 1. 



  • Re: C++ wtf?

    I figured out what was going on, if you case '0' into an int from a char, you can subtract a single digit from it to figure out what it is because of the ASCII codes. Needless to say, I found it out on my own and the teacher had no idea. 



  • I figured out what was going on, if you case '0' into an int from a char, you can subtract a single digit from it to figure out what it is because of the ASCII codes. Needless to say, I found it out on my own and the teacher had no idea.
    Why do you keep trying to sound better than your teacher? First you felt the need to question the legitimacy of the code sample (which ended up being correct), and now you're trying to make it seem like your teacher doesn't even understand their own code. I wouldn't be the least bit surprised if they just couldn't figure out what you were trying to ask them.

    Anyway, to give a full description of what the code is doing, you need to understand that char and int8s are one in the same. You don't cast '0' from a char to an int because it already is one. The reason C and C++ have the concept of chars and let you define them using the '0' syntax because it's human-readable. Here's a full and ridiculously tedious description of what the code does (for reference, the code is "d += (bnum.at[i] - '0') * p"):

    1. first it retrieves the ith character from the character array (which is functionally equivalent to bnum[i] or *(bnum++)).
      • keep in mind that this character is actually just an int8 containing the ascii value of that character
    2. we then subtract the ascii value that matches the character '0' (which is also an int8) and we get another int8 as the result
    3. now we multiply that int8 by the value in p, where p is most likely an int containing a multiple of 2 (for a binary conversion)
      • while it would have been faster to do a simple bit shift, multiplying by p allows the function to be extended to include other number bases <= 10)
      • before we run the multiplication, the code most likely automatically casts the int8 into a normal int so that the types match
    4. finally, we add this int back into d (where d is of course initialized to 0)

    If you ever find yourself in a similar situation, where a line of code seems more complex than it needs to be, split the line up into multiple pieces and print out the values at each line. Once you see and understand exactly how the code works, it's a lot easier to determine which parts can be removed. In this case, nothing can be removed without breaking the intended functionality.



  •  I am not trying to sound better than my teacher, she did not understand the code and hence could not explain it to me. Therefore I had to look it up. I didn't know anymore than she did. I do now (refering to this once instance only, not programming on a whole) because I bothered to look it up, she never did and next semster if she gets the same question, still won't be able to explain it.

     As to another point you made, all the numbers in that class was base 10 so...yet I digress, even if you are using only base 10, you never know when you will need to expand that to other bases so adding in support at the begining is usually best.



  • I was mainly bothered by how it was "needless to say" that your teacher had no clue what was going on, since that means you were expecting that from the start. I'll stop being the party pooper though since I don't know your teacher. Sorry for sounding like an ass.

    About the base 2 thing, I was referring to how you said the numbers were all "binary strings" in the first post, making me think the strings looked like this: "010001101110". But yeah, the code will work for any base < = 10 (since after 10, you'd need to add extra code to get A, B, C, D, E, and F characters working since you can't just subtract '0').



  • @malfist said:

    I figured out what was going on, if you case '0' into an int from a char, you can subtract a single digit from it to figure out what it is because of the ASCII codes.

     

    That's so old that it's in the original edition of K&R. How can people not know that? 



  •  It's called 'Introduction to C++'



  • My teacher thinks that the best way to pass a color to glMaterialfv() is by casting our homegrown Vec3 class to a float pointer. And to add insult to injury, glMaterialfv() expects the array to contain four floats. You can probably guess what his IDE of choice is.



  • Use a standard library function like atoi() or strtol().

    If you want to talk about the correct way to WRITE the atoi() function, that's a different matter, and actually quite a bit more difficult than writing the reverse function.  Consider first the sub-problem of determining when a string represents a valid integer representation.


Log in to reply