指向结构体数组的指针和获取内存

4

链接是指向节点的指针。

typedef struct node * link;

在main()函数中,我有以下代码(config->m只是一些整数):
// array of pointers to structs
link heads[config->m]; 

// make memory for head nodes
for(i = 0; i < config->m; i++)
  heads[i] = malloc(sizeof(struct node));

代码可以运行(这很棒)。但是我能否在不使用循环的情况下分配config->m块内存?我尝试过了。
link heads[config->m];
heads = malloc(sizeof(struct node) * config->m);

但是我的友好编译器告诉我“无法分配不兼容的类型”

我知道我可以使用

struct node heads[config->m];

但我希望使用指针来完成这项工作。

而且,像往常一样,总有人会问我这是否是作业的一部分,答案是肯定的(有点)。但这段代码与实际任务无关,只是为了我的启发。但还是谢谢你的询问 :|

2个回答

3

不行,你需要循环。你的heads数组本质上是一个二维数组。你至少需要两个分配。第一个是指针数组:

link * heads = (link*)malloc (config->m * sizeof (link));

第二个是heads数组中每个成员指向的内存:
link buf = (link)malloc(sizeof(struct node) * config->m);
for(i = 0; i < config->m; i++)
    heads[i] = &buf[i];

然后进行解除分配:

free(heads);
free(buf);

嗯,我想那回答了我的问题。谢谢。 - El Duderino
在for循环中,应该是heads[i] = &buf[i]吧?你想让头指针拥有节点的地址,对吗? - tpdi
谢谢tpdi。实际上,原来的heads数组应该是一个指针的链接**(或节点)数组。因此出现了问题。我喜欢C语言,在我的节点结构中添加一些填充之前,我的测试程序都没有崩溃 ;)。 - RedBlueThing
实际上这里有另一个问题:https://dev59.com/7nRB5IYBdhLWcg3wAjNH。我完全同意第一个答案。typedef blah * thing 搞乱了我的间接感觉;)。 - RedBlueThing
1
我最初因同样的原因犯了同样的错误。 - tpdi

1
link heads[config->m]; 
link buffer = malloc(sizeof(struct node) * config->m);

for(i = 0; i < config->m; i++)
  heads[i] = &buffer[i];

....
free(buffer);

编辑:

实际上,你不需要heads。首先,让我们摆脱link,因为(请参见Cannonade答案中的评论),它只会使问题更加混乱。

假设一个结构体节点是一个侵入式链表中的节点,并且看起来像这样:

      struct node {
        int val;
        int filler[10]; // this is pure filler, to make node big
        struct node* next;
      };

现在我们添加我们的包含文件,并配置->m:

  #include <stdio.h>
  #include <stdlib.h>
  // your config->m
  const int m = 10 ; 

在 main() 函数中,我们打印节点的大小:

  int main() {

     printf( "sizeof( struct node ) = %i\n", sizeof( struct node) );

现在我们声明一个指向节点的指针:

     // na is a node pointer
     struct node* na;

并且使用malloc分配m个节点。malloc返回数组的地址,也是数组中第一个节点的地址。我们将na设置为malloc返回的地址:

      na = malloc(sizeof(struct node) * m);

现在我们将使用指针na,就像它是一个数组一样。这可以工作是因为C定义了array[offset]*(array + offset * sizeof(element))
     int i;
     // we give the first node a val of zero
     na[0].val = 0;
     // and a null next pointer
     na[0].next = 0 ;

现在我们将遍历数组的其余部分,并将每个节点的下一个节点设置为数组中的前一个节点:
     for(i = 1; i < m; i++) {
        na[i].val = i ;
        // na[ offset ] is *(na + offset)
        // we don't want to dereference, 
        // we want the address, so we use the 
        // address-of operator ("&")
        na[i].next = &na[ i - 1 ];
     }

我们的头是数组中的最后一个节点 na[m-1]。列表中的每个next都是数组中的前一个节点。同样,如果我们想要指针而不是被指向的内容,我们使用取地址运算符:

     struct node* current = &na[ m - 1 ];

我们将打印每个节点的地址。它应该是其next节点指针+sizeof(struct node)的地址,因为每个节点都是列表中其下一个节点(在数组中)之后的节点(列表是“反转”的数组)。

我们将其转换为char*以获得字节结果。如果我们不进行转换,我们将以struct node*单位获得结果(这应该始终为1)。

     while( current ) {
        printf( "val %i, address of current %p, ", current->val, current) ;
        printf( " address of current->next %p, ", current->next ) ;
        if( current->next ) {
           printf( " distance from next: ");
           printf( "in bytes %i, ", 
              ( (char*) current)  - (char*) current->next ) ;
           printf( " in struct nodes %i", current  - current->next ) ;
        }
        printf( "\n" );
        current = current->next;   
     }

     return 0;
  }

在我的系统上,这会产生以下输出:

  sizeof( struct node ) = 48
  val 9, address of current 0x804a1b8,  address of current->next 0x804a188,  distance from next: in bytes 48,  in struct nodes 1
  val 8, address of current 0x804a188,  address of current->next 0x804a158,  distance from next: in bytes 48,  in struct nodes 1
  val 7, address of current 0x804a158,  address of current->next 0x804a128,  distance from next: in bytes 48,  in struct nodes 1
  val 6, address of current 0x804a128,  address of current->next 0x804a0f8,  distance from next: in bytes 48,  in struct nodes 1
  val 5, address of current 0x804a0f8,  address of current->next 0x804a0c8,  distance from next: in bytes 48,  in struct nodes 1
  val 4, address of current 0x804a0c8,  address of current->next 0x804a098,  distance from next: in bytes 48,  in struct nodes 1
  val 3, address of current 0x804a098,  address of current->next 0x804a068,  distance from next: in bytes 48,  in struct nodes 1
  val 2, address of current 0x804a068,  address of current->next 0x804a038,  distance from next: in bytes 48,  in struct nodes 1
  val 1, address of current 0x804a038,  address of current->next 0x804a008,  distance from next: in bytes 48,  in struct nodes 1
  val 0, address of current 0x804a008,  address of current->next (nil),

我以前从未见过像那样使用内存缓冲区的方式。我想,如果你可以在一次调用中获得所有内存,避免大量调用malloc是很好的。谢谢。 - El Duderino
除了我稍微搞砸了一点。;) - tpdi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接