C结构指针从结构到结构数组

时间:2017-12-11 18:21:11

标签: c arrays pointers struct

我需要一些指针语法的帮助。我有一个结构数组,我试图从另一个结构中创建一个指向它的指针,包含在数组中。

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

是否根本无法创建指向结构数组中某个元素的指针?任何帮助将不胜感激。

编辑:更好的代码示例

我目前正在使用线性链接列表作为共享内存堆栈,用于pthreads。结构数组是节点的共享池。无论何时从堆栈中删除节点,都会将其放入共享池中。如果一个线程试图将新项添加到堆栈中,它会检查池中是否存在要添加的元素,以避免每次需要向堆栈添加另一个元素时分配新内存。

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

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;

如下:错误:从类型'node_t'分配类型'struct node_t *'时出现不兼容的类型。

4 个答案:

答案 0 :(得分:2)

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

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];

答案 1 :(得分:1)

这是错误的:

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变量中。从您发布的代码片段中,可能是该函数的局部变量,因此它不仅是错误的类型,一旦函数返回它就不再存在。

给定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()的调用将分配nelem struct foo的连续副本(其中包含未知的,未指定的数据......)。这些副本可以通过

访问
array[ n ]

只要n >= 0n < nelem

  

是否根本无法创建指向结构数组中某个元素的指针?

你的代码太复杂了。要创建指向n元素的指针:

struct foo *nthElement = array + n;

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

答案 2 :(得分:1)

简短回答

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是指向... 长度未指定 struct foo数组的指针。 (注意数组长度的不同。实际上不指定长度是错误的,我很快就会谈到它)

根据您的声明,让我们谈谈您在使用时遇到的错误。

声明1抛出错误

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

为简化并明确说明,我将在以下讨论中删除bar_arr[i]->部分内容。

在此声明中,*foo_ptr是一个长度未指定struct foo的数组,我们可以这样称呼它,*foo_ptrstruct foo []的数组。因此(*foo_ptr)[j]表示j数组的struct foo []元素。这里的一切似乎都很好。 但是你的数组没有定义长度,即使你为它分配了一个malloc数组,但是在编译时,gcc并不知道它。这就是为什么它会引发关于&#34;未指定边界的错误&#34;。

引发错误的声明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]只是j元素,或者说j数组。

因此,您将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是一种数组,而array2是一种指针

答案 3 :(得分:0)

在此声明中......

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

... foo_ptr的成员struct bar被声明为指向未知长度数组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];

但实际上,让每个人都更容易,包括你自己,并且不要那样做。