Почему эти фрагменты кода ведут себя по-разному?

#c #linked-list

#c #связанный список

Вопрос:

Я относительно новичок в C и изучал связанные списки с указателями.

Я узнал, что это (*foo).bar одно и то же объявление foo->bar . foo->bar используется, потому что он более удобочитаем.

Поэтому я не понимаю, почему эти фрагменты кода ведут себя по-разному:

1)

 void appendCourse(CourseNode** pLL, Course c){
    CourseNode * root = *pLL;

    CourseNode* last = makeCourseNode(c);

    if(root != NULL){
        CourseNode node = *root;

        while(node.pNext != NULL){
            node = *node.pNext;
        }

        node.pNext = last;
    } else {
        *pLL = last;
    }  
}
  

и

2)

 void appendCourse(CourseNode** pLL, Course c){
    CourseNode * root = *pLL;

    CourseNode* last = makeCourseNode(c);

    if(root != NULL){
        CourseNode *node = root;

        while(node->pNext != NULL){
            node = node->pNext;
        }

        node->pNext = last;
    } else {
        *pLL = last;
    }  
}
  

мне кажется, что 1) должен вести себя так, как если бы сначала выполнялось разыменование, затем доступ к участникам. Вроде как (*foo).bar

но 1), похоже, вообще не работает правильно, он может успешно добавить только первый элемент.

2) однако добавляет все элементы в связанный список.

На случай, если это поможет: мои структуры и другой метод:

 typedef struct CourseNode {
    struct CourseNode* pNext;
    Course course;
} CourseNode;

typedef struct
{
    StudentNode *pWaitlistHead;             // Waitlist for this course
    char szCourseId[12];                    // Course Identifier
    char szRoom[15];                        // Room number of the course
    char szDays[15];                         // What days the course will meet, ex: MWF, TR, etc
    char szTimes[15];                        // Meeting Time, ex: 10:00-11:15am
    int  iAvailSeats;                       // Number of available seats in the course
    double dFee;                            // Additional fees for the course
} Course;


CourseNode* makeCourseNode(Course c){
    CourseNode * node = malloc(sizeof(CourseNode));
    node->pNext = NULL;
    node->course = c;
    return node;
}
  

Комментарии:

1. Вы создаете локальную копию CourseNode , которая не является копией корневого ptr. Если вы покажете код, который вызывает appendCourse , вам будет легко помочь

2. Просто потому, что (*foo).bar это не то же самое, что *foo.bar

3. Вы сделали не только синтаксическую десуггерацию, но и семантическое изменение.

Ответ №1:

     CourseNode node = *root;

    while(node.pNext != NULL){
        node = *node.pNext;
    }
  

Это создает новый CourseNode called node . Значение этого нового CourseNode изменено, но это никак не влияет на связанный список.

     CourseNode *node = root;

    while(node->pNext != NULL){
        node = node->pNext;
    }
  

Здесь node указывает на CourseNode , который находится в связанном списке.

Самый простой способ понять разницу заключается в том, что первый фрагмент кода создает новые CourseNode s. Это похоже на разницу между этими двумя:

 int foo (int *i)
{
    int *j = i; // j is a pointer to the same int i points to
    *j = 2;     // this changes the value of the int i points to

    int j = *i; // this creates a new int
    j = 2;      // this changes the value of that new int
}