#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:
- Ты забываешь об
#include lt;stdlib.hgt;
этом . Ваш код дико неопределен, потому что вы срезали высокие биты возвратаmalloc()
. - Вы вернули указатели на массивы стека.
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);
- Эта строка не работает в вашем тестовом примере:
fscanf(IF," %d",amp;numOp);
Входные данные не соответствуют шаблону; вы входите в цикл с неопределеннымnumOp
значением . (Я тривиально исправил это, исправив входной файл. Вы всегда должны проверять возврат scanf.) - Это сканирование приводит к проблеме чтения, вызывающей бессмыслицу.
fscanf(IF," %s %s %s" ,title,author,subject);
но в ваших входных данных есть четыре поля, разделенные пробелами.
- В выводе отладки отображается первый элемент в связанном списке, но вы каждый раз добавляете его в конец списка, поэтому он не изменится.
Объяснение «срезал высокие биты»:
Неявное объявление от отсутствующего #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;
и компилировать с включенными предупреждениями. Это дает предупреждение о «Неявном объявлении».