Flummoxed - Please Help!

Discussion in 'C++' started by Mike Copeland, Feb 18, 2014.

  1. I have the following (rather simple, I think) code which compiles but
    executes in a bizarre way: the code in the subprogram is skipped when
    called. 8<{{
    Here's the code and the call to it I use:

    string spellNumber(double value)
    {
    bool showThousands = false;
    bool allZeros = true;
    int ii, dPos, nn;
    char wc;
    string digits, temp;
    ostringstream ossw;
    static string builder;
    ossw.str("");
    ossw << value;
    digits = ossw.str();
    dPos = digits.find('.');
    if(dPos != string::npos) digits.erase(dPos);
    nn = digits.length();
    wc = digits.back();
    for(ii = digits.length()-1; ii >= 0; ii--)
    {
    int ndigit = (int)(digits[ii]-'0');
    int column = (digits.length()-(ii+1));
    } // for
    // more code to be added here
    return builder;
    }
    ....
    spellNumber(123.45); // call the function

    I have, of course the normal stdafx.h header and "use namespace
    std;", and this is code from a small test program I use to debug new
    functions and such. Many other programs and many thousands of lines of
    code work fine, but this code is weird...and I can't see what's wrong
    with it!
    Please advise... TIA
     
    Mike Copeland, Feb 18, 2014
    #1
    1. Advertisements

  2. The logic error is on the line 42 of your original program, at least
    according to my crystal ball, which is the best source of information I
    have at this point, since you've chosen not to post the entire program.

    http://www.parashift.com/c++-faq/posting-code.html

    V
     
    Victor Bazarov, Feb 18, 2014
    #2
    1. Advertisements

  3. Fair enough; I was sloppy. Here's the entire program code:
    // CPP10 Test Bed Program MRCopeland 02/18/2014
    #include "stdafx.h"
    string spellNumber(double value)
    {
    int ii, dPos, nn;
    char wc;
    string digits;
    ostringstream ossw;
    static string builder;
    ossw.str(""); // Convert integer portion of value to string
    ossw << value;
    digits = ossw.str();
    dPos = digits.find('.');
    if(dPos != string::npos) digits.erase(dPos);
    nn = digits.length(); // Traverse characters in reverse order
    wc = digits.back();
    for(ii = digits.length()-1; ii >= 0; ii--)
    {
    int ndigit = (int)(digits[ii]-'0');
    int column = (digits.length()-(ii+1));
    } // for
    return builder;
    }
    int main(int argc, char *argv[])
    {
    string str = spellNumber(123.45);
    return EXIT_SUCCESS;
    } // main

    During execution, the following occurs during the IDE trace:
    1. The subprogram is entered and immediately jumps to the "return
    builder" statement. (Why?)
    2. Then, the function is reentered and code steps are taken - until the
    "if" statement executes. The logic works as expected with the data
    presented ("digits" is runcated to "123"), whereupon the function exits
    (!).
    3. The statements beyond the "if" are skipped for no apparent reason.
    Any thoughts?
     
    Mike Copeland, Feb 18, 2014
    #3
  4. I took your code and made only one change:

    //#include "stdafx.h"
    #include <string>
    #include <sstream>
    using std::string;
    using std::eek:stringstream;

    (since I have no idea what was in your 'stdafx.h' header). The program
    compiled and ran fine (under the debugger). Stepping through it showed
    that it followed all statements and returned an empty string (since no
    change is made to 'builder' object in the 'spellNumber' function).

    It sounds that you're trying to debug an optimized version of your
    program (a "release" version). Perhaps you should disable optimizations
    in order to step through it. The optimizer is often not the best tool
    for verifying the logic of your program because it can determine and
    throw away the code that has no effect. For instance, all the code that
    follows the 'if' statement has no side effect (no change is made to any
    memory location that would be noticed by the caller of the function),
    methinks.

    V
     
    Victor Bazarov, Feb 18, 2014
    #4
  5. During execution, the following occurs during the IDE trace:
    It gets weirder and weirder...
    First, I'm not producing (or testing) a Release version, and I have
    no non-normal optimizations set. I'm running "vanilla" VS2010 Express,
    afaics.
    Second, there are other things going that I hadn't mentioned:
    1. As I debug, some of the variables in the function don't show up, nor
    can I see their values during execution by holding my mouse over them
    while the code is being stepped through. (Highly unusual!.) The
    variables that don't show are all the scalars (ints and chars), while
    the non-scalars do show (and change as code executes).
    2. I have tried moving the position of the scalar variables within the
    routine, but no change there.
    3. I moved the scalars outside of the routine (making them global
    <gasp!>), and they show and change, as execution proceeds - as they
    should.
    4. Also, once these scalars are moved and debug normally, the code runs
    through the logic provided (!). (I know that nothing really changes in
    terms of the return string, but there's more logic to be added to do
    some of that - I'm just working out the logic to handle the data and
    expand it as needed.)
    Thus, it appears that the problem of code that isn't executed within
    the routine is some effect of the scalar data declared and used in the
    code (totally odd, in my experience...). I'm at a complete loss to
    understand this... 8<{{
    Here's my latest code (which as I said is working as I step through
    the debugger). <sigh>
    #include <string>
    #include <sstream>
    using std::string;
    using std::eek:stringstream;
    int ii, dPos, nn;
    char wc;
    int ndigit;
    int column;
    string spellNumber(double value)
    {
    string digitStr;
    ostringstream ossw;
    static string builder;
    ossw.str(""); // Convert integer portion of value to string
    ossw << value, digitStr = ossw.str();
    dPos = digitStr.find(".");
    if(dPos != string::npos)
    digitStr.erase(dPos);
    nn = digitStr.length(); // Traverse characters in reverse order
    wc = digitStr.back();
    for(ii = digitStr.length()-1; ii >= 0; ii--)
    {
    ndigit = (int)(digitStr.at(ii)-'0');
    column = (digitStr.length()-(ii+1));
    } // for
    // more logic to be added here...
    return builder;
    }

    int main(int argc, char *argv[])
    {
    string str = spellNumber(123.45);
    return EXIT_SUCCESS;
    } // main
     
    Mike Copeland, Feb 19, 2014
    #5
  6. Mike Copeland

    Öö Tiib Guest

    What you describe confirm what others said. Cut that "no non-normal" crap.
    Remove every last of "normal" optimizations if you want to step thru and
    see things. The compiler writers of Microsoft are far wiser than debugger
    writers of Microsoft that are far wiser than IDE writers of Microsoft.
    So if you want to see things of your program in IDE you *must* make
    the compiler as dumb as you only can.
     
    Öö Tiib, Feb 19, 2014
    #6
  7. Mike Copeland

    Geoff Guest

    The code as posted (and after making changes to make it compile due to
    missing definitions) copies nothing into builder, the returned string
    is empty.
     
    Geoff, Feb 19, 2014
    #7
  8. Mike Copeland

    Geoff Guest

    Are you looking at the Autos window or the Locals window? This
    behavior is normal for Autos. The variables disappear as they go out
    of scope.
    You are looking at Autos window.
    All of this returns a blank string under debug and release builds. Do
    you mean to return digits, not builder?
     
    Geoff, Feb 19, 2014
    #8
  9. Mike Copeland

    Geoff Guest

    What is this function supposed to do?
    Line above erases the decimal point and all after. Your string is now
    "123". Why do you need to do anything else to this string?

    OK, nn is 3, wc is '3'. Now what?
    WTF was this done for? You could have easily just said ndigit = nn. I
    don't know what you are going to do with the column variable but they
    both go out of scope when the for loop is completed, ii is 0xffffffff
    (-1?) which suggests something went wrong in the loop.
     
    Geoff, Feb 19, 2014
    #9
  10. It's the start of a routine that will "spell a number": to produce
    the sort of string data that's printed on a check. For example, 123
    yields "One Hundred Twenty Three". The code that processes the
    conversion isn't yet written...
    See above. I will process the cents part separately. Ultimately I
    want to print checks with the output from this routine.
    Again, I'm testing only part of the code logic. 8<}}
     
    Mike Copeland, Feb 19, 2014
    #10
  11. Mike Copeland

    Geoff Guest

    You misunderstood the intent of my comments. They were intended to
    tell you to properly document your code. State the purpose of the
    function, THEN write the function.
    .... and doing a very bad job of it by inspection. Those variables in
    the for() loop go out of scope and can't be referenced outside that
    loop. The loop becomes a no-op and yields nothing of interest. You
    never documented why you need ndigit or column. You can get ndigit by
    writing ndigit = digits.length() and immediately writing "one-hundred"
    or "two-hundred" based on ndigit == 3 alone, the for loop becomes
    superfluous.

    You never addressed the issues of the IDE mentioned in my other posts
    in this thread. What you are seeing is to be expected given the code
    you've fed it. Your variables are going out of scope as you step
    through the function and you are looking for them in all the wrong
    places. Change your style, use white space, learn scoping rules and
    declare your variables accordingly.

    string spellNumber(double value)
    {
    int ndigit, column;
    string digits;
    ostringstream ossw;
    static string builder;

    // Convert integer portion of value to string
    ossw.str("");
    ossw << value;
    digits = ossw.str();

    // truncate the string
    int dPos = digits.find('.');
    if(dPos != string::npos)
    digits.erase(dPos);

    // Traverse characters in reverse order
    int nn = digits.length();
    char wc = digits.back();
    for(int ii = digits.length()-1; ii >= 0; ii--)
    {
    ndigit = (int)(digits[ii]-'0');
    column = (digits.length()-(ii+1));
    }

    return digits;
    }
     
    Geoff, Feb 19, 2014
    #11
  12. Your function returns a copy of the empty string named 'builder'.

    Seeing this, the compiler can also determine that all the other code
    has no observable external effect and is at liberty to ignore it.
     
    guinness.tony, Feb 24, 2014
    #12
    1. Advertisements

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.
Similar Threads
Loading...