如果没有malloc,链表实现将失败

linked list implementation fail without malloc

本文关键字:失败 实现 链表 malloc 如果没有      更新时间:2023-10-16

第一个例子是没有动态内存分配的链表。但在这个例子中,当我们运行它时,它只会显示10,然后会提供运行时错误。请帮我找出问题所在。

#include<bits/stdc++.h>
using namespace std;
struct Node{
int data;
struct Node* next;
}Node;
struct Node* head;
void Insert(int x)
{
struct Node* temp;
temp=head;
struct Node* newnode;
newnode->data=x;
newnode->next=NULL;
if(head==NULL)
{
head=newnode;
return;
}
while(temp->next!=NULL)
{
temp=temp->next;
}
temp->next=newnode;
}
void print()
{
struct Node* temp;
temp=head;
while(temp!=NULL)
{
cout<<temp->data<<" ";
temp=temp->next;
}
cout<<endl;
}
int main()
{
head=NULL;
Insert(10);
Insert(20);
Insert(30);
print();
}

在下面的示例中,我刚刚使用malloc为变量提供动态内存。它的工作完全符合预期。为什么两者之间有这样的区别?

#include<bits/stdc++.h>
using namespace std;
struct Node{
int data;
struct Node* next;
}Node;
struct Node* head;
void Insert(int x)
{
struct Node* temp=(struct Node*)malloc(sizeof(struct Node));
temp=head;
struct Node* newnode=(struct Node*)malloc(sizeof(struct Node));
newnode->data=x;
newnode->next=NULL;
cout<<"Reached here"<<endl;
if(head==NULL)
{
head=newnode;
return;
}
while(temp->next!=NULL)
{
temp=temp->next;
}
temp->next=newnode;
}
void print()
{
struct Node* temp=(struct Node*)malloc(sizeof(struct Node));
temp=head;
while(temp!=NULL)
{
cout<<temp->data<<" ";
temp=temp->next;
}
cout<<endl;
}
int main()
{
head=NULL;
Insert(10);
cout<<"Inserted 10"<<endl;
Insert(20);
cout<<"2nd"<<endl;
Insert(30);
cout<<"3rd"<<endl;
print();
}

在没有malloc的示例中,这只是非法代码:

struct Node* newnode;
newnode->data=x;
newnode->next=NULL;

newnode而不是指向任何合法内存,因此使用newnode写入内存是未定义的行为。

如果您想要一个而不使用的使用malloc的链表,则必须预先为节点保留内存。例如,您可以在程序启动时创建一个1000个节点的池,然后在程序执行期间使用这些节点。

类似:

static struct node nodePool[1000];
struct node* getNode()
{
// Add code to find an unused node and return a pointer to the node
// This will require some extra data object to track which nodes are free
}
void freeNode(struct node* p)
{
// Add code to mark the node as unused
// This will require some extra data object to track which nodes are free
}
void Insert(int x)
{
...
struct Node* newnode = getNode();
if (newnode == NULL)
{
// No more nodes
add error handling
return something or exit(1);
}
newnode->data=x;
newnode->next=NULL;
...
}

注意:对节点池使用平面阵列是可行的,但对性能不利。Get/fre节点将为O(n(,这对程序性能不利。使用池的程序有更高级的池实现,允许O(1(操作。一种(非常简单(方法是将池控制数据实现为具有头指针和尾指针的链表。这将允许CCD_ 5和CCD_。

注意:我刚刚注意到这个问题同时用C++和C标记。这个答案是用C写的。对于C++代码,没有(也很少有(理由实现自己的链表——只需使用std::list

您的两个示例都是错误的,但原因不同。指针变量需要给定值,就像常规变量一样。因此,您的第一个示例是错误的,因为指针变量newnode是未初始化的。查看我添加到您的代码中的注释

struct Node* temp; // temp has no value
temp=head;         // now temp is given a value
struct Node* newnode; // newnode has no value
newnode->data=x;      // ERROR, newnode is used before it's been given a value
newnode->next=NULL;

在给正则变量赋值之前,您不会使用它。指针变量也没什么不同。

第二个例子有相反的错误,您给temp指针一个值两次!再次查看添加的评论

struct Node* temp=(struct Node*)malloc(sizeof(struct Node)); // temp is given a value
temp=head;                         // now temp is given a different value,
// the first value is discarded
struct Node* newnode=(struct Node*)malloc(sizeof(struct Node)); // newnode is given a value
newnode->data=x;                                       // newnode is being used correctly
newnode->next=NULL;

您可以通过两种方式给指针一个不同的值,您可以创建一个新节点让它指向,这就是temp=(struct Node*)malloc(sizeof(struct Node));的作用,或者您可以让它指向一个已经存在的节点,这也是temp=head;的作用。两者兼而有之没有多大意义。在第二个示例中,使用temp=(struct Node*)malloc(sizeof(struct Node));创建的节点从未使用过,而是在使temp指向头节点时创建并丢弃。这被称为内存泄漏。如果泄漏变得足够大,您的程序将耗尽内存。往好里说是浪费。

再想想你将如何使用正则变量,你永远不会写这样的代码int x = 10; x = 20;——给一个变量一个值,然后在下一行把这个值扔掉,给变量一个不同的值是没有意义的。但这正是您对temp变量所做的操作。同样,指针并不特殊,适用于正则变量的相同规则也适用于指针变量。