-1

gHeadPtr が常に最初の (最小) 評価構造を指している場合、AddToList がどのように機能するのか理解できませんが、gHeadPtr がそれを指していない、またはそれを間違えていますか? または、誰かが AddToList の仕組みを教えてくれますか? 最後の文字列が何を意味するのか、なぜダブルポインターが必要なのか、どの構造体ポイント gHeadPtr で、gHeadPtr が最初の (最小) 評価構造体を指すのか、構造体に (最大評価で) いつ追加するのかわかりません。

struct DVDInfo
{
     char           rating;
     char           title[ kMaxTitleLength ];
     char           comment[ kMaxCommentLength ];
     struct DVDInfo  *prev;
     struct DVDInfo *next;
};

char            GetCommand( void );
struct DVDInfo  *ReadStruct( void );
void            AddToList( struct DVDInfo *curPtr );
void            ListDVDs( bool forward );
char            *TrimLine( char *line );

struct DVDInfo *gHeadPtr, *gTailPtr;

int main (int argc, const char * argv[])
{
     char command;   
     while ( (command = GetCommand() ) != 'q' ) 
     {
          switch( command ) 
          {
               case 'n':
                    AddToList( ReadStruct() );
                    break;
               case 'l':
               case 'r':
                    ListDVDs( command=='l' );
                    break;
          }
          printf( "\n----------\n" );
     }  
     printf( "Goodbye...\n" );  
     return 0;
}

char GetCommand( void )
{
     char buffer[ 100+1 ];
     printf( "Enter command (q=quit, n=new, l=list, r=reverse list):  " );
     fgets( buffer, sizeof(buffer), stdin );
     return *TrimLine( buffer );
}

struct DVDInfo *ReadStruct( void )
{
     struct DVDInfo *infoPtr;   
     infoPtr = malloc( sizeof( struct DVDInfo ) );  
     if ( infoPtr == NULL ) 
     {
          printf( "Out of memory!!!  Goodbye!\n" );
          exit( 1 );
     }
     char buffer[ 500+1 ];    
     printf( "Enter DVD Title:  " );
     fgets( buffer, sizeof(buffer), stdin );
     strlcpy( infoPtr->title, TrimLine( buffer ), sizeof(infoPtr->title) ); 
     printf( "Enter DVD Comment:  " );
     fgets( buffer, sizeof(buffer), stdin );
     strlcpy( infoPtr->comment, TrimLine( buffer ), sizeof(infoPtr->comment) ); 
     int num;
     do 
     {
          printf( "Enter DVD Rating (1-10):  " );
          fgets( buffer, sizeof(buffer), stdin );
          num = atoi( TrimLine( buffer ) );
     }
     while ( ( num < 1 ) || ( num > 10 ) );
     infoPtr->rating = num; 
     return( infoPtr );
}

void AddToList( struct DVDInfo *curPtr )
{
     struct DVDInfo **nextPtrPtr = &gHeadPtr;
     struct DVDInfo *prevPtr = NULL;    
     while ( *nextPtrPtr != NULL && curPtr->rating > (*nextPtrPtr)->rating ) 
     {
          prevPtr = *nextPtrPtr;
          nextPtrPtr = &(prevPtr->next);
     }
     curPtr->prev = prevPtr;                // link to previous struct
     curPtr->next = *nextPtrPtr;              // link to next struct
     if ( curPtr->next != NULL )
          curPtr->next->prev = curPtr;       // link prev of next struct to curPtr
     else
          gTailPtr = curPtr;                  // no next struct: curPtr is now the tail
     *nextPtrPtr = curPtr;                      // link next or previous struct (or head) to curPtr
} //когда функция передах структкру, а потом получает новую, указатели сохраняются?

void ListDVDs( bool forward )
{
     struct DVDInfo *curPtr = ( forward ? gHeadPtr : gTailPtr );
     bool separator = false;    
     if ( curPtr == NULL ) 
     {
          printf( "No DVDs have been entered yet...\n" );
     } 
     else 
     {
          while ( curPtr != NULL ) 
          {
               if ( separator )
                    printf( "--------\n" );
               printf( "Title:   %s\n", curPtr->title );
               printf( "Comment: %s\n", curPtr->comment );
               printf( "Rating:  %d\n", curPtr->rating );            
               curPtr = ( forward ? curPtr->next : curPtr->prev );
               separator = true;
          }
     }
}

