Чтение из файла в связанный список C - PullRequest
0 голосов
/ 01 июня 2019

Я пытаюсь прочитать текстовый файл, а затем сохранить его в связанном списке на C. Я много пробовал, но не нашел решения.

Вот что у меня есть:

typedef struct contact{

    char name[50];
    char number[10];
    char bithday[15];
    struct contact *next;
}contact;

struct contact *head;
FILE *fp;

Эта часть сохраняет контакты, которые у меня уже есть, в текстовый файл.

void backup(){

    struct contact *ap;

    fp=fopen("save_contacts.txt", "w");

    if(fp==NULL){
        printf(" Error\n");
        system("pause");
        return 1;
    }
    for (ap=head;ap!=NULL;ap=ap->next){
        fprintf(fp,"%s ",ap->name);
        //fprintf(fp,", ");
        fprintf(fp,"%s ",ap->number);
        //fprintf(fp,", ");
        fprintf(fp,"%s ",ap->birthday);
        //fprintf(fp,", ");
        fprintf(fp,"; ");
    }
    fprintf(fp, "End");
}

Так что моя проблема с этой частью, она не читает текстовый файл.

void read() {
    struct contact *ap;
    int i;
    head=NULL;
    char aux[30];

    FILE *fp=fopen("save_contacts.txt","r");

    do{

        head=NULL;
        ap=(contact*)malloc(sizeof(contact));

        fscanf(fp,"%s ",&ap->name);
        fscanf(fp,"%s ",&ap->number);
        fscanf(fp,"%s ",&ap->birthday);
        fscanf(fp,"%s ",aux);

        if(strcmp(aux,";")==0){
            ap=ap->next;
        }
    }while(strcmp(aux,"End")!=0);

}

1 Ответ

1 голос
/ 01 июня 2019

Doing

   ap=(contact*)malloc(sizeof(contact));

   fscanf(fp,"%s ",&ap->name);
   fscanf(fp,"%s ",&ap->number);
   fscanf(fp,"%s ",&ap->birthday);
   fscanf(fp,"%s ",aux);

   if(strcmp(aux,";")==0){
       ap=ap->next;

ap->next не задано, поэтому второй ход ap имеет неопределенное значение, поэтому поведение не определяется при разыменовании

Запишите свой способ сохранения с помощью:

 for (ap=head;ap!=NULL;ap=ap->next){
   ...
   fprintf(fp,"; ");
 }
 fprintf(fp, "End");

несовместимо с вашим способом чтения где ';' заменено на 'End' для последнего элемента

Вы можете сделать это (я полагаю, что нет ';' для последнего элемента):

int read() {      
  FILE *fp=fopen("save_contacts.txt","r");

  if (fp == NULL) {
    fprintf(stderr, "cannot open 'save_contacts.txt'\n");
    head = NULL;
    return 0;
  }

  contact ** pp = &head;
  char aux[30];
  int result;

  for (;;) {
    *pp = malloc(sizeof(contact));

    if (fscanf(fp,"%49s %9s %14s %29s", (*pp)->name, (*pp)->number, (*pp)->birthday, aux) != 4) {
      fputs("invalid file, cannot read the 3 fields then ;/End\n", stderr);
      result = 0;
      free(*pp);
      break;
    }
    pp = &(*pp)->next;
    if (strcmp(aux,"End") == 0) {
      result = 1;
      break;
    }
    if (strcmp(aux, ";") != 0) {
      fputs("invalid file, expected ; or End\n", stderr);
      result = 0;
      break;
    }
  }

  *pp = NULL;
  fclose(fp);

  return result;
}

возвращает 0 в случае проблемы, иначе 1

Примечание. Я защищаю чтение строки, чтобы не записывать их, и проверяю, верный ли файл


Например, с полной программой

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct contact{
  char name[50];
  char number[10];
  char birthday[15]; /* not bithday */
  struct contact *next;
}contact;

struct contact *head;

int read() {      
  FILE *fp=fopen("save_contacts.txt","r");

  if (fp == NULL) {
    fprintf(stderr, "cannot open 'save_contacts.txt'\n");
    head = NULL;
    return 0;
  }

  contact ** pp = &head;
  char aux[30];
  int result;

  for (;;) {
    *pp = malloc(sizeof(contact));

    if (fscanf(fp,"%49s %9s %14s %29s", (*pp)->name, (*pp)->number, (*pp)->birthday, aux) != 4) {
      fputs("invalid file, cannot read the 3 fields then ;/End\n", stderr);
      result = 0;
      free(*pp);
      break;
    }
    pp = &(*pp)->next;
    if (strcmp(aux,"End") == 0) {
      result = 1;
      break;
    }
    if (strcmp(aux, ";") != 0) {
      fputs("invalid file, expected ; or End\n", stderr);
      result = 0;
      break;
    }
  }

  *pp = NULL;
  fclose(fp);

  return result;
}

int main()
{
  if (read()) {
    /* debug */
    for (contact * p = head; p != NULL; p = p->next)
      printf("%s %s %s\n", p->name, p->number, p->birthday);
  }

  /* free resources */
  while (head != NULL) {
    contact * p = head;

    head = head->next;
    free(p);
  }

  return 0;
}

Компиляция и исполнение:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra -Wall l.c
pi@raspberrypi:/tmp $ cat save_contacts.txt 
bruno 007 19/02/1960 ;
you 001 01/01/2010 ;
bar 123 31/12/1999 End
pi@raspberrypi:/tmp $ ./a.out
bruno 007 19/02/1960
you 001 01/01/2010
bar 123 31/12/1999
pi@raspberrypi:/tmp $ 

Исполнение под valgrind :

pi@raspberrypi:/tmp $ valgrind ./a.out
==2334== Memcheck, a memory error detector
==2334== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2334== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2334== Command: ./a.out
==2334== 
bruno 007 19/02/1960
you 001 01/01/2010
bar 123 31/12/1999
==2334== 
==2334== HEAP SUMMARY:
==2334==     in use at exit: 0 bytes in 0 blocks
==2334==   total heap usage: 6 allocs, 6 frees, 5,712 bytes allocated
==2334== 
==2334== All heap blocks were freed -- no leaks are possible
==2334== 
==2334== For counts of detected and suppressed errors, rerun with: -v
==2334== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
pi@raspberrypi:/tmp $ 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...