Ошибки в коде (конечный автомат)

Я немного схожу с ума, пытаясь исправить этот код. Я занимаюсь этим почти два часа и не могу найти, что не так.

Это простая программа, которая должна принимать некоторый текст в качестве входных данных и возвращать тот же текст со всеми числами, переключенными с десятичной системы на шестнадцатеричную.

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

int revNumber(int);

typedef enum { STATE_WORD, STATE_BLANK, STATE_NUMBER } state_t;

int main()
{
    int c;
    int readNum = 0;
    int writeNum = 0;
    int digit = 1;
    int sign = 1;

    state_t state = STATE_BLANK;

    while( (c = getchar()) != EOF )
    {
        switch(state)
        {
            case STATE_WORD:
                if( isspace(c) )
                    state = STATE_BLANK;
                putchar(c);
                break;

            case STATE_BLANK:
                if(c == '-')
                {
                    sign = -1;
                    state = STATE_NUMBER;
                }
                else if( isdigit(c) )
                {
                    readNum += (c - '0') * digit;
                    digit *= 10;
                    state = STATE_NUMBER;
                }
                else if( isspace(c) )
                    putchar(c);

                else
                {
                    state = STATE_WORD;
                    putchar(c);
                }
                break;

            case STATE_NUMBER:
                if( isdigit(c) )
                {
                    readNum += (c - '0') * digit;
                    digit   *= 10;
                }
                else
                {
                    writeNum = revNumber(readNum);
                    readNum = 0;

                    if(sign == -1)
                        putchar('-');

                    if(digit > 1)
                    {
                        if( isspace(c) )
                        {
                            printf("%x", writeNum);
                            state = STATE_BLANK;
                        }
                        else
                        {
                            printf("%d", writeNum);
                            state = STATE_WORD;
                        }
                    }
                    digit = 1;
                    sign  = 1;
                    putchar(c);
                }
                break;
        }
    }
}


int revNumber(int n)
{
    int revNum = 0;
    while(n != 0)
    {
        revNum += revNum * 10 + n%10;
        n   /= 10;
    }
    return revNum;
}

Программа, однако, работает некорректно, по какой-то причине я все время неправильно конвертирую в шестнадцатеричный формат. Почему это происходит? Большое спасибо.


person YoTengoUnLCD    schedule 23.11.2015    source источник
comment
Любой код ошибки, который вы получаете после компиляции кода.   -  person mumair    schedule 23.11.2015
comment
Что ты имеешь в виду? Я не получаю ошибок компиляции.   -  person YoTengoUnLCD    schedule 23.11.2015
comment
Попробуйте скомпилировать с -Wall -Wextra. Однако это не причина вашей проблемы.   -  person tonysdg    schedule 23.11.2015
comment
Есть ли какие-либо параметры, окружающие ввод? Например, ожидается ли, что пользователь будет вводить данные определенным образом (например, с пробелами между каждым отдельным словом / числом), или это полностью произвольно?   -  person tonysdg    schedule 24.11.2015
comment
Ну, моя идея заключалась в том, чтобы взять, например, текст hi123 ‹- не число, а 345 - это единица для hi123‹ - не число, а 159 - это единица.   -  person YoTengoUnLCD    schedule 24.11.2015
comment
@tonysdg По-прежнему компилируется отлично (я только забыл поставить return 0 на main).   -  person YoTengoUnLCD    schedule 24.11.2015
comment
Как я уже сказал - это не причина вашей проблемы :) Почему бы не прочитать весь ввод в виде строки, использовать strtok для проверки каждого отдельного раздела на наличие чисел (т.е. строка включает только числа), а затем проанализировать эти разделы с помощью чего-то вроде sprintf (buf, "%x", atoi ("345"))?   -  person tonysdg    schedule 24.11.2015
comment
Хм, я хотел знать, что не так с этим кодом, больше всего, если честно, так как я совершенно не понимаю, почему он не работает так, как задумано.   -  person YoTengoUnLCD    schedule 24.11.2015
comment
Совет от профессионала: вы можете создать около 20 хорошо названных функций из кода, который вы публикуете. Поступая так, вы можете начать понимать, что вы на самом деле делаете, и тогда вы, вероятно, очень легко обнаружите, что у вас проблема.   -  person Tormod Haugene    schedule 24.11.2015
comment
Ваша revNumber функция не работает. Смотрите мой ответ.   -  person Gillespie    schedule 24.11.2015


Ответы (3)


