如何从递归函数返回一个指针,它将波兰表示法转换为反向抛光表示法?

时间:2014-12-16 20:08:20

标签: c++ c pointers recursion postfix-notation

我的一个朋友被赋予了一个编写函数来将波兰符号转换为反向抛光符号的赋值,所以最后一个字符串:" sin * - x 4 + 8 3&#34 ;,应该转换为:" x 4 - 8 3 + * sin"。有一些约束,所以例如:最后一个指针应该返回一个在堆上分配的内存,一个函数原型应该只包含一个参数,它应该是原始字符串。我知道使用静态变量是对人类的可怕罪行,但尽管我们提出的最好的事情是:

char * prefix2postfix( char ppn_in[] ){

    if (ppn_in[0] == '\0') {
        return ppn_in;
    }

    int i = 0; 
    char *left = "",
         *root = "";

    while (ppn_in[i] == ' ') i++;

    if (is_num(ppn_in[i]) || is_var(ppn_in[i])) {
        char tmp[8];
        memset(tmp, '\0', 7);
        tmp[0] = ' ';
        tmp[1] = ppn_in[i];
        root = tmp;
        left = prefix2postfix(ppn_in + i + 1);
    } else if (is_op(ppn_in[i])) {
        switch (ppn_in[i]) {
            case '+':
                root = " +";
                break;
            case '-':
                root = " -";
                break;
            case '*':
                root = " *";
                break;
            case '/':
                root = " /";
                break;
        }
        left = prefix2postfix(ppn_in + i + 1);
    } else if (strncmp(ppn_in, "sqrt", 4) == 0) {
        root = " sqrt";
        left = prefix2postfix(ppn_in + i + 4);
    } else if (strncmp(ppn_in, "sqr", 3) == 0) {
        root = " sqr";
        left = prefix2postfix(ppn_in + i + 3); 
    } else if (strncmp(ppn_in, "sin", 3) == 0) {
        root = " sin";
        left = prefix2postfix(ppn_in + i + 3); 
    } else if (strncmp(ppn_in, "cos", 3) == 0) {
        root = " cos";
        left = prefix2postfix(ppn_in + i + 3);
    } else if (strncmp(ppn_in, "tan", 3) == 0) {
        root = " tan";
        left = prefix2postfix(ppn_in + i + 3);
    } else if (strncmp(ppn_in, "log", 3) == 0) {
        root = " log";
        left = prefix2postfix(ppn_in + i + 3);
    }   


    printf("reached end of the function\n");

    static char buff[200];
    buff[199] = '\0';

    strcpy(buff, left); 
    strcat(buff, root);
    return buff;
}

问题是(并且它可能不是唯一的)我不知道如何正确地结束函数,以便只调用一次printf("reached end of the function\n");行,在这种情况下我可以使用malloc因为否则我最终会发生内存泄漏。任何建议都表示赞赏!

修改

我试图自己来一些东西,我最终会造成内存泄漏吗? (我知道这是非常低效的,但我分配了200个字节,将它们复制到一个新缓冲区,然后我使用了我自由调用的值)

char * prefix2postfix( char ppn_in[] ){

    if (ppn_in[0] == '\0') {
        return ppn_in;
    }

    int i = 0; 
    char *left = "",
         *root = "";

    while (ppn_in[i] == ' ') i++;

    if (is_num(ppn_in[i]) || is_var(ppn_in[i])) {
        char tmp[8];
        memset(tmp, '\0', 7);
        tmp[0] = ' ';
        tmp[1] = ppn_in[i];
        root = tmp;
        left = prefix2postfix(ppn_in + i + 1);
    } else if (is_op(ppn_in[i])) {
        switch (ppn_in[i]) {
            case '+':
                root = " +";
                break;
            case '-':
                root = " -";
                break;
            case '*':
                root = " *";
                break;
            case '/':
                root = " /";
                break;
        }
        left = prefix2postfix(ppn_in + i + 1);
    } else if (strncmp(ppn_in, "sqrt", 4) == 0) {
        root = " sqrt";
        left = prefix2postfix(ppn_in + i + 4);
    } else if (strncmp(ppn_in, "sqr", 3) == 0) {
        root = " sqr";
        left = prefix2postfix(ppn_in + i + 3); 
    } else if (strncmp(ppn_in, "sin", 3) == 0) {
        root = " sin";
        left = prefix2postfix(ppn_in + i + 3); 
    } else if (strncmp(ppn_in, "cos", 3) == 0) {
        root = " cos";
        left = prefix2postfix(ppn_in + i + 3);
    } else if (strncmp(ppn_in, "tan", 3) == 0) {
        root = " tan";
        left = prefix2postfix(ppn_in + i + 3);
    } else if (strncmp(ppn_in, "log", 3) == 0) {
        root = " log";
        left = prefix2postfix(ppn_in + i + 3);
    }   

    char * buff = malloc(200);
    buff[199] = '\0';

    strcpy(buff, left); 
    strcat(buff, root);

    if(*left != '\0')
        free(left);

    return buff;
}

