没有malloc的C中的链接列表

#include  typedef struct node { int i; struct node *next; }node; node getnode(int a) { struct node n; ni=a; n.next=NULL; return n; } main() { int i; node newtemp,root,temp; scanf("%d",&i); root=getnode(i); temp=root; while(i--) { newtemp=getnode(i); temp.next=&newtemp; if(root.next==NULL) { root=temp; } temp=*(temp.next); } temp=root; while( temp.next != NULL ) { printf(" %d ",temp.i); temp=*(temp.next); } } 

我试图在不使用malloc的情况下创建链接列表。 编程只打印根,后面没有节点。 我找不到这个错误。 如果有任何内存问题,gcc编译器会抛出一个分段错误。(?)请忽略糟糕的编程风格..

初始化temp.next ,指定给它的指针的值是多少?

 temp.next=&newtemp; 

为什么,每次都是一样的! (如果你不相信,请画一幅画。)

放弃。 如果您需要不确定数量的内存(具有不确定数量的节点),那么您需要分配内存。

你可以避免malloc但不是免费的:

  • 在Linux / UNIX上,您可以调用brk()并编写自己的内存分配器。
  • 在每个系统上,您可以使用固定大小的数组作为内存源编写自己的分配器。
  • 我不知道替代品会直接购买malloc / free。 他们在那里是有原因的。
  • 返回要在外部使用的局部变量很简单但是是错误的并且不起作用。

您只有两个可用于存储节点的内存空间,它们是rootnewtemp 。 将新节点分配给newtemp ,旧节点不再存在。

假设您在scanf的第一次迭代之前输入了数字5 ,您有:

 5 -> NULL 

循环的第一次迭代后,你有

 5 -> 4 -> NULL 

在循环的第二次迭代之后,你有

 5 -> 3 -> NULL 

(包含4的节点已被包含3的节点完全替换)。

唯一的解决方案是使用malloc ,并使getnode返回一个node*

您可以静态声明节点结构数组并从该数组中选择新节点。 但是,你会实现一个蹩脚,可悲的专业自定义分配器。 并且可用节点的最大数量将是该arrays的大小。

或者,您可以使用递归作为分配机制,并对递归堆栈底部的列表执行操作。

这两种方法都大致相同。

当然,您可以构建链接列表或任何其他数据结构,而无需动态内存分配。 但是,无论你怎么努力,你都不能建立它根本不分配内存。

替代方案:

创建一个全局或静态内存池,您可以在其中放置对象,模仿heap / malloc / free。 FreeRTOS做的事情就像。 在这种情况下,自程序开始以来,您将拥有一个静态分配的大内存块, 负责管理它,在需要新节点时返回正确的指针并将该内存标记为已使用。

PS:我不会质疑你为什么要避免使用malloc。 我认为你有充分的理由。

在你的程序中,当你这样做时,在第20行:

  node newtemp,root,temp; 

你是allocatin thre节点,其中之一是“newtemp”。 然后你在第28行做:

  newtemp=getnode(i); 

它只是复制了旧的“newnode”上的返回节点的内容(争议,不是吗?)

所以你这样做,只是吼叫:

  temp.next=&newtemp; 

这会将一个指针从最初的“root.next”设置为“newnode”。

  if(root.next==NULL) 

在第一次传递时将为“NULL”,但随后只替换相同的内容。

  temp=*(temp.next); { root=temp; } 

再次, 数据从单个分配的对象“*(temp.next)” 复制到另一个“temp”。 它不会创建任何新节点。

如果你这样做,它会工作:

 #include  typedef struct node { int i; struct node *next; } node; #define MAX_NODES 10 node *create_node( int a ) { // Memory space to put your nodes. Note that is is just a MAX_NODES * sizeof( node ) memory array. static node node_pool[ MAX_NODES ]; static int next_node = 0; printf( "[node *create_node( int a )]\r\tnext_node = %d; i = %d\n", next_node, a ); if ( next_node >= MAX_NODES ) { printf( "Out of memory!\n" ); return ( node * )NULL; } node *n = &( node_pool[ next_node++ ] ); n->i = a; n->next = NULL; return n; } int main( ) { int i; node *newtemp, *root, *temp; root = create_node( 0 ); temp = root; for ( i = 1; ( newtemp = create_node( i ) ) && i < MAX_NODES; ++i ) { temp->next = newtemp; if ( newtemp ) { printf( "temp->i = %d\n", temp->i ); printf( "temp->next->i = %d\n", temp->next->i ); temp = temp->next; } } for ( temp = root; temp != NULL; temp = temp->next ) printf( " %d ", temp->i ); return 0; } 

输出:

  $ gcc -Wall -o list_no_malloc list_no_malloc.c $ ./list_no_malloc [node next_node = 0; i = 0)] [node next_node = 1; i = 1)] temp->i = 0 temp->next->i = 1 [node next_node = 2; i = 2)] temp->i = 1 temp->next->i = 2 [node next_node = 3; i = 3)] temp->i = 2 temp->next->i = 3 [node next_node = 4; i = 4)] temp->i = 3 temp->next->i = 4 [node next_node = 5; i = 5)] temp->i = 4 temp->next->i = 5 [node next_node = 6; i = 6)] temp->i = 5 temp->next->i = 6 [node next_node = 7; i = 7)] temp->i = 6 temp->next->i = 7 [node next_node = 8; i = 8)] temp->i = 7 temp->next->i = 8 [node next_node = 9; i = 9)] temp->i = 8 temp->next->i = 9 [node next_node = 10; i = 10 Out of memory! 0 1 2 3 4 5 6 7 8 9 

链表是长度不确定的,没有malloc就无法创建任何长度不确定的列表。

我建议你只需使用malloc来分配链中的下一个链接。

当使用malloc时,该位置的“指针”将传递给变量(它是一个指针)。

 node* new = (node*)malloc(sizeof(node)); 

每次使用此代码时,都会指向“新”位置。 相反,您使用的是普通变量,它们具有“静态”分配的内存。 这意味着,每当你提到’temp’或’newtemp’时,你指的是每个时间相同的位置。

现在你告诉我如何使用3个(root,temp,newtemp)内存位置存储10个元素的长列表。 您可能想要绘制内存位置以想象发生了什么。 但请记住,每次调用’temp’时它都是SAME内存位置。 为此,我们必须使用malloc(或calloc)来动态分配内存。

在这种情况下,我们可以使用少量指针(远远小于列表使用的内存)。

因为没有人在现代C(又名C99)的精神中回答关于malloc部分的这个问题。 如果您的编译器符合您的可变长度数组

 node myNodes[n]; 

其中n具有仅在运行时确定的某个值。 您可能不应该使用此方法来覆盖它,因为这仅限于堆栈的大小,否则您可能会遇到堆栈溢出。