Когда я набираю 123 в командной строке, ваша программа внутренне сохраняет: 1*1 + 2*10 + 3*100 = 321, что в обратном порядке, хорошо. Но тогда ваша функция обратного 321 возвращает 146 вместо 123. Что-то там точно не так.

Предлагаю для начала взглянуть на это:

http://www.programmingsimplified.com/c/source-code/c-program-reverse-number

Проблема в том, что эта строка:

revNum += revNum * 10 + n%10;

должно быть:

revNum = revNum * 10 + n%10;

Если вы собираетесь скопировать функцию, вы должны, по крайней мере, убедиться, что она работает, прежде чем полагаться на нее в своем коде.

person Gillespie    schedule 23.11.2015
comment
Проблема заключалась в том, что я не скопировал эту функцию, я сделал ее и продолжал смотреть на нее, думая, что она работает нормально. Спасибо за помощь. - person YoTengoUnLCD; 24.11.2015
comment
Я просто предположил, что вы скопировали и вставили, потому что он очень похож на тот, который здесь, вплоть до странного интервала в n /= 10;. - person Gillespie; 24.11.2015

следующий код на самом деле не дополняет число двойкой, поскольку шестнадцатеричные значения не имеют знака, а имеют только величину.

Однако это работает, как ожидалось (для каждого тестового примера, который я использовал)

Он демонстрирует предпочтительную логику для работы с конечным автоматом, включая то, как легко обрабатывать переходы между состояниями.

следующий код не меняет местами цифры в номере, вы сможете легко добавить эту функцию, которая заменит вызов printf() в функции inNumber()

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

typedef enum { STATE_WORD, STATE_BLANK, STATE_NUMBER } state_t;


state_t inWord  ( char ch );
state_t inBlank ( char ch );
state_t inNumber( char ch );

int  number = 0;
char sign   = ' ';

state_t state = STATE_BLANK;


int main( void )
{
    int c;


    printf( "program will echo sentence with numeric sub strings output in hex format\n");
    printf( "Enter a sentence:");

    while( (c = getchar()) && (c != EOF) )
    {
        switch(state)
        {
            case STATE_WORD:
                state = inWord( c );
                break;

            case STATE_BLANK:
                state = inBlank( c );
                break;

            case STATE_NUMBER:
                state = inNumber( c );
                break;

            default:
                printf( "state machine contains invalid state\n");
                break;
        } // end switch

        if( '\n' == c )
        {
            break;
        }
    } // end while

    putchar( '\n');
    return 0;
} // end function: main


state_t inWord( char ch )
{
    state_t newState = STATE_WORD;

    if( isdigit( ch ) )
    {
        newState = inNumber( ch );
    }

    else
    {
        putchar( ch );
    }

    return newState;
} // end function: inWord


state_t inBlank( char ch )
{
    state_t newState = STATE_BLANK;

    if( isdigit( ch ) )
    {
        newState = inNumber( ch );
    }

    else if( isalpha( ch ) )
    {
        newState = inWord( ch );
    }

    else
    {
        putchar( ch );
    }

    return newState;
} // end function: inBlank


state_t inNumber( char ch )
{
    state_t newState = STATE_NUMBER;

    if( !isdigit( ch ) )
    {
        printf( "%X ", number );
        newState = inBlank( ch );
    }

    else
    {
        number *=10;
        number += ch-'0';
    }

    return newState;
} // end function: inNumber
person user3629249    schedule 23.11.2015

Ваша функция разворота создает число, отличное от того, что было введено. Измените "+ =" на "=", чтобы начать. поместите операторы печати для readNum и writeNum после функции, и вы увидите проблемы

Функция также не работает, если введенное число кратно 10. Вы можете понять эту часть.

person petEEy    schedule 23.11.2015
comment
Readnum хранится в обратном порядке, поэтому здесь есть revNum. Я не пытаюсь преобразовать его в шестнадцатеричный формат. - person YoTengoUnLCD; 24.11.2015
comment
Виноват. Я не понял цели revNum (). Я отредактировал свой ответ - person petEEy; 24.11.2015
comment
Нет, он должен работать нормально для кратных 10. Не могли бы вы привести пример, когда кратное 10 не сработает? - person Gillespie; 24.11.2015
comment
Ты прав. Я заметил, что вывод был выключен, и предположил, что это снова revNumber (). Что-то должно быть не так в его государственной машине. Это немного кода для простой задачи. Я не хочу все это интерпретировать ... - person petEEy; 24.11.2015