从C中的txt文件中读取链表

时间:2017-07-14 16:18:37

标签: c linked-list scanf

我试图从文件中读取我的链表而没有运气。使用fprintf正确保存Struct(无法使用fwrite)。这是我的结构:

typedef struct database
{
    int id;
    int nrindeksu;
    char *imie;
    char *nazwisko;
    char *wydzial;
    char *kierunek;
    struct database* link;
} data;

char buffer[1024]; //changed buffer size

我使用此功能将链接列表保存到文件中:编辑:对其他功能进行一些更改后,这个功能会崩溃。

void save(data* head)
{
    FILE *fp;
    fp = fopen("test.txt", "w");
    data* current = head->link;

    while (current != NULL) {
        fprintf(fp,"%d ",current->nrindeksu);
        fprintf(fp,"%s ",current->imie);
        fprintf(fp,"%s ",current->nazwisko);
        fprintf(fp,"%s ",current->wydzial);
        fprintf(fp,"%s\n",current->kierunek);
        current = current->link;
    }
    fclose(fp);
}

并试图从文件中读取它:

void read(data* head)
{
    data* current = head;
    FILE *fp;
    fp = fopen("test.txt", "r");

    while(//I still need help with this loop)
    fscanf(fp, "%d", current->link->nrindeksu);

    fscanf(fp, "%s", buffer);
    current->link->imie=malloc(strlen(buffer) + 1);
    if(current->link->imie == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->imie, buffer);

    fscanf(fp, "%s", buffer);
    current->link->nazwisko=malloc(strlen(buffer) + 1);
    if(current->link->nazwisko == NULL) {
        fprintf(stderr, "Malloc error");
        exit(0);
    }
    strcpy(current->link->nazwisko, buffer);

    fscanf(fp, "%s", buffer);
    current->link->wydzial=malloc(strlen(buffer) + 1);
    if(current->link->wydzial == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->wydzial, buffer);

    fscanf(fp, "%s", buffer);
    current->link->kierunek=malloc(strlen(buffer) + 1);
    if(current->link->kierunek == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->kierunek, buffer);

    fclose(fp);
}

知道为什么它没有读什么? 此外,我不知道如何编写一个循环来确定它应该停止从文件中读取的位置。

编辑: 我使用此功能将项目添加到列表中:

void add_bottom(data* head) 
{
    data* current = head;

    while (current->link != NULL)
    {       
        current = current->link;
    }

    current->link = malloc(sizeof(*current));//changed every malloc 
    if(current->link == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }

    printf("Podaj nr indeksu studenta: ");
    scanf("%d", current->link->nrindeksu);

    printf("Podaj imie studenta: ");
    fflush(stdin);
    scanf("%19[^\n]", buffer);
    current->link->imie=malloc(strlen(buffer) + 1);
    if(current->link->imie == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->imie, buffer);

    printf("Podaj nazwisko studenta: ");
    fflush(stdin);
    scanf("%19[^\n]", buffer);
    current->link->nazwisko=malloc(strlen(buffer) + 1);
    if(current->link->nazwisko == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->nazwisko, buffer);

    printf("Podaj wydzial studenta: ");
    fflush(stdin);
    scanf("%29[^\n]", buffer);
    current->link->wydzial=malloc(strlen(buffer) + 1);
    if(current->link->wydzial == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->wydzial, buffer);

    printf("Podaj kierunek studenta: ");
    fflush(stdin);
    scanf("%29[^\n]", buffer);
    current->link->kierunek=malloc(strlen(buffer) + 1);
    if(current->link->kierunek == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    strcpy(current->link->kierunek, buffer);

    current->link->link = NULL;
}

主:

int main(int argc, char *argv[]) 
{
    char c;
    head = init(head);
    if(head == NULL) {
        fprintf(stderr, "Malloc error"); 
        exit(0);
    }
    read(head);
    do{
        printf("Baza danych - wybierz opcje: [d]odaj, [w]yswietl, [u]sun, [k]oniec: ");
        scanf("%c", &c);
        if(c=='d')
        {
            system("cls");
            add_bottom(head);
        }
        if(c=='w')
        {
            system("cls");
            show(head);
        }
        if(c=='u')
        {
            system("cls");
            show(head);
            remove_by_id(&head);
            system("cls");
            show(head);
            printf("\n");
        }
        fflush(stdin);

    }while(c!='k');
    save(head);
    free(head);
    return 0;
}

函数init也只是

head = calloc(1,sizeof(data));

这样第一个节点始终为NULL,无法以其他方式创建或编辑第一个节点。

1 个答案:

答案 0 :(得分:1)

评论网站的代码有几个问题。仅举几例说明......

陈述(其中6个):

fscanf("%d", &nrindeksu);

...原样不允许您发布的代码进行编译,因为fscanf()需要FILE *作为第一个参数。

fscanf(fp, "%d", &nrindeksu);

函数strlen(nazwisko)(与帖子中所有其他类似的行一样)只返回缓冲区的长度,而不用计算NULL终止符,这将需要长度为接收缓冲区current->link->nazwisko

至少,你可以通过明确地为NULL终结符添加空间来解决这个问题:

current->link->nazwisko=(char*)malloc(sizeof(char) * strlen(nazwisko) + 1);
                        ^^^^^^^       ^^^^^^^^^^^^^^                  ^^^
                            not necessary                          necessary

因为sizeof(char)总是== 1,所以没有必要

清理:

current->link->nazwisko=malloc(strlen(nazwisko) + 1);

或者,正如评论中所建议的那样(如果POSIX是一个选项),您可以使用strdup()

char *tmp = 0;
tmp = strdup(nazwisko);
if(tmp)
{
     current->link->nazwisko = tmp;
     strcpy(current->link->nazwisko, nazwisko);
}

另一个小问题。以下是合法的,并确实分配了足够的空间:

current->link = malloc(sizeof(data));

但是这种形式:

current->link = malloc(sizeof(*current));

generally recommended ,因为在variable表达式中使用type而不是sizeof会更好。

另外一条评论 it is not necessary to cast the return of [m][c]alloc when using C

编辑(编辑你的代码,允许它编译和运行。[完成内存泄漏])

//does not include global declarations of struct data and variables
void read(data** head); //so object can be changed when passes as function argument
//             ^
void save(data* head);


int main(void)
{
    data *h = calloc(1, sizeof(data));
    read(&h);  //note, passing to data **, not data *
    save(h);

    return 0;
}

void save(data* head)
{
    FILE *fp;
    fp = fopen("text2.txt", "w");
    //data* current = head->link;

    fprintf(fp,"%d ",head->link->nrindeksu);
    fprintf(fp,"%s ",head->link->imie);
    fprintf(fp,"%s ",head->link->nazwisko);
    fprintf(fp,"%s ",head->link->wydzial);
    fprintf(fp,"%s\n",head->link->kierunek);
    fclose(fp);
}


void read(data **head)
{
    data *current = calloc(1, sizeof(*current));
    current = *head;
    int count;
    FILE *fp;
    fp = fopen(".\\text.txt", "r");

    {
        current->link = malloc(sizeof(data));
        if(current->link == NULL) {
            fprintf(stderr, "Malloc error"); 
            exit(0);
        }
        count = fscanf(fp,"%d %s %s %s %s", &nrindeksu, imie, nazwisko, wydzial, kierunek);
        if(count != 5)
        {
            free(current);
            return 
        }
        current->link->nrindeksu = nrindeksu;

        current->link->imie=(char*)malloc(sizeof(char) * strlen(imie)+1);
        if(current->link->imie == NULL) {
            fprintf(stderr, "Malloc error"); 
            exit(0);
        }
        strcpy(current->link->imie, imie);

        current->link->nazwisko=(char*)malloc(sizeof(char) * strlen(nazwisko)+1);
        if(current->link->nazwisko == NULL) {
            fprintf(stderr, "Malloc error"); 
            exit(0);
        }
        strcpy(current->link->nazwisko, nazwisko);

        current->link->wydzial=(char*)malloc(sizeof(char) * strlen(wydzial)+1);
        if(current->link->wydzial == NULL) {
            fprintf(stderr, "Malloc error"); 
            exit(0);
        }
        strcpy(current->link->wydzial, wydzial);

        current->link->kierunek=(char*)malloc(sizeof(char) * strlen(kierunek)+1);
        if(current->link->kierunek == NULL) {
            fprintf(stderr, "Malloc error");         
            exit(0);
        }
        strcpy(current->link->kierunek, kierunek);

        current->link->link = NULL; 
    }
    fclose(fp);
}

注意:上面的代码确实将数据读入节点,并且能够将节点数据写入文件,但是您必须清理内存。什么都没有被释放。我在上面的评论中发布的链接将有助于解决这个问题。

编辑2 (基于 this tutorial link 中的功能)

以下将文本文件(参见代码底部的示例文件)读入链表,然后将列表内容写入第二个文本文件,然后清理所有使用的内存。

typedef struct database
{
    int id;
    int nrindeksu;
    char *imie;
    char *nazwisko;
    char *wydzial;
    char *kierunek;
    struct database* link;
}data;

typedef struct {
    int id;
    int nrindeksu;
    char imie[20];
    char nazwisko[20];
    char wydzial[30];
    char kierunek[30];
}LINE;

LINE line;

void push(data** head_ref, LINE *line);
void store(data *d, FILE *p);
void cleanup(data *d);

int main(void)
{
    data *head = NULL;
    FILE *fp;
    fp = fopen(".\\text1.txt", "r");
    if(fp)
    {
        while(fscanf(fp,"%d %s %s %s %s", &line.nrindeksu, line.imie, line.nazwisko, line.wydzial, line.kierunek)== 5)
        {
            push(&head, &line); 
        }
        fclose(fp);
    }
    fp = fopen(".\\text2.txt", "w");
    if(fp)
    {
        store(head, fp);
        fclose(fp);
    }
    cleanup(head);
    return 0;
}

/// synonymous with your "read()" 
void push(data** head_ref, LINE *line)
{
    /* 1. allocate node */
    data *new_node = malloc(sizeof(*new_node));

    /* 2. put in the data  */
    new_node->id  = line->id;
    new_node->nrindeksu  = line->nrindeksu;
    new_node->imie = calloc(1, strlen(line->imie)+1);
    strcpy(new_node->imie, line->imie); 
    new_node->nazwisko = calloc(1, strlen(line->nazwisko)+1);
    strcpy(new_node->nazwisko, line->nazwisko); 
    new_node->wydzial = calloc(1, strlen(line->wydzial)+1);
    strcpy(new_node->wydzial, line->wydzial); 
    new_node->kierunek = calloc(1, strlen(line->kierunek)+1);
    strcpy(new_node->kierunek, line->kierunek); 

    /* 3. Make next of new node as head */
    new_node->link = (*head_ref);

    /* 4. move the head to point to the new node */
    (*head_ref)    = new_node;
}


void store(data *d, FILE *p)
{
    char line[260];
    while(d != NULL)
    {
        sprintf(line, "%d %s %s %s %s\n", d->nrindeksu, d->imie, d->nazwisko, d->wydzial, d->kierunek);
        fputs(line, p);
        d = d->link;
    }
}

void cleanup(data *d)
{
    data *tmp;

    while(d != NULL)
    {
        tmp = d;

        if(tmp->imie)   free(d->imie);
        if(tmp->nazwisko) free(d->nazwisko);
        if(tmp->wydzial)    free(d->wydzial);
        if(tmp->kierunek) free(d->kierunek);
        d = d->link;
        free(tmp);
    }
    free(d);
}

作为代码示例的输入引用的文本文件:

text1.txt:

0 string01 string02 string03 string04
1 string11 string12 string13 string14
2 string21 string22 string23 string24
3 string31 string32 string33 strin3g4
4 string41 string42 string43 string44
5 string51 string52 string53 string54
6 string61 string62 string63 string64
7 string71 string72 string73 string74
8 string81 string82 string83 string84
9 string91 string92 string93 string94