1 个答案:

答案 0 :(得分:2)

你的解析并没有完全用两个分支进行递归,但是为了回答你的问题,你需要每次都使用malloc返回值,否则调用者不知道何时释放。我将示例保留为C代码,因为我在您的问题中没有看到任何C ++。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int is_num( char v ) { return isdigit( v ); }
int is_var( char v ) { return isalpha( v ); }
int is_op( char v ) { return ispunct( v ); }

char * prefix2postfix( char ppn_in[] ){

    if (ppn_in[0] == '\0') {
        char * ptr = malloc( sizeof( char ) * 1024 );
        ptr[0] = '\0';
        return ptr;
    }

    int i = 0; 
    char tmp[16];
    char *left = 0,
         *root = "";

    while (ppn_in[i] == ' ') i++;

    if ( is_var(ppn_in[i])) {
        tmp[0] = ' ';
        tmp[1] = ppn_in[i];
        char *tptr = &tmp[2];
        while( is_var(ppn_in[i + 1] ) )
            *tptr++ = ppn_in[++i];
        *tptr = '\0';
        root = tmp;
        left = prefix2postfix(ppn_in + i + 1);
    } else if (is_num(ppn_in[i]) || is_var(ppn_in[i])) {
        char tmp[8];
        memset(tmp, '\0', 7);
        tmp[0] = ' ';
        tmp[1] = ppn_in[i];
        root = tmp;
        left = prefix2postfix(ppn_in + i + 1);
    } else if (is_op(ppn_in[i])) {
        switch (ppn_in[i]) {
            case '+':
                root = " +";
                break;
            case '-':
                root = " -";
                break;
            case '*':
                root = " *";
                break;
            case '/':
                root = " /";
                break;
        }
        left = prefix2postfix(ppn_in + i + 1);
    } else if (strncmp(ppn_in, "sqrt", 4) == 0) {
        root = " sqrt";
        left = prefix2postfix(ppn_in + i + 4);
    } else if (strncmp(ppn_in, "sqr", 3) == 0) {
        root = " sqr";
        left = prefix2postfix(ppn_in + i + 3); 
    } else if (strncmp(ppn_in, "sin", 3) == 0) {
        root = " sin";
        left = prefix2postfix(ppn_in + i + 3); 
    } else if (strncmp(ppn_in, "cos", 3) == 0) {
        root = " cos";
        left = prefix2postfix(ppn_in + i + 3);
    } else if (strncmp(ppn_in, "tan", 3) == 0) {
        root = " tan";
        left = prefix2postfix(ppn_in + i + 3);
    } else if (strncmp(ppn_in, "log", 3) == 0) {
        root = " log";
        left = prefix2postfix(ppn_in + i + 3);
    }   


    printf("reached end of the function  '%s'  '%s'\n", left ? left : "", root );

    if( left )
    {
        strcat( left, root );
        return left;
    }
    char * buff = malloc( sizeof( char ) * 1024 );
    strcpy( buff, root );
    return buff;
}

