为了创建一个链接列表(它将包含下一个和上一个节点的属性),我将使用2个下一个和前一个节点的指针,但我想知道我是否可以在不使用malloc的情况下完成代码(分配内存): 例如: 而不是mallocing:
link *const l = (link *)malloc(sizeof(link));
if(l == NULL)
/* Handle allocation failure. */
...
l->data = d;
l->next = list->head;
head = l;
我可以简单地创建一个新的链接变量,其格式为属性(值,指向下一个和上一个链接的指针),并简单地将链接中最后一个链接中的最后一个链接链接到此链接? 例如,我的列表文件是b。
link i;
i.date=d;
getlast(b).next=&i
我提前为我不熟悉的事实道歉,并且非常乐意接受诚实的解决方案:D
编辑: 我尝试使用malloc解决问题。如果有人能在代码中解决我的错误,我会很高兴,因为我似乎无法找到它。
#include <stdio.h>
#include <malloc.h>
struct Node{
int value;
struct Node * Next;
struct Node * Previous;
};
typedef struct Node Node;
struct List{
int Count;
int Total;
Node * First;
Node * Last;
};
typedef struct List List;
List Create();
void Add(List a,int value);
void Remove(List a,Node * b);
List Create()
{
List a;
a.Count=0;
return a;
}
void Add(List a,int value)
{
Node * b = (Node *)malloc(sizeof(Node));
if(b==NULL)
printf("Memory allocation error \n");
b->value=value;
if(a.Count==0)
{
b->Next=NULL;
b->Previous=NULL;
a.First=b;
}
else
{
b->Next=NULL;
b->Previous=a.Last;
a.Last->Next=b;
}
++a.Count;
a.Total+=value;
a.Last=b;
}
void Remove(List a,Node * b)
{
if(a.Count>1)
{
if(a.Last==b)
{
b->Previous->Next=NULL;
}
else
{
b->Previous->Next=b->Next;
b->Next->Previous=b->Previous;
}
}
free(b);
}
答案 0 :(得分:5)
是的 - 你可以这样做。
e.g。
link l1,l2;
l1.next = &l2;
l2.next = NULL;
是一个非常精细且有效的2个节点的链表。 您还可以创建一组节点,并根据您的需要将它们链接在一起,例如:创建argv的链接列表:
int main(int argc, char *argv[])
int i;
link links[100];
for (i = 0; i < argc && i < 100; i++) {
//assuming the nodes can hold a char*
links[i].data = argv[i];
links[i].next = NULL;
if (i > 0)
links[i-1].next = &links[i];
}
当然有一些缺点:
argc
malloc缓冲区
虽然节点而不是硬编码100)所以你不能做这样的事情:
void append_link(link *n, char *data)
{
link new_link;
n->next = &new_link;
new_link.next = NULL;
new_link.data = data;
}
这是无效的,因为当append_link
结束时,new_link
消失了。传入的n->next
现在指向一个无效的局部变量。如果new_link
取而代之的是malloc'ed,那么它将超越此功能 - 一切正常。
答案 1 :(得分:3)
不是。
您可以为列表中的每个节点创建一个变量,但是当您想要另一个节点时会发生什么?五十个节点?在离开定义范围后,这些变量也不会出现,这意味着您必须使所有内容全局化或使用静态存储并公开指向它们的指针。这意味着在该范围之后指向它们的所有指针都将无效。这些都是非常丑陋的解决方案。
如果您不理解范围我的意思,这里有一个简单的例子:
int main() { /* Entering function scope. */
int x = 5;
{ /* Entering block scope. */
int y = 7;
printf("%d\n", y);
} /* Exiting block scope, all variables of this scope are gone. (y) */
printf("%d %d\n", x, y); /* Won't compile because y doesn't exist here. */
} /* Exiting function scope, all non-static storage variables are gone. (x)
您还可以创建一个全局数组,认为这可以解决许多不同的变量,但如果您的解决方案是使用数组实现这个,那么为什么使用链表而不是数组呢?到目前为止,你已经失去了链表的好处。
答案 2 :(得分:2)
C中只有两种方法可以创建没有固定编译时大小的内存数据结构:
malloc
。后者(自动存储)具有以下属性:当其声明终止的块的执行时,其生命周期结束,因此很难用于长期数据。通常也可以获得您可以获得的此类存储量的限制,并且无法检测何时超出该限制(通常会导致崩溃或内存损坏)。因此,从实际角度来看,malloc
是制作运行时动态大小数据结构的唯一方法。
请注意,如果您的链接列表不需要具有动态大小(即它具有固定或有限大小),您也可以使用静态存储持续时间。
答案 3 :(得分:1)
新节点的内存必须来自 somwhere 。您当然可以创建单个变量并手动链接它们:
link a, b, c;
...
a.next = &b;
b.next = &c;
c.next = NULL;
你可以想象,这种方法不能扩展;如果您希望列表中包含3个以上的元素,则必须分配3个以上link
个变量。请注意,以下不会工作:
void addToList( link *b )
{
link new;
...
b->next = &new;
}
因为当new
退出时addToList
不再存在,所以指针不再有意义 1 。
可以做的是使用link
数组作为“堆”,并从该数组中分配。您需要跟踪哪些元素可供使用;一种简单的方法是初始化数组,使每个a[i]
指向a[i+1]
(除了最后一个指向NULL的元素),然后有一个指向第一个可用元素的指针。如下所示:
// You really want your "heap" to have static storage duration
static link a[HEAP_SIZE];
// Initialize the "heap"
for ( size_t i = 0; i < SIZE - 1; i++ )
a[i].next = &a[i+1];
a[i].next = NULL;
// Set up the freeList pointer; points to the first available element in a
link *freeList = &a[0];
// Get an element from the "heap"
link *newNode = freeList;
freeList = freeList->next;
newNode->next = NULL;
// Add a node back to the "heap" when you're done with it:
deletedNode->next = freeList;
freeList = deletedNode;
同样,您可以创建多少列表节点,但这样您就可以创建足够大的“堆”来满足您的要求。
<小时/> 1。显然,
new
占用的phsyical内存位置仍然存在,但现在可供其他进程/线程使用,因此该地址中包含的值将不再符合您的预期。