2015-01-29 2 views
1

Я построил родовое двоичное дерево поиска.Общая функция объявления Stuct

typedef struct Tree { 
    void* data; 
    struct Tree *left; 
    struct Tree *right; 
}Tree; 

И две функции, которые создают дерево с различными переменными типа данных.

Tree* GetNewTreeInt(){ 
    Tree* newTree = (Tree*)malloc(sizeof(Tree)); 
    *((int*)newTree->data); 
    newTree->left = newTree->right = NULL; 
    return newTree; 
} 

Tree* GetNewTreeChar(){ 
    Tree* newTree = (Tree*)malloc(sizeof(Tree)); 
    *((char*)newTree->data); 
    newTree->left = newTree->right = NULL; 
    return newTree; 
} 

Я попытался создать общую функцию, сохранить функцию по адресу

Tree* CreateTree(); 

    int main() { 
    void* root; 
    scanf("%d", &choose); 
    if(choose==0){ 
     Tree* CreateTree=GetNewTreeInt(); 
     (Tree*)root=CreateTree(); 
    } 

Но я получаю следующее сообщение об ошибке: называется тип объекта «Дерево *» (так называемый "STRUCT Tree *) не является функциональным или функциональным указателем

+0

Вы сдаете на другой стороне задания ... 'root = (void *) CreateTree()' – user590028

+1

Строка '* ((int *) newTree-> data);' не имеет никакого эффекта make' GetNewTreeInt 'и' GetNewTreeChar' точно такие же функции. – nwellnhof

+0

@nwellnhof инициализация переменных будет выполняться позже после ввода от пользователя – gbox

ответ

1

Похоже, вы пытались использовать указатель на функцию. Для этого вам нужно будет объявить указатель на функцию к функции, которые возвращают Tree*, а не Tree* непосредственно:

if(choose==0) { 
    Tree* (*CreateTree)(void); 
    CreateTree = &GetNewTreeInt; 
} 

Однако, ваши две функции идентичны, так как линия *((int*)newTree->data); не имеет побочных эффектов. Вы можете просто создать функцию, как это вместо:

Tree* GetNewTreeInt(void){ 
    Tree* newTree = (Tree*)malloc(sizeof(Tree)); 
    newTree->left = newTree->right = NULL; 
    return newTree; 
} 

Это когда вы получаете доступ tree->data, что вам нужно, чтобы бросить void * к указателю типа вы знаете, он содержит. Если вы не знаете, какой тип дерева у вас снаружи, вы должны добавить еще одно поле в свою структуру, которое означает, какой тип данных хранится. Если вы только сохраняете небольшие типы данных, такие как int и char Я бы рекомендовал использовать объединение вместо указателя void, так как объединение будет хранить данные внутри Дерева в памяти. В любом случае вам все равно потребуется что-то в вашем дереве, чтобы указать, какой тип данных он хранит.

typedef struct Tree { 

    // 0 means there is an int in tree->data.i, 
    // 1 means there is a char in tree->data.c 
    int type; 

    union { 
     int i; 
     char c; 
    } data; 

    struct Tree *left; 
    struct Tree *right; 

} Tree; 

Тогда ваши две функции становятся:

Tree* GetNewTreeInt(void){ 
    Tree* newTree = (Tree*)malloc(sizeof(Tree)); 
    newTree->type = 0; 
    newTree->data.i = 0; // Set an initial value 
    newTree->left = newTree->right = NULL; 
    return newTree; 
} 

Tree* GetNewTreeChar(void){ 
    Tree* newTree = (Tree*)malloc(sizeof(Tree)); 
    newTree->type = 1; 
    newTree->data.c = '\0'; // Set an initial value 
    newTree->left = newTree->right = NULL; 
    return newTree; 
} 

И вы можете использовать указатель на функцию так же, как это:

if(choose==0) { 
    Tree* (*CreateTree)(void); 
    CreateTree = &GetNewTreeInt; 

    Tree* tree = CreateTree(); 
    tree->data.i = 7; 
} 

Каждое дерево будет иметь либо data.i или data.c, но не оба, позже, когда вы пересекаете свои деревья, вы можете проверить их тип, чтобы узнать, какие:

if (tree->type == 0) { 
    int data = tree->data.i; 
} else if (tree->type == 1) { 
    char data = tree->data.c; 
} 

EDIT

Если вы действительно хотите использовать void *, вы можете добавить int type к вашей структуры, и при прохождении вы могли бы сделать что-то вроде этого:

if (tree->type == 0) { 
    int data = *(int *)tree->data; 
} else if (tree->type == 1) { 
    char data = *(char *)tree->data; 
} 
+0

что касается типа переменной, я не могу использовать union, но спасибо за объяснение о соединении. Что касается указателя на функцию, то что мне нужно сделать, это объявить функцию указателя внутри main и присвоить ей функцию? Дерево * (* CreateTree)(); означает, что это указатель типа дерева и что он хранит адрес, который является способом (* CreateTree), а не только CreateTree? – gbox

+1

@gbox Если вы не можете использовать 'union', вы все равно можете это сделать, добавив в свою структуру' type', чтобы определить, какой тип данных находится в 'tree-> data'. См. Раздел ** EDIT ** в самом низу моего сообщения – Paulpro

+1

'Tree * (* CreateTree) (void);' означает, что 'CreateTree' является указателем на функцию, в которой эта функция не принимает никаких аргументов и возвращает' Tree * '. '*' In '(* CreateTree)' указывает, что 'CreateTree' является самим указателем (указателем на функцию). – Paulpro

2

Это:

Tree* CreateTree(); 

..declares функцию CreateTree, которая возвращает Tree*, без полного определения функции (нет тела функции, только прототип).В то время как это:

Tree* CreateTree=GetNewTreeInt(); 

объявляет переменную типа Tree* имени CreateTree и вызывает функцию GetNewTreeInt() назначая ее возвращаемое значение CreateTree. Это дает вам вашу ошибку, так как вы уже объявили функцию с тем же именем.

Если вы хотите CreateTree быть указателем на функцию, и указать его в функции GetNewTreeInt, вам нужно объявить его как (глобально или в main, но не оба):

Tree *(*CreateTree)(); 

..и затем направьте его на GetNewTreeInt как это:

CreateTree = GetNewTreeInt; 

..и тогда вы можете вызвать функцию через указатель только с CreateTree(), как с нормальной функцией, например .:

root = CreateTree(); 

Если вы хотите ЬурейеЕ типа указателя на функцию, вы можете сделать это следующим образом:

typedef Tree *(*CreateTreeFuncType)(); 

... и объявить CreateTree как:

CreateTreeFuncType CreateTree; 

вместо использования упомянутый ранее синтаксис указателя функции.

Смежные вопросы