пустые указатели и функциональные указатели в элементах структуры - PullRequest
1 голос
/ 14 февраля 2011

Здравствуйте, у меня есть следующий код.

typedef struct __vector {
       int (*container_end) ( struct __vector *);
}vector;

и другая структура итератора со следующим объявлением:

typedef struct __iterator {      
    void *ptr_to_container;  
    int (*end)(struct __iterator *);
}iterator;                          

int                                 
end(iterator *itr) {                
    return (itr->ptr_to_container)->container_end(itr->ptr_to_container);
}       

Этот код не компилируется, так как ptr_to_container является пустым указателем.

Есть ли способ обойти эту проблему.

container_end функция будет определена отдельно, а ptr_to_container будет указывать на некоторый контейнер.

благодаря Avinash

Ответы [ 4 ]

2 голосов
/ 14 февраля 2011

Похоже, вы что-то упустили при определении структуры итератора. Почему итератор имеет указатель на функцию end, которая принимает итератор?

Если вы хотите, чтобы оно было действительно общим, вы могли бы вместо этого использовать это определение:

typedef struct __iterator {
    void * ptr_to_container;
    int (*end)(void *);
} iterator;

int end(iterator * it) { return it->end(it->ptr_to_container)); }

В определении вектора (и других типов данных) вы можете определить функцию для создания итератора:

static int vector_end(vector * v) { /* implementation omittted */ }

iterator * vector_create_iterator(vector * v)
{
    iterator * it = malloc(sizeof(iterator));
    it->ptr_to_container = v;
    it->end = vector_end;
    return it;
}

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

В качестве альтернативы вы можете настроить общий интерфейс структуры данных, например

typedef struct _container container;

struct _container {
    int (*end)(container * c);
};

Тогда реализация вектора должна «только» заполнить эту структуру контейнера:

typedef struct _vector {
    container c;
    /* other fields required by the vector */
}

static int vector_end(container * c)
{
    vector * v = (vector *) c;
    ...
} 

container * create_vector()
{
    vector * v = malloc(sizeof(vector));
    v->c.end = vector_end;
    return v;
}

... и итератор может работать только с общим контейнером:

typedef struct _iterator {
    container * c; 
    /* other fields used by the iterator, such as current position */
}

int end(iterator * it) { return it->c->end(it->c); }

Из примера кода, о котором идет речь, похоже, что вы смешали эти два подхода: -)

0 голосов
/ 14 февраля 2011

Вам необходимо явно привести * ptr_to_container к векторному указателю:

((__vector *)(itr->ptr_to_container))->container_end

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

Хотя я не очень понимаю, почему вы хотите иметь такую ​​конструкцию. Похоже, вы хотите иметь объектную ориентацию здесь с наследованием, но без явного указания чего-либо. Это не сработает. В C вам придется использовать менее общие структуры или перейти на C ++.

0 голосов
/ 14 февраля 2011

Если это должно быть void *, используйте

int                                 
end(iterator *itr) {                
    return ((vector)(itr->ptr_to_container))->container_end(itr->ptr_to_container);
} 

или укажите в итераторе, что это векторный итератор

typedef struct __iterator {      
    vector *ptr_to_container;  
    int (*end)(struct __iterator *);
}iterator;  //probably you'll need to rename to make type of iterator clear

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

0 голосов
/ 14 февраля 2011

Вы пробовали приведение к вектору *?

return ((vector *)(itr->ptr_to_container))->containter_end(itr->ptr_to_container);

Однако, вы уверены, что хотите это сделать? Вы используете itr для вызова функции, а затем передаете ее в эту функцию. Включение большего количества контекста (больше кода) поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...