C结构,函数指针和头问题(不确定是哪个原因)

hac*_*atu 0 c binary-tree struct function-pointers header-files

所以,我正在尝试用C创建这个二进制树程序,它只是不断抛出最糟糕的编译错误.每当我更改某些内容以找到导致错误的内容时,它就会发生变化!我没有忘记我的包含守卫,我曾经使用过#pragma.如果我将结构放在标题中,我会得到不兼容的类型,如果我把它放在.c中,我会重新定义pretty_print,当我重命名pretty_print时,它会消失.当我修剪bintree.c中的其他函数和标题时,错误更改为intTree未定义.如果我然后将intTree更改为int,则它变为不兼容的类型.如果我将标头合并到.c中,这就消失了.现在它已经消失了.我认为这些可能是单独的错误,而且变化的错误可能是我的坏事,但它正在发生,我不知道为什么.我将展示代码,演示尽可能多的这些,但每当我尝试复制我所做的时,它会抛出不同的错误.但我并不沮丧.我希望能够发布一个格式正确的问题和有用的信息,但我没有,尽管在这个程序上花了几个小时.

bintree.cxx

#include "bintree.h"

int add(intTree* root,int key,void* val){
    if(!root){
        root=malloc(sizeof(intTree));
        if(!root){
            return 1;
        }
        root->key=key;
        root->val=val;
        root->left=0;
        root->right=0;
        return 0;
    }
    if(key>root->key){
        if(root->right){
            return add(root->right,key,val);
        }else{
            root->right=(intTree*) malloc(sizeof(intTree));
            if(!root->right){
                return 1;
            }
            root->right->key=key;
            root->right->val=val;
            root->right->left=0;
            root->right->right=0;
            return 0;
        }
    }
    if(key<root->key){
        if(root->left){
            return add(root->left,key,val);
        }else{
            root->left=malloc(sizeof(intTree));
            if(!root->left){
                return 1;
            }
            root->left->key=key;
            root->left->val=val;
            root->left->left=0;
            root->left->right=0;
            return 0;
        }
    }
    return 2;
}

void* get(intTree* root,int key){
    if(!root){
        return 0;
    }
    if(key>root->key){
        return get(root->right,key);
    }
    if(key<root->key){
        return get(root->left,key);
    }
    return root->val;
}

int remove_root(intTree* root){
    if(!root){
        return 1;
    }
    if(root->right){
        root->key=root->right->key;
        root->val=root->right->val;
        return remove_root(root->right);
    }
    if(root->left){
        root->key=root->left->key;
        root->val=root->left->val;
        return remove_root(root->left);
    }
    free(root);
    return 0;
}

int remove_node(intTree* root,int key){
    if(!root){
        return 1;
    }
    if(key>root->key){
        return remove_node(root->right,key);
    }
    if(key<root->key){
        return remove_node(root->left,key);
    }
    return remove_root(root);
}

void delete(intTree* root){
    if(root){
        delete(root->right);
        delete(root->left);
        free(root);
    }
}

void pretty_print(intTree* root,int ws,int wso,void (*print_val)(void*)){
    if(!root) return;
    printf("%*s",ws,"");
    print_val(root->val);
    pretty_print(root->left,ws+wso,wso,print_val);
    pretty_print(root->right,ws+wso,wso,print_val);
}
Run Code Online (Sandbox Code Playgroud)

bintree.h

#pragma once

#include <stdlib.h>

typedef struct intTree_s{
    int key;
    void* val;
    struct intTree_s* left;
    struct intTree_s* right;
} intTree;

int add(intTree*,int,void*);
void* get(intTree*,int);
int remove_root(intTree*);
int remove_node(intTree*,int);
void delete(intTree*);
void pretty_print(intTree*,int,int,void(*)(void*));
Run Code Online (Sandbox Code Playgroud)

这些抛出了数百个关于intTree的错误类型的错误.对于我用来定义intTree的typedef/struct格式,这仍然存在.

bintree.c

#include "pretty_print.h"
void pretty_print(void){return;}
Run Code Online (Sandbox Code Playgroud)

pretty_print.h

void pretty_print(void);
Run Code Online (Sandbox Code Playgroud)

抛出"pretty_print"的冲突类型,但如果我重命名为"p",内联标题或将参数更改为"int v"则不会.这也适用于参数"int*a,void()(void)",就像在原始程序中一样.

最终的"错误":警告有关malloc,free,printf和puts的隐式重新定义.

bintree.cxx

struct intTree_s{
    int key;
    void* val;
    struct intTree_s* left;
    struct intTree_s* right;
};

typedef struct intTree_s intTree;

