【问题标题】:passing different structs to a function(using void *)将不同的结构传递给函数(使用 void *)
【发布时间】:2013-12-12 09:23:28
【问题描述】:

我需要弄清楚如何将两个不同的结构传递给一个函数。我尝试使用 void * 作为参数,但收到错误:

warning: dereferencing 'void *' pointer
error: request for member left in something not a structure or union

会员权限同样的错误

这是我所做的一般性术语(代码可能无法编译)。

struct A{
    char *a;
    struct A *left, *right;
} *rootA;

struct B{
    char *b;
    struct B *left, *right;
} *rootB;

void BinaryTree(void *root, void *s){
    if(condition)
        root->left=s;
    else if(condition)
        BinaryTree(root->left, s);

    if(condition)
        root->right=s;
    else if(condition)
        BinaryTree(root->right, s);
}

int main(){
    // Assume the struct of nodeA and nodeB get malloc() 
    // as well as the variables a and b with actual data.
    struct A nodeA;
    struct B nodeB;
    BinaryTree(rootA, nodeA);
    BinaryTree(rootB, nodeB);

    return 0
}

【问题讨论】:

  • 您的代码表明您没有传递指针。你的意思是BinaryTree(rootA, &nodeA) 等?
  • 我正在传递nodeA和nodeB的内存位置。函数参数中的 void 指针应该取消引用它以便在函数号中使用?
  • 你的参数类型是指针。您正在传递整个结构,而不是指向该结构的指针。尽管除此之外也可能存在问题。编译器不会将结构“取消引用”到 void 指针。
  • 当您假设root 是一些包含left 的结构时,void * 指针的解引用发生在函数BinaryTree 中。由于struct Astruct B 是相同的,因此重构void * 参数并将其转换为指向您的结构的指针..
  • 我指的是nodeA参数。此外,在函数内部,函数知道第一个参数为void *,因此它不会知道root->left 是什么。您需要执行类似((struct A *)root)->left 之类的操作,这意味着您需要知道root 属于哪个结构。

标签: c pointers struct malloc void


【解决方案1】:

您对结构声明感到困惑。类型由 struct 后面的单词给出。最后那件事需要去,至少在你了解 typedef 之前。示例:

struct A{
char *a;
struct A *left, *right;
};

当您调用 BinaryTree 时,您需要始终传递指针而不是结构。示例:

BinaryTree(&nodeA, &nodeA);

当您对 void 指针进行操作时,您需要先将其转换为正确的指针类型。示例:

(struct A*)root->left=s;

将这些结构作为 void 指针传递绝对是不好的做法,你会让自己感到非常困惑。空指针应谨慎使用。由于您似乎是从 C 开始的,因此我建议您在更好地理解值和引用语义之前不要使用它们。话虽如此,当我开始使用 C 语言时,我编写了很多愚蠢的代码,有时仍然这样做。随着时间和练习,你会弄明白的。

【讨论】:

  • 最后的东西只是简单地声明了一个已定义struct的变量,即struct A{ ... } * rootA;定义了struct A,并声明了一个变量rootA作为指向struct A的指针。只有当它与typedef 一起使用时,它才会将rootA 定义为一个类型。您将nodeA 用作两个参数意味着您希望将nodeA 用作根和节点,这可能不是OP 的意图。此外,struct A 不是 typedefed 转换为 (A*) 无效。
  • 没错,但我感觉 OP 可能不会这样使用它。在这种情况下,为什么他们会同时拥有这些结构的本地和全局实例?
  • 声明全局树的根(但不是节点)并不奇怪。而且您似乎暗示他想将nodeA 用作根和节点。虽然 OP 应该注意 nodeAnodeB 现在分配在堆栈上,并且可能在它们仍在树中时超出范围。
  • 在大多数情况下是的,但这是 main 方法,因此程序将在其范围用完时结束。可以肯定的是,这是一种处理持久元素的坏方法,但它确实有效,哈哈。
【解决方案2】:

您的程序有 2 个方面需要重新审视。一,是通过值而不是引用传递的参数。因此,BinaryTree 函数的调用应该有

BinaryTree(rootA, &nodeA);

另一个主要考虑因素是如何在BinaryTree 函数中处理这些空指针。在目前的形式中,

void BinaryTree(void *root, void *s){
    if(condition)
         root->left=s;

这里rootvoid *,因此无法评估root->left。因此,您需要将roottypecast 转换为有意义的数据类型,例如

struct A *hdl = (struct A*)(root);
hdl->left = s;

即使使用这种方法,一个更重要的考虑因素是您对不同的结构使用相同的函数。因此,要知道何时将 cast root 键入为 AB 将是困难的/具有挑战性的,因此,该策略需要重新考虑。

【讨论】:

  • 分配时不需要强制转换,因为void * 会自动升级。如果使用 root 而不将其分配给可用的数据类型,则必须在访问成员之前对其进行强制转换。
  • @Kninnug... 是的,我同意。我保留它是为了便于阅读,并强调 void * 应该转换为更有意义的数据类型指针。
猜你喜欢
  • 2013-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-08
  • 2012-05-15
  • 1970-01-01
  • 2021-12-27
  • 1970-01-01
相关资源
最近更新 更多