我试图了解链表中的指针是如何工作的。到目前为止,我在试图弄清楚指针指向的位置以及结构类型的指针如何工作时遇到了很多麻烦(我知道我们需要从堆中分配内存,但不能完全理解它,但也许这是一个完全不同的问题(。
让我们采用以下结构:
typedef struct Node {
int data;
struct Node *link;
} Node;
我认为现在将要发生的是:
假设你在主函数中有一个 Node 类型的指针,
Node* p
并且分配了内存(使用 malloc(。现在,如果我们有一些数据
p->data=5;
,p指向该数据的开头(至少我认为这是正在发生的事情(。
link
究竟指向哪里?
所以现在,我遇到了这段特定的代码:
typedef struct Node {
int data;
struct Node *link;
} Node;
typedef struct List {
Node* head;
int number_of_nodes;
} List;
所以这是我大脑中的完全混乱!.
现在在结构List
,head
在做什么?它指向什么?您将如何使用这两个列表创建一个链表?
我真的在尽力了解链表的工作原理,但所有的指针都很难跟踪。你可能会建议我从简单的事情开始,我做到了,我已经提到我理解了多少。但是第二个结构中的head
指针已经完全让我偏离了轨道!
如果有人能帮助我解释它,同时跟踪指针,这将使我的生活变得更加轻松。
链接到底指向哪里?
link
指向相同类型的另一个对象:
+------+------+ +------+------+ +------+------+
| data | link |---->| data | link |---->| data | link | ----> ...
+------+------+ +------+------+ +------+------+
现在在结构列表中,头部在做什么?它指向什么?
head
指向列表中的第一个节点:
+-----------------+ +------+------+ +------+------+
| head |---->| data | link |---->| data | link |----> ...
+-----------------+ +------+------+ +------+------+
| number_of_nodes |
+-----------------+
我真的在尽我最大的努力来理解链表是如何工作的,
不要难过 - 链表让我在我的数据结构课(我的第一个"硬"CS课(中循环。 我花了比同学们多一个星期的时间才摸索到这个概念。 希望图片有所帮助。
编辑
如果你有一个指向结构列表、分配的内存和所有内容的指针,会发生什么情况?那么它指向哪里(根据图表,顺便说一下,这确实有帮助(
因此,假设您有以下代码:
/**
* Create a new list object. head is initially NULL,
* number_of_nodes initially 0.
*/
List *newList( void )
{
List *l = malloc( sizeof *l );
if ( l )
{
l->head = NULL;
l->number_of_nodes = 0;
}
return l;
}
int main( void )
{
List *l = newList();
...
}
然后你的图片看起来像这样:
+---------+ +--------------------+
| l: addr | ----> | head: NULL |
+---------+ +--------------------+
| number_of_nodes: 0 |
+--------------------+
(addr
表示一些任意内存地址(
现在假设您将一个节点添加到列表中:
/**
* Create a new node object, using the input data
* link is initially NULL
*/
Node *newNode( int data )
{
Node *n = malloc( sizeof *n );
if ( n )
{
n->data = data;
n->link = NULL;
}
return n;
}
void insertNode( List *l, int data )
{
Node *n = newNode( data );
if ( n )
{
/**
* If list is initially empty, make this new node the head
* of the list. Otherwise, add the new node to the end of the
* list.
*/
if ( !l->head ) // or n->head == NULL
{
l->head = n;
}
else
{
/**
* cur initially points to the first element in the list.
* While the current element has a non-NULL link, follow
* that link.
*/
for ( Node *cur = l->head; cur->link != NULL; cur = cur->link )
; // empty loop body
cur->link = n;
}
l->number_of_nodes++;
}
}
int main( void )
{
List *l = newList();
insertNode( l, 5 );
...
}
现在您的图片如下所示:
+---------+ +--------------------+ +------------+
| l: addr | ----> | head: addr | ---> | data: 5 |
+---------+ +--------------------+ +------------+
| number_of_nodes: 1 | | link: NULL |
+--------------------+ +------------+
您可以添加另一个节点:
int main( void )
{
List *l = newList();
insertNode( l, 5 );
insertNode( l, 3 );
...
}
然后你的图片就变成了
+---------+ +--------------------+ +------------+ +------------+
| l: addr | ----> | head: addr | ---> | data: 5 | +--> | data: 3 |
+---------+ +--------------------+ +------------+ | +------------+
| number_of_nodes: 2 | | link: addr | --+ | link: NULL |
+--------------------+ +------------+ +------------+
当然,您希望添加一些错误检查和消息,以防无法分配节点(发生这种情况(。 你可能想要一个有序列表,其中元素按顺序插入(升序、降序等(。 但这应该可以让您了解如何构建列表。
您还需要删除项目并释放该内存的功能。 以下是我释放整个列表的方法:
void freeList( List *l )
{
Node *prev, *cur = l->head;
while( cur && cur->link )
{
prev = cur;
cur = cur->link;
free( prev );
}
free( cur );
}
int main( void )
{
List *l = newList();
...
freeList( l );
free( l );
...
}
...结构类型的指针...
指针不能是结构类型。指针可以指向结构。
C 有对象。对象包括char
、int
、double
、结构和其他东西。结构是组合在一起的对象集合。
在 main,如果你用Node *p;
定义p
,那么你就会有一个指针p
。它没有值,因为你没有给它一个值。当你执行p = malloc(sizeof *p);
时,你请求足够的内存来容纳p
指向的事物的大小(*p
(。如果malloc
返回非 null 指针,则p
指向Node
结构。
然后p->data
指的是该结构的data
成员。p->data
是(*p).data
的简写,其中*p
的意思是"p
指向的对象",.data
的意思是"该对象中的data
成员"。
在p = malloc(sizeof *p);
和p->data = 5;
之后,p->link
不会指向任何内容,因为您没有为其赋值。在链表中,您将使用malloc
获取另一个Node
的内存,然后您将在一个Node
中设置p->link
以指向新的Node
。在每个Node
中,其link
成员指向列表中的下一个Node
。除了,在最后一个Node
中,p->link
设置为空指针以指示它是最后一个Node
。
在List
中,您将head
设置为指向Node
对象列表中的第一个Node
。