2015-04-02 2 views
0

я в настоящее время есть связанный список и нужно добавить в него данные, которые вводятся пользователем с клавиатуры так у меня есть два структур:добавления узла в связанный список, используя функцию

struct CourseInfo { 
    int courseID; 
    char courseName[30]; 
}; 
typedef struct CourseInfo courseinfo; 
struct StudentInfo { 
    char StudentID[10]; 
    char FirstName[21]; 
    char LastName[26]; 
    int num_course; 
    courseinfo array[10]; 
    struct StudentInfo *next; 
}; 

Так я имеют связанный список с 3 узлами в настоящее время. Затем мне нужно вызвать функцию и добавить узел. Узел должен быть вставлен в правильное место, в котором идентификатор studentID должен быть меньше его, а идентификатор studentID после этого должен быть больше, поэтому текущие идентификаторы, которые у меня есть, - 111111111, 333333333 и 444444444, и я пытаюсь добавить 222222222 так что бы во втором месте, так что моя функция выглядит следующим образом:

studentinfo *addStudent(studentinfo *data) //returns type studentinfo* now 
{ 
    studentinfo *add; 
    add = malloc(sizeof(studentinfo)); 
    add->next = NULL; //Now its set to NULL to begin 
    int knt; 
    printf("%s", "Adding new student:\nStudent ID: "); 
    scanf("%s", add->StudentID); 
    printf("%s", "First Name: "); 
    scanf("%s", add->FirstName); 
    printf("%s", "Last Name: "); 
    scanf("%s", add->LastName); 
    printf("%s", "Number of courses: "); 
    scanf("%d", &add->num_course); 
    for(knt = 0; knt < add->num_course; knt++) { 
     printf("%s", "Course ID: "); 
     scanf("%d", &add->array[knt].courseID); 
     printf("%s", "Course Name: "); 
     scanf("%s", add->array[knt].courseName); 
    } 
    if(searchStudentID(data, add->StudentID)) { 
     puts("immediately inside if"); 
     while(data != NULL) { 
      puts("Immediately inside while"); 
      if(strcmp(add->StudentID, data->StudentID) < 0) { 
       puts("inside if"); 
       add->next = data; 
       data = add; 
      } 
      else { 
       puts("inside first else"); 
       studentinfo *PrevPtr = data; 
       studentinfo *NPtr = data->next; 
       while(NPtr != NULL) { 
        ("inside while(NPTR != NULL)"); 
        if(strcmp(add->StudentID, NPtr->StudentID) < 0) { 
         add->next = PrevPtr; 
         PrevPtr->next = add; 
         break; 
        } 
        else { 
         puts("inside a differnet else"); 
         PrevPtr = NPtr; 
         NPtr = NPtr->next; 
        } 
       } 
       if(PrevPtr->next == NULL) { 
        puts("inside last if"); 
        add->next = NULL; 
        PrevPtr->next = add; 
       } 
      } 
     } 
    } 
    else { 
     puts("Found id"); 
    } 
    return data; //returns data back to call 
} 

так я добавил все эти puts заявления, потому что я хотел понять, почему программа терпела крах. Таким образом, оператор puts puts("Inside a different else") застревает в бесконечном цикле и сохраняет печать. Функция searchStudentID просто возвращает 1, если у нас уже нет идентификатора и 0, если мы уже имеем его. Я знаю, что эта функция работает, поэтому нет необходимости публиковать ее.

Я думаю, что проблема может быть в перерыве; заявление, потому что оно не выход из первого во время цикла, но только выходит из внутреннего цикла, но им не positive.The вызов этой функции выглядит следующим образом:

list = addStudent(list); //Now the new data is stored in list 

Где список связанный список с 3-мя узлами

+0

Прошел ли вы через код с отладчиком – pm100

+0

@ pm100 В настоящее время я использую code :: blocks и когда я строю и запускаю, я не получаю ошибок – JackV

+1

Несвязанное последнее сообщение в предложении else должно читать: «Найдено id * и утечка памяти * «Что касается реальной проблемы (проблем), достаточно сказать, что вы это делаете:' data = (ничего) 'означает * ничего * обратно на стороне вызывающей стороны этой функции. – WhozCraig

ответ

1