char *TrimLine( char *line )
{
     size_t length = strlen( line );
     while ( length > 0 && isspace( line[length-1] )) 
     {
          line[length-1] = '\0';
          length--;       
     }
     return line + strspn( line, " \t" );
}
4

2 に答える 2

0
struct DVDInfo **nextPtrPtr = &gHeadPtr;
struct DVDInfo *prevPtr = NULL;

プログラマーはグローバル ヘッド ポインター (gHeadPtr) をいじりたくないので、nextPtrPtr が必要です。Pointer to Pointer を使用する方が反復に Head Pointer 自体を使用するよりも優れているため、このポインターを使用してリストを反復処理するだけです。

while ( *nextPtrPtr != NULL && curPtr->rating > (*nextPtrPtr)->rating ) 
    {
    prevPtr = *nextPtrPtr;
    nextPtrPtr = &(prevPtr->next);
    }

上記の AddToList のコードは、リスト内で新しいノードを配置する場所 (つまり、映画の格付けの降順) を見つける処理を処理します。

curPtr->prev = prevPtr;                 // link to previous struct
curPtr->next = *nextPtrPtr;               // link to next struct

上記の行は、リンク リストへの挿入に使用されます。

if ( curPtr->next != NULL )
    curPtr->next->prev = curPtr;     // link prev of next struct to curPtr
else
    gTailPtr = curPtr; 

上記のこれらの行は、新しいノード (curPtr) がリンク リストの最初のノードまたは最後のノードである場合に使用されます。

于 2013-09-13T01:09:39.133 に答える
0
struct DVDInfo **nextPtrPtr = &gHeadPtr;
...
...
*nextPtrPtr = curPtr;  

二重ポインタの値は、別のポインタのアドレスです。AddToList() の場合、nextPtrPtr が指す値がリスト ヘッダー (gHeadPtr) のアドレスで自動的に開始され、必要に応じて更新されるため、ダブル ポインターが必要です。gHeadPtr を更新する必要がなければ、「struct DVDInfo *nextPtrPtr」を簡単に使用できたはずです。

AddToList() には 2 つのケースがあり、最初のケースでは必ずダブル ポインターが必要です。最初のケースは、gHeadPtr が NULL で、リストに要素がないことを意味する場合です。このような場合、「**nextPtrPtr = &gHeadPtr」は、nextPtrPtr の hte 値が NULL になることを意味します。それが「*nextPtrPtr != NULL」でチェックしているものです。これは NULL であるため、while ループをスキップし、*nextPtrPtr は curPtr を指します。したがって、gHeadPtr は curPtr を指し始めます。2 番目のケースは、ヘッド (gHeadPtr) が NULL でない場合、 while ループと nextPtrPtr は評価基準に基づいて最後の要素を指すため、curPtr は nextPtrPtr ノードの後に​​ノードとして追加されます。

これをさらに説明するために、AddToList() が単一のポインターを使用し、gHeadPtr が NULL であるとします (説明のために nextPtrPtr をポインターにする次のコードを提供しています)。この場合、nextPtrPtr は gHeadPtr を指します。つまり、gHeadPtr のアドレス (0x1010 としましょう) を取得します。nextPtrPtr は NULL であるため (おそらく gHeadPtr を NULL で初期化する必要があります)、while ループをスキップし、最後のステートメントが "nextPtrPtr = curPtr;" で実行されます。これにより、nextPtrPtr は curPtr (アドレス 0x2020 を持っているとしましょう) を指すようになりました。このようにして、gHeadPtr は 0x2020 を指すように更新されませんでした。

/* Note: Incorrect version for the sake of explanation */
void AddToList( struct DVDInfo *curPtr ) {
    struct DVDInfo *nextPtrPtr = gHeadPtr;
    struct DVDInfo *prevPtr = NULL;
    while (nextPtrPtr != NULL && curPtr->rating > (nextPtrPtr)->rating ) {
        prevPtr = nextPtrPtr;
        nextPtrPtr = prevPtr->next;
    }
    curPtr->prev = prevPtr;                 // link to previous struct
    curPtr->next = nextPtrPtr;               // link to next struct
    if ( curPtr->next != NULL )
        curPtr->next->prev = curPtr;     // link prev of next struct to curPtr
    else
        gTailPtr = curPtr;                // no next struct: curPtr is now the tail
    nextPtrPtr = curPtr;                   // link next or previous struct (or head) to curPtr
}
于 2013-09-13T00:47:03.090 に答える