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

标签 c struct binary-tree function-pointers header-files

所以,我试图用 C 编写这个二叉树程序,但它一直抛出最糟糕的编译错误。每当我更改某些内容以查找导致错误的原因时,它就会发生变化!我没有忘记我的 include 守卫,我用过一次#pragma。如果我将结构放在 header 中,我会得到不兼容的类型,如果我把它放在 .c 中,我会得到 pretty_print 的重新定义,当我重命名 pretty_print 时它会消失。当我删除 bintree.c 和 header 中的其他函数时,错误更改为 intTree being undefined。如果我然后将 intTree 更改为 int,它就会变成不兼容的类型。如果我将 header 合并到 .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);
}

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*));

这些会引发数百个有关 intTree 是不完整类型的错误。这适用于我用来定义 intTree 的任何 typedef/struct 格式。

bintree.c

#include "pretty_print.h"
void pretty_print(void){return;}

pretty-print .h

void pretty_print(void);

抛出“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);
}

我似乎无法再次生成原始错误,该错误是关于 pretty_print 的重新定义。对于我对这个问题知之甚少(基本上就是这样),我深表歉意。

最佳答案

implicit redefinition of malloc, free, printf, and puts.

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

#include <stdio.h>      // printf, puts and friends
#include <stdlib.h>     // malloc/free

不要将它们放在一些通用的头文件中 - 仅当它们公开您在头文件本身中使用的类型时才这样做。

你会得到一个“隐式重定义”,因为如果你不包含正确的头文件,编译器将根据你的使用隐式定义它们的签名(C 的最愚蠢的特性,海事组织)。


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

  1. 开始将与此组件相关的所有内容(例如您的 intTree 实现)放在一个 .c 文件中。 (包括 struct)。将所有函数标记为static,这意味着它们对文件外部的任何人都不可见。

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

  3. 决定是否有任何 struct 也需要可见,或者它们是否可以隐藏。最好将实际的struct 定义隐藏 保留在.C 文件中。您的公共(public) 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;
}

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 */

测试.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;
}

关于C 结构、函数指针和头文件问题(不确定是哪个原因),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23986575/

相关文章:

c++ - 结构中的字符串

c++ 使用结构排序

data-structures - 给定二叉树的先序二叉序列/排序,你能画出二叉树吗?

c++ - 这段插入 BST 的代码有什么问题?

c - 以零为条件的 If 语句

c - c 中的内联函数

c - 即使文件存在,open64() 也会失败并显示 ENOENT

不调用 cplex mip 求解器的 cplex 预求解器

C++:访问结构元素的初始化构造函数

java - 如何确定平衡或完美平衡的二叉搜索树(仅来自图片)