2015-05-23 3 views
1

Я не знаю, почему я могу прочитать Связанный список без проблем в LABEL: 1; но программа просто падает и печатает захват в LABEL: 0; В других терминах, почему связанный список отлично работает в функции лекции, но не за его пределами? Вот мой код:Программа вылетает при печати связанного списка на экране

/* including libraries */ 
#define V 20 

typedef struct DATA{ 
    char* NomP;char* NomA; 
    struct DATA *Next; 
}DATA; 

// Prototypes . 

int main(void) 
{ 
    char FileName[V]; 
    puts("Data file ? : ");gets(FileName); 

    FILE* fs = fopen(FileName,"r"); // Check if fs is NULL 

    DATA *HEAD = MALLOC(sizeof (DATA)); int len = lecture_data(fs,HEAD); 
    print_data(HEAD,len); //LABEL : 0 
    return 0; 
} 

int lecture_data(FILE *fs,DATA *ROOT) 
{ 
    char cNom[V],cArticle[V]; 
    int eofs=0;int i=0; 

while(!eofs) 
{ 
    DATA *Data = MALLOC(sizeof (DATA)); 
    fscanf(fs,"%s %s",cNom,cArticle); 
    Data->NomA = MALLOC(strlen(cArticle)+1); 
    Data->NomP = MALLOC(strlen(cNom)+1); 
    strcpy(Data->NomA,cArticle); 
    strcpy(Data->NomP,cNom); 
    if(i==0) 
    { 
     Data -> Next = NULL ; 
     ROOT = Data ; 
    } 
    else 
    { 
     DATA* Ptr = ROOT ; 
     while((Ptr->Next) != NULL) 
     { 
      Ptr = (Ptr -> Next); 
     } 
     Data -> Next = NULL ; 
     Ptr -> Next = Data ; 
    } 
    i++; 
    eofs = feof(fs) ; 
    // check ferror(fs) here 
} 
    puts("Start of reading :"); 

    print_data(ROOT,len); // LABEL : 1 

    puts("End Of Reading "); 
    fclose(fs); 
    return i; 
} 

Вот функция печати:

void print_data(DATA *L_ROOT,int len) 
{ 
    int i = 0 ; 
    DATA* LINK; 
    LINK = L_ROOT; 
    while(LINK != NULL) 
    { 
     printf("%d : DATA->NomA : %s\n",i,LINK->NomA); 
     printf("%d : DATA->NomP : %s\n",i,LINK->NomP); 
     LINK = LINK -> Next ; 
     i++; 
    } 
} 
+0

Этот код не компилируется. Функция 'lecture_data' использует неопределенную переменную (' ken'). – Amit

+0

Как вам нравится? что (кен)? –

+0

Я думаю, что он пытался написать len – Subinoy

ответ

2

Вы выделения данных для корня списка в основной функции, и передать функции, так что он может заполнить список, но при первом назначении элемента вы перезаписываете значение указателя ROOT.

это заставляет вас потерять единственное соединение между функцией и внешним миром (так как возвращаемое значение - это просто число), поэтому значение HEAD в main() остается не имеющим смысла (поскольку ваша функция никогда не использует его), в то время как список остается выделенным в некоторой ячейке памяти, на которую не указывает ни одна внешняя сторона, что означает, что она потеряна. Запуск valgrind мог бы определить это.

Вы можете исправить это путем изменения (я == 0) случай из -

ROOT = Data ; 

в

ROOT->next = Data ; 

, но убедитесь, что вы игнорируя данные корневого узла позже ,

p.s. - использование капитализированных переменных и типов не считается хорошей идеей (в основном это зарезервировано для макросов). Это также делает ваш код похожим на крик :)

+0

, но ROOT должен зарезервировать адрес DATA, я думаю: o; не могли бы вы объяснить это мне? ^? Я начинаю с нуля –

+0

@MichaelHeidelberg, вы выделили головной узел снаружи для этой цели - зарезервировать местоположение первого элемента. Проблема в том, что вы никогда не используете этот адрес, который вы выделили, вы просто переполняете его первым распределением, которое вы выполняете внутри функции, - отслеживайте свои задания, и вы это увидите. Если вы хотите, чтобы голова указывала прямо на первый узел, просто не выделяйте ничего в случае (i == 0) и вместо этого используйте адрес, который вы получили в качестве аргумента (просто начните с 'if (i == 0) Data = ROOT', else malloc it) – Leeor

+0

Я понял, спасибо, я думал, что HEAD будет адресом первого DATA. Я забыл, что адрес ГОЛОВА остается таким, каким он есть снаружи. –

1

Проблема (основная) заключается в том, что lecture_data не использует свой входной параметр (ROOT) для хранения связанного списка и не возвращает внутренний сгенерированный список , Правильный способ справиться с этим состоит в том, чтобы ROOT ссылается на параметр вызывающей области, чтобы он мог, при необходимости, обновлять ссылку.

int main(void) 
{ 
    char FileName[V]; 
    puts("Data file ? : ");gets(FileName); 

    FILE* fs = fopen(FileName,"r"); // Check if fs is NULL 

    DATA *HEAD = NULL; 
    int len = lecture_data(fs, &HEAD); 
    print_data(HEAD); //LABEL : 0 

    return 0; 
} 

int lecture_data(FILE *fs,DATA **ROOT) 
{ 
    char cNom[V],cArticle[V]; 
    int i=0; 
    DATA *current = *ROOT; // grab the passed in reference 

    while(!feof(fs)) 
    { 
     if(fscanf(fs,"%s %s",cNom,cArticle) <= 0) // This call is only successful if the return value is > 0 
     { 
      // check ferror(fs) here 
      continue; // Can also "break;" here, essentially, it's eof already 
     } 

     DATA *Data = MALLOC(sizeof (DATA)); 
     Data->NomA = MALLOC(strlen(cArticle)+1); 
     Data->NomP = MALLOC(strlen(cNom)+1); 
     strcpy(Data->NomA,cArticle); 
     strcpy(Data->NomP,cNom); 

     if(NULL == current) // ROOT was uninitialized before the call 
     { 
      Data -> Next = NULL; 
      *ROOT = Data; 
     } 
     else 
     { // We don't need to iterate the list in every step. 
      Data->Next = current->Next; // This part allows the function to insert nodes in the middle/end of an existing list 
      current->Next = Data; 
      current = Data; 
     } 
     i++; 
    } 
    puts("Start of reading :"); 

    print_data(ROOT); // LABEL : 1 

    puts("End Of Reading "); 
    fclose(fs); 
    return i; 
} 

Примечание: print_data ничего с параметром len не делать, поэтому нет необходимости передавая его вовсе.

Это решение не является расточительным с точки зрения «пустых» узлов в списке (в отличие от пустого заголовка для игнорирования) и подходит как для инициализации списка с нуля, так и для случаев, когда вам необходимо добавить/вставить в существующий список.

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