Управление связанными списками - это управление указателями узлов, а не только узлами.Вы хотите сделать несколько вещей, чтобы сделать это значительно проще на себя:

  • Отделите шаг ввода от этапа поиска и ввода. Они не принадлежат друг другу, независимо от того, как они могут казаться иначе. Самое большое преимущество, которое это приносит вам, сводится к тому, что ваш код ввода в список должен выполняться (и только, что он должен делать): управление связанным списком. Я сохранил вашу целостность, но вы действительно должны проверять ошибки и выполнять чтение данных в другом месте.

  • Используйте указатель на указатель, чтобы просмотреть список. Большим преимуществом этого является устранение необходимости вставки в головной блок с особым корпусом. Если это позиция, которую в конечном итоге займет новый узел, пусть будет так, но устранение этого особого случая еще больше уменьшит сложность алгоритма.

  • Не выполняйте поиск в списке, если вы не можете сохранить результаты поиска, которые будут использоваться для логики вставки. Не имеет смысла выполнять проверку O (N) связанного списка, чтобы определить, имеются ли уже входные данные, только для повторного поиска , чтобы найти позицию, на которую будут введены данные. Сделайте это один раз. Найдите позицию, в которой она принадлежит. Если он уже есть, ничего не делайте, иначе вы сидите у обрыва правильного места вставки уже.

  • И, наконец, не выделяйте новый узел, если не знаете, что он вам нужен. Используйте автоматическую переменную, которая помогает самоотбрасывать, если вы ничего не делаете.

Собираем все, что вместе дает что-то вроде этого:

struct CourseInfo { 
    int courseID; 
    char courseName[30]; 
}; 
typedef struct CourseInfo CourseInfo; 

struct StudentInfo { 
    char StudentID[10]; 
    char FirstName[21]; 
    char LastName[26]; 
    int num_course; 
    CourseInfo array[10]; 
    struct StudentInfo *next; 
}; 
typedef struct StudentInfo StudentInfo; 

StudentInfo *addStudent(StudentInfo *head) 
{ 
    StudentInfo **pp = &head, *p = NULL, rec; 
    int knt; 

    // TODO: error check your inputs! 
    printf("%s", "Adding new student:\nStudent ID: "); 
    scanf("%s", rec.StudentID); 
    printf("%s", "First Name: "); 
    scanf("%s", rec.FirstName); 
    printf("%s", "Last Name: "); 
    scanf("%s", rec.LastName); 
    printf("%s", "Number of courses: "); 
    scanf("%d", &rec.num_course); 
    for(knt = 0; knt < rec.num_course; knt++) { 
     printf("%s", "Course ID: "); 
     scanf("%d", &rec.array[knt].courseID); 
     printf("%s", "Course Name: "); 
     scanf("%s", rec.array[knt].courseName); 
    } 

    // walk the list pointers, starting with head, looking for 
    // a node that is equal or greater than the input node 
    while (*pp && (knt = strcmp((*pp)->StudentID, rec.StudentID)) < 0) 
     pp = &(*pp)->next; 

    // leave now if already present 
    if (*pp && knt == 0) 
     return head; 

    // allocate new node 
    p = malloc(sizeof *p); 
    if (p == NULL) 
    { 
     perror("Failed to allocate new node"); 
     exit(EXIT_FAILURE); 
    } 

    // structure copy. 
    *p = rec; 

    // link into proper list position. 
    p->next = *pp; 
    *pp = p; 

    // always return the head (which may have updated above) 
    return head; 
} 

Вот и все. Как уже упоминалось, я лично выполнял операцию ввода где-то, кроме этой функции, но я оставляю это для рассмотрения.

Удачи.

+0

Большое спасибо за очень подробный ответ, и у меня есть 1 вопрос, который я не понимаю, когда вы выделяете память 'p = malloc (sizeof * p)' shouldnt, который должен быть 'p = malloc (sizeof (studentinfo))' потому что wont 'sizeof * p' будет 0, так как' * p = NULL ' – JackV

+1

@JackRV' sizeof' - это конструкция оператора времени компиляции; он работает немного иначе, чем вы можете сначала подумать. [См. Этот вопрос и выбранный ответ] (http://stackoverflow.com/questions/19785518/is-dereferencing-null-pointer-valid-in-sizeof-operation) – WhozCraig

+0

О, хорошо, я понимаю, что это работает по-другому, чем я думал было бы – JackV

0

Так как эта функция обновляет список, вам необходимо либо это

studentinfo *addStudent(studentifo *data) 

и вернуть обновленное значение головы. Или

void addStudent(studentifo **data) 

и сделать

*data = <new thing> 
0

Вопросы, которые я вижу:

  1. Вы не настройки add->next к NULL.

  2. Вы меняете data локально.

     add->next = data; 
         data = add; 
    

    изменяет значение data локально в функции. Он не изменяет значение в вызывающей функции.

  3. У вас есть чек

    while(data != NULL) 
    

    следуя if заявление

    if(searchStudentID(data, add->StudentID)) { 
    

    , но я не вижу какой-либо код, чтобы добавить новый студент, когда searchStudentID(data, add->StudentID) возвращается false и когда data == NULL начать с ,

+0

Ну, если searchStudentID возвращает 0, тогда я не хочу добавлять данные, потому что ученик уже находится в нашем файле – JackV

+0

@JackRV. Это имеет смысл. Как насчет того случая, когда 'data == NULL' начнется? –

+0

Итак, я отредактировал свой вопрос и программу, чтобы соответствовать этим критериям, и я понимаю, почему мне нужно было добавить эти вещи, хотя моя программа все еще застревает в бесконечном цикле в том же месте. – JackV

Смежные вопросы