Passing string iterator to function

Tag: c++ , string , pointers , iterator Author: jkduifwuriew Date: 2014-04-22

I have a function I want to use in other function which gets number from string. In base funcion I create std::string::iterator and I want to pass it to other function that gets this number, skips spaces, and then outer function continues to search through string.

When I am using iterator I do something like *strPtr to get value, and *++strPtr to get value and move to another character. When I pass pointer to that I need to use **strPtr to get value and I hove no idea how to get value and increment iterator. :(

I did *++*strPtr and it kinda worked but it crashes when it quits internal function.

double calculate( char* x ){
std::string formula = x;
ValueStack valueStack;
OperatorStack operatorStack;

std::string::iterator strPtr = formula.begin();

while( *strPtr == ' ' )
{
    strPtr++;
}

if( *strPtr == '-' )
{
    std::string temp;
    temp += *strPtr;

    while( *++strPtr == ' ' );

    while( ((*strPtr <= '9' ) && (*strPtr >= '0' )) || (*strPtr == '.') )
    {
        temp += *strPtr;
        while( *++strPtr == ' ' );
    }

    char** x;
    valueStack.push( strtod( temp.c_str(), x ) );
}

while( strPtr < formula.end() )
{

    if( *strPtr == ' ' )
    {
        while( *++strPtr == ' ' );
    }

    if( operatorStack.isOper( *strPtr ) )
    {   
        if( *strPtr == ')' )
        {
            evaluate( &valueStack, &operatorStack );
            strPtr++;
        }

        else if( *strPtr == '(' )
        {
            operatorStack.push( *strPtr );

            while( *++strPtr == ' ' );

            if( *strPtr == '-' )
            {
                std::string temp;
                temp += *strPtr;

                while( *++strPtr == ' ' );

                while( ((*strPtr <= '9' ) && (*strPtr >= '0' )) || (*strPtr == '.') )
                {
                    temp += *strPtr;
                    while( *++strPtr == ' ' );
                }

                char** x;
                valueStack.push( strtod( temp.c_str(), x ) );
            }
        }

        else if( operatorStack.prior( *strPtr ) <= operatorStack.prior( operatorStack.top() ) )
        {
            evaluate( &valueStack, &operatorStack );
            operatorStack.push( *strPtr++ );
        }

        else operatorStack.push( *strPtr++ );
    }

    else
    {
        std::string temp;
        temp += *strPtr;

        while( *++strPtr == ' ' );

        while( ((*strPtr <= '9' ) && (*strPtr >= '0' )) || (*strPtr == '.') )
        {
            temp += *strPtr;
            while( *++strPtr == ' ' );
        }

        char** x;
        valueStack.push( strtod( temp.c_str(), x ) );
    }
}

evaluate( &valueStack, &operatorStack );

double ret = valueStack.pop();
if( pow(ret, 2) < 0.000000001 ) return 0;
return ret; 
}

To clarify, I want make function like this, and use it above:

void getValue( std::string::iterator strPtr, ValueStack* valueStack )
{
std::string temp;
    temp += *strPtr;

    while( *++strPtr == ' ' );

    while( ((*strPtr <= '9' ) && (*strPtr >= '0' )) || (*strPtr == '.') )
    {
        temp += *strPtr;
        while( *++strPtr == ' ' );
    }

    char** x;
    valueStack->push( strtod( temp.c_str(), x ) );
}
Post your code.
Post your code so we can see exactly what you are doing
We don't know what evaluate is doing. Therefore you need to either provide all the code, or remove the calls to functions we do not know about and recreate the issue.
valueStack.push( strtod( temp.c_str(), x ) ); is accessing an uninitialized variable x. This may crash your program because the strtod function dereferences x also. Read the documentation of strtod to see how to use it properly.
@Matt McNabb THANK YOU! It was causing a problem :)

Other Answer1

There are an easier way for iterating over a string you can, for instance:

    string str("3+5-4   -  3 / 4");

    for (string::iterator it = str.begin(); it!=str.end();++it)
    {
        if (!(*it == ' ')) {  // Skip spaces.

           if(isdigit(*it))
           {
             // Do your thing with ValueStack.
           }
           else
           {
               // Handle operators here.
               switch(*it)
               {
                   case('-'): break;
                   case('+'): break;
                   case('/'): break;
                   case('*'): break;
               }
           }
        }
    }

On the other hand, I recommend you take a look at Boost.Spirit. It will help you to achive what you're trying to do (evaluating mathematical expressions) in a more elegant way. Also in that link there are an example of a "calculator" just like you want but using spirit.

Your algorithm only supports one digit numbers. And its very hard to get multi-digit numbers supported without using some external library (such as Boost.Spirit for instance ;) ).

comments:

Thank you. It's purposed to calculate more complexed equations including negatives, floating point, and brackets. It works in this form, but I've wanted to call one function three or four times instead of putting quite long code this many times.
So, if its working what's wrong with the evaluate function? Why you don't use it?
It works. Maybe I didn't make it clear. I want to close the second part in other function and call it, for example getValue
@Pershing - It's purposed to calculate more complexed equations including negatives, floating point, and brackets. The issue with writing your code in the way you wrote it is that you will quickly go bonkers trying to enhance and maintain it. Your code will be doing all sorts of twists and turns trying to keep up. The formal way of writing such expression evaluators is using a grammar/parser or as stated, a library that implements this paradigm, and not do "character-by-character" looping in an adhoc fashion.
Thank you all for answering, I really apreciate that and it helps me a lot. But the question was: how do I pass an iterator into function to make it works and don't working on its copy which I think is the problem?

Other Answer2

One thing I see in your code is that you assume that std::string is null terminated. Most of your loops are not bounded properly. For example:

while( *strPtr == ' ' )
{
    strPtr++;
}

What if the entire string is spaces? What stops this loop from going into uncharted territory?

A std::string does not have to be null terminated, so there is no guarantee this loop will stop when it reaches the end of the string. You do the same sort of loop in other places in your code.

If you're going to loop this way, it would need to be written:

while( *strPtr == ' ' && strPtr != formula.end())
    strPtr++;

comments:

That's why I suggest iterating with the for loop for (string::iterator it = str.begin(); it!=str.end();++it). Actually, this code has many errors, and the main cause is the extensive use of * and ++. There is no need to complicate such trivial work.
Thank you. I've added some safety features :)