int add(intTree* root,int key,void* val){
    if(!root){
        root=malloc(sizeof(intTree));
        if(!root){
            return 1;
        }
        root->key=key;
        root->val=val;
        root->left=0;
        root->right=0;
        return 0;
    }
    if(key>root->key){
        if(root->right){
            return add(root->right,key,val);
        }else{
            root->right=(intTree*) malloc(sizeof(intTree));
            if(!root->right){
                return 1;
            }
            root->right->key=key;
            root->right->val=val;
            root->right->left=0;
            root->right->right=0;
            return 0;
        }
    }
    if(key<root->key){
        if(root->left){
            return add(root->left,key,val);
        }else{
            root->left=malloc(sizeof(intTree));
            if(!root->left){
                return 1;
            }
            root->left->key=key;
            root->left->val=val;
            root->left->left=0;
            root->left->right=0;
            return 0;
        }
    }
    return 2;
}

void* get(intTree* root,int key){
    if(!root){
        return 0;
    }
    if(key>root->key){
        return get(root->right,key);
    }
    if(key<root->key){
        return get(root->left,key);
    }
    return root->val;
}

int remove_root(intTree* root){
    if(!root){
        return 1;
    }
    if(root->right){
        root->key=root->right->key;
        root->val=root->right->val;
        return remove_root(root->right);
    }
    if(root->left){
        root->key=root->left->key;
        root->val=root->left->val;
        return remove_root(root->left);
    }
    free(root);
    return 0;
}

int remove_node(intTree* root,int key){
    if(!root){
        return 1;
    }
    if(key>root->key){
        return remove_node(root->right,key);
    }
    if(key<root->key){
        return remove_node(root->left,key);
    }
    return remove_root(root);
}

void delete(intTree* root){
    if(root){
        delete(root->right);
        delete(root->left);
        free(root);
    }
}

void pretty_print(intTree* root,int ws,int wso,void (*print_val)(void*)){
    if(!root) return;
    printf("%*s",ws,"");
    print_val(root->val);
    pretty_print(root->left,ws+wso,wso,print_val);
    pretty_print(root->right,ws+wso,wso,print_val);
}
Run Code Online (Sandbox Code Playgroud)

我似乎无法再生成原始错误,这是关于pretty_print的重新定义.我很少知道我对这个问题知之甚少(基本上就是这样).

Jon*_*art 6

隐式重新定义malloc,free,printf和puts.

这意味着您没有包含正确的头文件.将这些添加到调用这些函数的每个C文件中.

#include <stdio.h>      // printf, puts and friends
#include <stdlib.h>     // malloc/free
Run Code Online (Sandbox Code Playgroud)

不要将它们放在一些常见的头文件中 - 只有在它们暴露您在头文件本身中使用的类型时才这样做.

您正在获得"隐式重新定义",因为如果您不包含正确的头文件,编译器将根据您的使用情况隐式定义其签名(C,IMO的最愚蠢的特征).


人们似乎很难知道.c文件和头文件中的内容.这很简单:

  1. 开始将与此组件相关的所有内容(例如,您的intTree实现)放在一个.c文件中.(包括structs).标记所有功能static,这意味着文件外的任何人都看不到它们.

  2. 确定哪些功能是您可公开访问的API的一部分.static从这些函数中删除,并将其原型复制/粘贴到该.c文件的附带.h文件中.(例如int add(intTree* root,int key,void* val);).

  3. 确定是否struct需要显示任何内容,或者是否可以隐藏它们.最好将实际struct定义隐藏在.C文件中.您的公共API函数将仅指向这些结构,因此外部代码永远不需要知道这些结构的大小/偏移量struct.所以只需添加struct foo;到头文件中,将其定义保留在.C文件中.

例:

foo.c的

#include "foo.h"

/** Definition of struct foo - hidden to consumers of foo **/
struct foo
{
    int a;
    int b;
    int c;
};             /* This always gets forgotten :-) */

/** "private" internal function, marked static to hide from consumers **/
static void _foo_internal(struct foo *f)
{
    // ... internal function ****
}

/** Foo Public API **/
struct foo *new_foo(int a, int b, int c)
{
    struct foo* f;

    f = malloc(sizeof(*f));
    if (f == NULL)
        return NULL;

    _foo_internal(f);
    f->a = a;
    f->b = b;
    f->c = c;
}

int foo_get_a(struct foo *f)
{
    _foo_internal(f);
    return f->a;
}

void foo_set_a(struct foo *f, int val)
{
    _foo_internal(f);
    f->a = val;
}
Run Code Online (Sandbox Code Playgroud)

foo.h中

#ifndef FOO_H
#define FOO_H

/**
 * Consumers need to know only that struct foo exists,
 * not its size of member offsets.
 */
struct foo;

/** Prototypes for foo public API **/
struct foo *new_foo(int a, int b, int c);
int foo_get_a(struct foo *f);
void foo_set_a(struct foo *f, int val);

#endif /* FOO_H */
Run Code Online (Sandbox Code Playgroud)

test.c的

#include "foo.h"

int main(void)
{
    /**
     * No static instances of foo allowed!
     * test.c does not know the size of struct foo!
     */
    //struct foo my_foo;

    struct foo *pFoo;

    pFoo = new_foo(1,2,3);
    if (pFoo == NULL)
        return 1;

    set_foo_a(pFoo, 42);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)