链接列表混乱

时间:2011-06-23 04:50:37

标签: c pointers linked-list traversal

过去几天我一直在查看本书的相同部分,似乎无法弄清楚这个链表/结构的字段是如何变化的。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dvdTracker.h"


/**************************************************> main <*/
int main (int argc, const char * argv[]) {
    char            command;

    gHeadPtr = NULL;
    gTailPtr = NULL;

    while ( (command = GetCommand() ) != 'q' ) {
        switch( command ) {
            case 'n':
                AddToList( ReadStruct() );
                break;
            case 'l':
                ListDVDs();
                break;
        }
    }

    printf( "Goodbye..." );

    return 0;
}


/*******************************************> GetCommand <*/
char    GetCommand( void )
{
    char    command;

    do {
        printf( "Enter command (q=quit, n=new, l=list):  " );
        scanf( "%c", &command );
        Flush();
    }
    while ( (command != 'q') && (command != 'n')
           && (command != 'l') );

    printf( "\n----------\n" );
    return( command );
}


/*******************************************> ReadStruct <*/
struct DVDInfo  *ReadStruct( void ) {
    struct DVDInfo  *infoPtr;
    int             num;

    infoPtr = (struct DVDInfo *)malloc( sizeof( struct DVDInfo ) );

    if ( NULL == infoPtr ) {
        printf( "Out of memory!!!  Goodbye!\n" );
        exit( 0 );
    }

    printf( "Enter DVD Title:  " );
    fgets( infoPtr->title, kMaxTitleLength, stdin );
    ReplaceReturnAtEndOfString( infoPtr->title );

    printf( "Enter DVD Comment:  " );
    fgets( infoPtr->comment, kMaxCommentLength, stdin );
    ReplaceReturnAtEndOfString( infoPtr->comment );

    do {
        num = 0;
        printf( "Enter DVD Rating (1-10):  " );
        scanf( "%d", &num );
        Flush();
    }
    while ( ( num < 1 ) || ( num > 10 ) );

    infoPtr->rating = num;

    printf( "\n----------\n" );

    return( infoPtr );
}


/*******************************************> AddToList <*/
void    AddToList( struct DVDInfo *curPtr ) {
    if ( NULL == gHeadPtr )
        gHeadPtr = curPtr;
    else
        gTailPtr->next = curPtr;

    gTailPtr = curPtr;
    curPtr->next = NULL;
}


/*******************************************> ListDVDs <*/
void    ListDVDs( void ) {
    struct DVDInfo  *curPtr;

    if ( NULL == gHeadPtr ) {
        printf( "No DVDs have been entered yet...\n" );
        printf( "\n----------\n" );
    } else {
        for ( curPtr=gHeadPtr; curPtr!=NULL; curPtr = curPtr->next ) {
            printf( "Title:  %s\n", curPtr->title );
            printf( "Comment:   %s\n", curPtr->comment );
            printf( "Rating:  %d\n", curPtr->rating );

            printf( "\n----------\n" );
        }
    }
}

当我调试此程序时,请在以下行:

gTailPtr-&gt;接着= curPtr;

gHeadPtr-&gt;接下来也指向当前指针,虽然我没有看到如何。

这是来自Mac上的Learning C(Addison)第256页,如果有人可以提供帮助,谢谢!或者至少解释一下。

2 个答案:

答案 0 :(得分:1)

如果它是第二个插入列表的项目,那么gTailPtrgHeadPtr最初将指向同一个节点(列表中的第一个也是唯一的节点)。因此,此时gTailPtr->nextgHeadPtr->next只是同一对象的两个名称。

要理解的关键是gHeadPtr不是节点本身,并且根本不包含next字段。它只是节点的指针:这意味着它包含的是对某个节点的引用(或根本没有节点)。当您分配给gHeadPtr本身时,您正在更改指向的节点。当您使用->运算符时,您正在检查它现在指向的节点。

可以这样想:指针变量就像一张纸,上面写有电话号码。当您更改指针变量时,这就像删除电话号码并将其替换为另一个;当您使用->运营商时,这就像拨打电话号码一样。指向同一节点的两个指针变量就像是有两张纸,上面写着相同的电话号码:你用来拨打哪一个并不重要,你会到达同一个目的地。 NULL指针是一张白纸:尝试拨打该号码是没有任何意义的。

答案 1 :(得分:0)

这是一个双头链表。您可以将它用作队列(先进先出)和堆栈(先进先出)。指针gHeadPtr用于弹出插入的第一个元素,gTailPtr弹出插入的最后一个元素。想一想列表是空白的。 gHeadPtr和gTailPtr都为null。现在找出列表是否为空的条件是if ( NULL == gHeadPtr )。因此,当要插入第一个元素时,将curPtr指向gHeadPtr。插入后,直到您需要弹出第一个元素,无需触摸gHeadPtr。甚至gTailPtr第一次指向curPtr。因此,当只插入一个元素时,gHeadPtr和gTailPtr都指向同一个元素。插入下一个元素时,gHeadPtr不受影响。新元素将添加到gTailPtr旁边,gTailPtr将指向新元素。这是关于队列的基本内容。更好地研究数据结构。