Перебор массива указателей на функции

У меня есть эта структура:

typedef struct {
    void (*func)(instruction);
    union {
        double db;
        char ch;
    };
} instruction;

В моем исходном файле у меня есть массив этих инструкций. Мой вопрос в том, как мне пройтись по этому массиву и выполнить каждую функцию структуры?

Я думал, что знаю, как это сделать, но тот факт, что функция инструкции имеет параметр, который является инструкцией, кажется, вызывает проблемы. Таким образом, это не работает:

int i;
    for (i = 0; i <= instr_count; i++) {
        (*instr[i].func) (instr[i]);
        }

instr — массив инструкций.

Вот функция, которая заполняет массив. Сам массив объявляется в начале файла.

void read_instructions()
{
    char* str;
    char *instruct;
    int n;
    char c;
    instruction next = {0};
    while (!feof(datafile)) {
        // Fetch the next string
        // if (push or pop), get the next argument
        // create instructiwn and add to instruction array
        str = get_next_string();

        instruct = strtok (str, " ");

        if (strncmp (instruct, "P", 1) == 0) {
            char *arg = strtok (NULL, " ");
            if (strncmp (str, "PUSH", 4) == 0) {
                next.func = pushFunc;
            }
            else {
                next.func = popFunc;
            }
            n = arg[0];
            if (n > 64 || n < 71)
                next.ch = n;
            else {
                double n;
                scanf ("%lf", arg, n);
                next.db = n;
            }
            instr[instr_count] = next;
            instr_count++;
        }
        else {
            c = instruct[0];


            switch (c) {
            case 'A' :
                next.func = addFunc;
                break;
            case 'S' :
                next.func = subFunc;
                break;
            case 'M' :
                next.func = multFunc;
                break;
            case 'D' :
                next.func = divFunc;
                break;
            default :
                break;
            }
            instr[instr_count] = next;
            instr_count++;
        }
    }
    fclose (datafile);
}

В качестве краткого пояснения, этот код берет файл «промежуточного кода», определяет инструкцию и создает структуру инструкции для каждой из них, которая содержит соответствующий указатель на функцию.

Запуск кода дает мне эту ошибку времени выполнения:

«Необработанное исключение по адресу 0x00000000 в Interpreter.exe: 0xC0000005: нарушение прав доступа». (Составлено с использованием VS 2010).


person Troncoso    schedule 09.07.2012    source источник
comment
Похоже, один из ваших указателей на функции был указателем NULL.   -  person FatalError    schedule 09.07.2012
comment
Это происходит сбой именно в какой строке?   -  person alk    schedule 09.07.2012


Ответы (2)


Трудно сказать, не глядя на остальную часть вашего кода, но адрес, указанный в ошибке (0x00000000), подразумевает, что один из ваших указателей на функции в массиве — NULL.

Не могли бы вы убедиться, что ваш массив правильно инициализирован, прежде чем пройтись по нему?

person reuben    schedule 09.07.2012
comment
Я отредактировал свой пост, включив в него функцию, которая должна заполнить массив. - person Troncoso; 09.07.2012
comment
@Troncoso Рассмотрим случай, когда встречается что-то отличное от «P», «A», «S», «M» или «D». Как выглядит ваш ввод? - person reuben; 09.07.2012
comment
Мой подход очень строг. Инструкции только Pop, Push, Add, Sub, Mult и Div. Каждая инструкция находится на отдельной строке. Поскольку это задание класса, оно не предназначено для проверки неправильного ввода. - person Troncoso; 09.07.2012
comment
@Troncoso ... и вы абсолютно уверены, что instruct[0] всегда является одним из «P», «A», «S», «M» или «D»? В любом случае, вы должны попробовать запустить это под отладчиком, чтобы увидеть, где происходит сбой, и, в идеале, пройтись по вашей логике, чтобы понять, почему. - person reuben; 09.07.2012
comment
Да. Каждая строка начинается с одного из этих символов. У меня счетчик инициализирован до 0 и увеличивается каждый раз, когда добавляется инструкция. Сбой происходит в той строке, которую я пытаюсь написать. Без него программа компилируется нормально. - person Troncoso; 09.07.2012
comment
@Troncoso Это не совсем то, о чем я спрашивал - я тонко спрашивал, есть ли вероятность ошибки в вашей логике синтаксического анализа, а не содержит ли ваш входной файл что-либо еще. В любом случае, я поддерживаю свою рекомендацию запустить отладчик. - person reuben; 09.07.2012
comment
Ах. Ага. Я тоже так думал. Я понятия не имею, делают ли функции, которые я использую, то, что я от них ожидаю, чтобы правильно анализировать строки. Я посмотрю, что я не могу найти с помощью отладки. - person Troncoso; 09.07.2012
comment
Вы должны изменить регистр default: в операторе switch, чтобы напечатать сообщение об ошибке Неверная инструкция или что-то в этом роде. - person Chris Dodd; 09.07.2012
comment
После отладки я обнаружил, что мои методы синтаксического анализа не дают мне результатов, которые я ожидал. После их исправления мои ошибки исчезли. Большое спасибо! - person Troncoso; 11.07.2012

В зависимости от того, является ли instr массивом instruction или instruction *, вы хотите либо

instr[i].func(&instr[i]);

or

instr[i]->func(instr[i]);

Я подозреваю, что вам нужен первый (массив instruction), поскольку то, что у вас есть, будет скомпилировано (с предупреждениями для большинства компиляторов) для этого; вы просто получите мусор для аргумента в функции.

Исключение, которое вы получаете, предполагает, что это не ваша проблема, однако, у вас, вероятно, есть инструкция с указателем NULL func в вашем массиве.

Изменить

Похоже, вы делаете классическую ошибку while(!feof(input)) — всякий раз, когда вы видите это, это почти всегда неправильно.

Проблема в том, что после того, как вы прочитаете последнюю строку ввода, feof по-прежнему будет возвращать false - он не вернет true, пока вы не попытаетесь прочитать PAST конец ввода и не получите результат EOF. Таким образом, вы получите дополнительную итерацию цикла с пустой строкой после окончания вашего входного кода, что, вероятно, приведет к сбою, который вы видите.

то, что вы, вероятно, хотите, это что-то вроде while (!(str = get_next_string())) или, возможно, while (!(str = fgets(buffer, sizeof(buffer), datafile)))

person Chris Dodd    schedule 09.07.2012
comment
Я отредактировал свой пост, включив в него функцию, которая должна заполнить массив. - person Troncoso; 09.07.2012