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

问题描述 投票:1回答:4

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

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数组内部创建一个新的指针,如下所示:

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 *'时不兼容的类型。

c arrays pointers struct
4个回答
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
投票

这是错的:

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

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

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

struct foo *nthElement = array + n;

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


1
投票

简短的回答

foo_ptr宣布struct 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]

没有人会宣布bchar (*b)[]对吗?

更多解释你的错误

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

让我们来看看你的宣言,struct foo (*foo_ptr)[]。同样,我们可以说,foo_ptr是一个指向...长度未指定的struct foo数组的指针。 (注意数组长度的不同。实际上不指定长度是错误的,我很快就会谈到它)

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

Statement 1 that throws error

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 []th元素。这里的一切似乎都很好。但是你的数组没有定义长度,即使你为它分配了一个malloc'ed数组,但是在编译时,gcc并不知道它。这就是为什么它会抛出关于“未指定的边界”的错误。

Statement 2 that throws error

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

正如我上面所说,foo_ptr是指向struct foo []数组的指针。让我们注意foo_ptr首先是指针的事实。所以在这个声明中,foo_ptr[j]有点像*foo_ptr。除了指数j,他们有相同的类型。由于我们已经知道*foo_ptr是一个struct 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的阵列,然而,在gcc的意义上,array1是一种类型的数组,而array2是一种指针。


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

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

© www.soinside.com 2019 - 2024. All rights reserved.