int main( int argc, char ** argv )
{
    if( argc == 2 )
    {
        char * ptr = prefix2postfix( argv[1] );
        printf( "Result: %s\n", ptr );
        free( ptr );
    }
}

做你想做的事:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int is_binary_operator( const char * token )
{
    return ( ( *token == '+' ) ||
             ( *token == '*' ) ||
             ( *token == '-' ) ||
             ( *token == '/' ) );
}

int is_unary_operator( const char * token )
{
    return ( !strcmp( token, "sin" ) ||
             !strcmp( token, "cos" ) ||
             !strcmp( token, "tan" ) ||
             !strcmp( token, "exp" ) ||
             !strcmp( token, "log" ) ||
             !strcmp( token, "ln" ) ||
             !strcmp( token, "sqrt" ) ||
             !strcmp( token, "sqr" ) );
}

int reverse_polish_arranger( char ** tokens, size_t cnt, size_t iter/*, size_t depth*/ )
{
    /*printf( "%*sPeeking at %s\n", depth << 1, "", tokens[iter] );*/
    if( is_binary_operator( tokens[iter] ) )
    {
        int next_pos = reverse_polish_arranger( tokens, cnt, iter + 1 /*, depth + 1 */);
        int end_pos = reverse_polish_arranger( tokens, cnt, next_pos + 1 /*, depth + 1 */);
        char * ptr = tokens[iter];
        memmove( tokens + iter, tokens + iter + 1, sizeof( char * ) * ( end_pos - iter  ) );
        tokens[end_pos] = ptr;
        return end_pos;
    }
    else if( is_unary_operator( tokens[iter] ) )
    {
        int end_pos = reverse_polish_arranger( tokens, cnt, iter + 1 /*, depth + 1*/ );
        char * ptr = tokens[iter];
        memmove( tokens + iter, tokens + iter + 1, sizeof( char * ) * ( end_pos - iter ) );
        tokens[end_pos] = ptr;
        return end_pos;
    }
    else
        return iter;
}

char * reverse_polish( const char * expr )
{
    size_t index;
    size_t push_index = 0;
    size_t len = 0;
    char * result = 0;
    char * buffer = 0;
    char ** pointers = 0;

    /* Prepare the workspace. */
    if( !expr )
        return 0;
    len = strlen( expr );
    if( !( result = malloc( sizeof( char ) * len ) ) )
        return 0;
    if( !( buffer = malloc( sizeof( char ) * len ) ) )
    {
        free( result );
        return 0;
    }
    if( !( pointers = malloc( sizeof( char * ) * len ) ) )
    {
        free( result );
        free( buffer );
        return 0;
    }
    strcpy( buffer, expr );
    memset( pointers, 0, sizeof( char * ) * len );

    /* Cheap tokenize using space a delimiter. */
    pointers[push_index++] = buffer;
    for( index = 0; index < len; ++index )
        if( buffer[index] == ' ' )
            buffer[index++] = '\0', pointers[push_index++] = &buffer[index];

    /* printf( "Before:\n" );
     * for( index = 0; index < push_index; ++index )
     *    printf( "Token %3d: %s\n", index, pointers[index] );
     */

    /* Do the conversion. */
    reverse_polish_arranger( pointers, push_index, 0/*, 0*/ );

    /*
     * printf( "After:\n" );
     * for( index = 0; index < push_index; ++index )
     *    printf( "Token %3d: %s\n", index, pointers[index] );
     */

    /* Prepare output buffer. */
    result[0] = '\0';
    for( index = 0; index < push_index; ++index )
        strcat( strcat( result, pointers[index] ), " " );

    /* Cleanup temporary workspace */
    free( pointers );
    free( buffer );

    /* Return new string. */
    return result;
}

int main( int argc, char ** argv )
{
    if( argc == 2 )
    {
        char * reversed = reverse_polish( argv[1] );
        if( reversed )
        {
            printf( "Reverse: %s\n", reversed );
            free( reversed );
        }
        else
            printf( "Failed to reverse: %s\n", argv[1] );
    }
    return 0;
}

结果:

./a.out "sin * - x 4 + 8 3"
Reverse: x 4 - 8 3 + * sin