【问题标题】:C structure pointer to a structure array, from a structureC 结构体指针指向结构体数组,来自结构体
【发布时间】:2017-12-11 18:21:10
【问题描述】:

我需要指针语法方面的帮助。我有一个结构数组,我正在尝试从另一个结构内部创建一个指向它的指针,该结构包含在一个数组中。

struct foo array* = malloc(sizeof(foo)*10);
bar_arr[i]->foo_ptr = &array;

我已经阅读了这个问题:c pointer to array of structs。虽然它确实消除了一些混乱,但我仍然有一些错误需要解决。

我已经这样定义了我的结构:

struct bar{
...
struct foo (*foo_ptr)[];
...
}

似乎我可以向数组中添加新结构,因为以下没有返回错误:

(*bar_arr[i]->foo_ptr)[j] = new_struct;

但是,如果我尝试在结构数组中创建一个指向结构的新指针,如下所示:

struct foo* one_ptr = (*bar_arr[i]->foo_ptr)[j];

或者这个:

struct foo* one_ptr = bar_arr[i]->foo_ptr[j];

编译器会给我错误。一种是无效使用具有未指定边界的数组,或者 one_ptr 和 foo_ptr[j] 具有不兼容的类型(在这种情况下:一种是 foo 类型,另一种是 struct foo *)。

是否根本不可能创建指向结构数组元素之一的指针?任何帮助将不胜感激。

编辑:更好的代码示例

我目前正在使用线性链表作为共享内存堆栈,与 pthread 一起使用。结构数组是节点的共享池。每当从堆栈中删除一个节点时,它就会被放入共享池中。如果线程尝试向堆栈添加新元素,它会检查要添加的元素是否存在于池中,以避免每次需要向堆栈添加另一个元素时都必须分配新内存。

每个线程都需要一个指向共享节点池的指针作为参数。这就是为什么我试图从参数结构中创建一个指向它的指针。我希望这个问题会有一个简单的答案。

typedef struct node{...} node_t;

struct thread_args
{
...
node_t (*pool)[];
...
}

node_t shared_pool = malloc(sizeof(node_t)*10);
arg[index]->pool = &shared_pool;

我正在尝试访问线程正在执行的函数之一中的池。

node_t *item;
item = stack->root;
//remove item from stack
(*args->pool)[index] = item;
//...later
node_t *item2;
item2 = (*args->pool)[index];

希望这能提供更多信息。

另外,我尝试使用时得到的确切错误:

node_t *pool;
args[index]->pool = shared_pool;

如下:error: incompatible types when assignmenting to type ‘struct node_t *’ from type ‘node_t’。

【问题讨论】:

  • 这里的名字实在是太笼统了,没有足够的上下文来理解你在这里的意图。您能否就您的结构和目标给出一个更完整但最小的示例?
  • 如果不查看您尝试创建的引用的布局,很难判断您正在尝试做什么。特别是,我不确定为什么需要指向数组的指针,而不是常规指针,后者是表示数组的常用方式。

标签: c arrays pointers struct


【解决方案1】:

对于初学者来说,这个声明(没有提到右大括号后省略的分号)

struct bar{
...
struct foo (*foo_ptr)[];
                     ^^^
...
}

无效。您必须指定数组的大小。否则,指针将指向非竞争类型的对象。

考虑到您尝试使用数组的方式,此声明没有意义。您可以像这样声明数据成员

struct bar{
...
    struct foo *foo_ptr;
...
}; 

然后

struct foo *array = malloc(sizeof(struct foo)*10);
bar_arr[i]->foo_ptr = array;

在这种情况下你可以写

bar_arr[i]->foo_ptr[j] = new_struct;

struct foo* one_ptr = bar_arr[i]->foo_ptr + j;

struct foo* one_ptr = &bar_arr[i]->foo_ptr[j];

【讨论】:

  • 我首先尝试了这个解决方案:它给了我上面描述的不兼容类型错误。但是,当我在创建共享池后立即再次尝试时(请参阅澄清编辑),它编译了。这让我认为作为线程参数一部分的指针以某种方式改变了它的类型,阻止我在那里使用它。如果是这种情况,我可能不得不问一个新的更具体的问题。
【解决方案2】:

这是错误的:

struct foo array* = malloc(sizeof(foo)*10);
bar_arr[i]->foo_ptr = &array;

假设你的意思是

struct foo *array = malloc(sizeof(foo)*10);
bar_arr[i]->foo_ptr = &array;

您将实际array 变量的地址 存储到结构的foo_ptr 变量中。从您发布的代码 sn-p 来看,这可能是该函数的局部变量,因此它不仅类型错误,而且一旦您的函数返回,它就不再存在。

给定struct foo,这将分配一个指向struct foo数组的指针:

struct foo *array = malloc( nelem * sizeof( *array ) );

这将分配那个

bar_arr[i]->foo_ptr = array;

或者,更直接地:

bar_arr[i]->foo_ptr = malloc( nelem * sizeof( *( bar_arr[i]->foo_ptr ) ) );

请注意,我使用对 malloc() 结果分配给的指针的取消引用作为 sizeof() 的参数。这是确保指针和完成的内存分配始终引用相同类型的简单方法。

malloc() 的调用将分配nelemstruct foo 的连续副本(其中将包含未知的、未指定的数据...)。这些副本可以通过

