Почему мое содержимое связанного списка исчезает при выходе из функции?

#c #function #linked-list #scanf

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

Вопрос:

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

Затем я проверяю адрес каждого созданного и связанного узла и не обнаружил никаких проблем, когда он находится внутри функции, список ссылок работал нормально, но не в main().

Input.txt
3
1 Кодировка Марк Программирование
1 Кулинария Минни Кулинария
1 Садоводство Пенни Ботаника

Этот код не завершен, но в нем содержится моя проблема:

 #includelt;stdio.hgt; #includelt;ctype.hgt; #includelt;string.hgt;  struct book {  char *title;  char *author;  char *subject; }; struct library {  struct book collection;  int num_books;  struct library *next; };  void AddBook(FILE *IF, FILE *OF, struct library** thislib);//function prototype  int main(void){  FILE *IF,*OF;  int sel,numOp,i;  struct library *Lib=NULL;//declare head pointer  if(((IF=fopen("library.txt","a "))==NULL)||((OF=fopen("output.txt","w"))==NULL)){//open input and output file  printf("File cannot be open!");  }  else{   fscanf(IF," %d",amp;numOp); //scan the number of operation from file  for(i=0;ilt;numOp;i  ){ //Loop according to number of operation  if(feof(IF)) //if file pointer reach EOF break  break;   fscanf(IF," %d",amp;sel); //scan the type of operation  switch(sel){  case 1:   AddBook(IF,OF,amp;Lib); //add the book if sel is 1  break;  case 2:    break;  }  printf("%s ", Lib-gt;collection.title); // print the title of the book but it show nothing  }  }  return 0; }  void AddBook(FILE *IF, FILE *OF, struct library** thislib){  char title[30],author[30],subject[20]; //declare variable to hold data  struct library *temp=NULL; //create a new node  struct library *ptr=*thislib; //create a pointer that point to head of link list  temp=(struct library*)malloc(sizeof(struct library)); //allocate memory for the new node  fscanf(IF," %s %s %s" ,title,author,subject);  temp-gt;collection.title=title; // put the data into link list  temp-gt;collection.author=author;  temp-gt;collection.subject=subject;  temp-gt;next=NULL;  if((*thislib)==NULL){  (*thislib)=temp; // if there is no content in link list put temp into head  }  else{  while (ptr-gt;next!=NULL)  {  ptr=ptr-gt;next; //put node at the end of link list  }  ptr-gt;next=temp;  }  fprintf(OF,"The book %s author %s subject %s has been added to the library.n",title,author,subject);  printf("%s ",(*thislib)-gt;collection.title); //this work fine but it keep updating, weren't it suppose to have the same value }  

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

1. temp-gt;collection.title=title; помещает указатели на локальные переменные в узел списка. Эти указатели становятся недействительными при возврате функции. Вам нужно сделать динамические копии строк, например temp-gt;collection.title=strdup(title)

2. Эй, это работает, большое вам спасибо, strcpy() тоже работает?

3. Вы не можете использовать strcpy() его, пока не выделите память. strdup() представляет собой комбинацию malloc() и strcpy() .

Ответ №1:

  1. Ты забываешь об #include lt;stdlib.hgt; этом . Ваш код дико неопределен, потому что вы срезали высокие биты возврата malloc() .
  2. Вы вернули указатели на массивы стека.
 temp-gt;collection.title=title; // put the data into link list  temp-gt;collection.author=author;  temp-gt;collection.subject=subject;  

Надо их обмануть. strdup() это твой друг:

 temp-gt;collection.title=strdup(title); // put the data into link list  temp-gt;collection.author=strdup(author);  temp-gt;collection.subject=strdup(subject);  
  1. Эта строка не работает в вашем тестовом примере: fscanf(IF," %d",amp;numOp); Входные данные не соответствуют шаблону; вы входите в цикл с неопределенным numOp значением . (Я тривиально исправил это, исправив входной файл. Вы всегда должны проверять возврат scanf.)
  2. Это сканирование приводит к проблеме чтения, вызывающей бессмыслицу.
 fscanf(IF," %s %s %s" ,title,author,subject);  

но в ваших входных данных есть четыре поля, разделенные пробелами.

  1. В выводе отладки отображается первый элемент в связанном списке, но вы каждый раз добавляете его в конец списка, поэтому он не изменится.

Объяснение «срезал высокие биты»:

Неявное объявление от отсутствующего #include lt;stddef.hgt; было бы int malloc(size_t) , что неверно. На 32-разрядных платформах это работает, но на 64-разрядных платформах это не так. int получает передачу void * , которая не приводит к правильному значению.

Допустим, что malloc() вернулся 0x104C000010 . Обратный адрес выглядит так (окончание здесь не имеет значения по причинам, в которые я сейчас вдаваться не собираюсь)

 0 63  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  |0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|1|0|0|1|0|0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -   

Но возвращаемое значение интерпретируется как 32-разрядное целое число (большинство 64 платформ имеют sizeof(int) = 4), поэтому оно будет интерпретироваться как

 0 31  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  |0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|1|0|0|1|0|0|  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -   

и когда struct library * это делается, это приводит к

 0 63  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  |0|0|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|1|1|0|0|1|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -   

который 0x4C000010 . Упс, это указывает на что-то другое. Может случиться все, что угодно, но, скорее всего, авария.

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

1. «вы срезали высокие куски возвращения мэллока ()». Как?

2. @MadPhysicist: Неявный тип int malloc(...); меньше и int меньше, чем void * на современных платформах.

3. Что значит срезанные верхние биты? Какое влияние это окажет?

4. @Джошуа. Это хороший выбор, особенно если у OP gt; 4 ГБ оперативной памяти. Возможно, вы захотите изложить это для ОП в ответе.

5. @Strugle: #include lt;stdlib.hgt; и компилировать с включенными предупреждениями. Это дает предупреждение о «Неявном объявлении».