array[ n ]

只要n >= 0n < nelem

是否根本不可能创建指向结构数组元素之一的指针?

您的代码过于复杂。创建指向nth 元素的指针:

struct foo *nthElement = array + n;

您只需将n 添加到第一个元素的地址,结果指针将指向nth 元素,假设n 在适当的范围内。

【讨论】:

    【解决方案3】:

    简答

    foo_ptrstruct bar 中的声明不正确。将其更改为struct foo *foo_ptr。并将您的分配语句更改为以下内容

    struct foo *array = malloc(sizeof(struct foo)*10);
    bar_arr[i]->foo_ptr = array;
    

    然后你可以像下面这样读取或写入数组的元素

    // read from array
    struct foo one_struct = bar_arr[i]->foo_ptr[j];
    
    // write to array
    struct foo new_struct = { ... }
    bar_arr[i]->foo_ptr[j] = new_struct;
    

    注意:读写操作都是struct foo的所有字段的副本)。

    变化说明

    想一个简单的例子。你如何制作一个包含 10 个char 的数组。

    char *a = malloc(sizeof(char)*10)

    achar的指针,它指向一个包含10个char的空间。所以我们可以把它当作一个数组来使用。 a[4] 表示 10 个char 数组中的第 5 个char

    如果要将此数组分配给另一个变量怎么办?

    char *b = a;

    现在b 也是一个数组(不是原始数组的副本,ba 指向一个数组)。您现在可以通过b 引用该元素,就像您对a 所做的那样。例如,b[4]

    没有人会将b 声明为char (*b)[] 对吧?

    你的错误的更多解释

    还是从一个简单的例子开始。当我们看到这样的声明——char (*x)[10]——我们会对x 说什么?我们可以说x 是一个指向 10 char 的数组的指针。

    让我们看看你的声明,struct foo (*foo_ptr)[]。同样,我们可以说,foo_ptr 是一个指向 ... length-unspecified struct foo 的数组的指针。 (注意数组长度的不同,其实不指定长度是不对的,我一会儿再说)

    根据你的这个声明,说说你在使用时遇到的错误。

    引发错误的语句 1

    struct foo* one_ptr = (*bar_arr[i]->foo_ptr)[j];

    为了简化和清楚,我将在下面的讨论中删除bar_arr[i]-> 的部分。

    在这个语句中,*foo_ptr是一个长度未指定的数组struct foo,我们可以这样称呼它,*foo_ptr是一个struct foo []的数组。所以(*foo_ptr)[j] 表示struct foo [] 数组的jth 元素。这里的一切似乎都很好。 但是您的数组没有定义长度,即使您为其分配了一个 malloc 的数组,但在编译时,gcc 对此一无所知。这就是为什么它会抛出关于“未指定边界”的错误。

    引发错误的语句 2

    struct foo* one_ptr = bar_arr[i]->foo_ptr[j];

    如上所述,foo_ptr 是指向struct foo [] 数组的指针。让我们注意foo_ptr首先是一个指针。所以在这个声明中,foo_ptr[j] 有点像*foo_ptr。除了索引j,它们具有相同的类型。因为我们已经知道*foo_ptrstruct foo [] 的数组,所以foo_ptr[j] 也是struct foo [] 的数组。它是一个数组,而不是struct foo 的对象。准确地说,你需要想象有一个大数组,其中每个元素仍然是数组(struct foo [] 的数组)。 foo_ptr[j] 只是这个大数组中的jth 元素,或者说jth 数组。

    所以你将foo_ptr[j] 分配给one_ptr 的做法或多或少类似于以下示例

    typedef char char_array_of_4_t[4];
    char_array_of_4_t array1;
    char *p = array1;        //ERROR: incompatible types
    

    为了便于理解,我在下面向您展示另一个示例。

    char array2[4];
    char *p = array2;
    

    在第二个示例中,没有错误。从人类的角度来看,array1array2 都是 4 个 char 的数组,但是,对于 gccarray1 是一种 array,而 @987654386 @ 是一种指针

    【讨论】:

      【解决方案4】:

      在此声明中...

      struct bar{
          // ...
          struct foo (*foo_ptr)[];
          // ...
      };
      

      ... struct bar 的成员 foo_ptr 被声明为指向未知长度数组 struct foo 的指针。这是允许的,但这是不寻常的。通常只声明一个指向数组第一个元素的指针,因为这在 C 中表现得更自然,而且也更简单:

      struct bar{
          // ...
          struct foo *foo_ptr;
          // ...
      };
      

      您可以通过这种形式分配给指向数组的成员:

      bar_arr[i]->foo_ptr[j] = new_struct;
      

      (当然,前提是指向的数组至少有 j + 1 元素。要获得指向此类元素的指针,您可以这样做

      struct foo *struct_ptr = &bar_arr[i]->foo_ptr[j];
      

      或者,等价的,

      struct foo *struct_ptr = bar_arr[i]->foo_ptr + j;
      

      您可以对原始结构声明执行相同的操作,但形式需要稍有不同。例如:

      struct foo *struct_ptr = &(*bar_arr[i]->foo_ptr)[j];
      

      但是说真的,让每个人都更轻松,包括你自己,不要那样做。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-06
        • 2013-02-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-24
        相关资源
        最近更新 更多