簡體   English   中英

C:fgets用於構建char *鏈接列表的用法

[英]C: fgets usage for building a linked list of char*

我使用fgets()不正確嗎?

我正在嘗試構建一個字符串鏈接列表( char * ),將每行添加到LL的末尾。 我正在從文件中讀取這些行,但是由於某些原因,僅當在while循環內使用fgets()時,每一行都會被當前正在處理的行覆蓋,但是add函數似乎可以正確接收每一行。

如果我在main()單獨添加行,則不會有問題。

這是一個示例輸入文件:

input.txt:

This life, which had been the
tomb of his virtue and of his
honour, is but a walking
shadow; a poor player, that
struts and frets his hour upon
the stage, and then is heard
no more: it is a tale told by an
idiot, full of sound and fury,
signifying nothing.
    --William Shakespeare

編碼:

#include <stdio.h> //printf, fopen
#include <stdlib.h> //exit, EXIT_FAILURE
#include <string.h> //strlen

struct node {
    char *line;
    struct node *next;
};

void print(struct node *node);

void add(struct node **head, char *newLine) {
    //printf("%s", newLine);

    struct node *new_node = (struct node *)malloc(sizeof(struct node));
    struct node *curr = *head;

    new_node->line = newLine;
    new_node->next = NULL;

    if (*head == NULL) {
        *head = new_node;
    } else {
        while (curr->next != NULL) {
            curr = curr->next;
        }
        curr->next = new_node;
    }
    print(*head);
}

void print(struct node *node) {
    printf("\n");

    while (node != NULL) {
        printf("%s\n", node->line);
        node = node->next;
    }
}

int main(int argc, char *argv[16]) {
    char newLine[81];
    struct node *head = NULL;
    FILE *fp = fopen(argv[1], "r");

    if (fp == NULL) {
        printf("ERROR: file open failed");
        exit(EXIT_FAILURE);
    }

    while (fgets(newLine, 81, fp)) {
        add(&head, newLine);
    }

    add(&head, "why");
    add(&head, "does");
    add(&head, "this");
    add(&head, "work??");

    fclose(fp);

    print(head);

    return 0;
}

有人可以告訴我發生了什么事嗎? 我把頭撞在牆上已經太久了。 我已經嘗試使用一些注釋的打印語句,但調試失敗。

您的問題出在add()方法中。 它一直向列表添加相同的緩沖區指針。 您需要將列表中的緩沖區復制到新分配的空間,即。 也需要分配node-> line,並將newLine復制到其中。 不要忘記malloc(strlen(newLine)+1)。

您有一個緩沖區來存儲輸入。 在添加節點時,您將指針傳遞到該單個緩沖區的第一個元素。 這意味着所有節點中的字符串指針將指向相同的單個緩沖區。 最后將包含您讀取的最后一個字符串。

最簡單的解決方案是使節點結構中的字符串成為數組,然后將字符串復制到其中。

另一種解決方案是為字符串動態分配內存(記住終止的空字符),然后再次將字符串復制到該內存中。

使用常量字符串文字時的區別在於,每個字符串將是一個不同的數組。

您必須為每行分配內存。 按照當前的編碼,所有節點都指向main()的本地數組,每次調用fgets()都會覆蓋其內容。

還要注意,添加到列表中的每一行都包含一個終止換行符,您可能應該在調用之前將其刪除。

這是更正的版本:

#include <stdio.h>  // printf, fopen
#include <stdlib.h> // exit, EXIT_FAILURE
#include <string.h> // strlen, strdup

struct node {
    char *line;
    struct node *next;
};

void print(struct node *node);

void add(struct node **head, char *newLine) {
    //printf("%s", newLine);

    struct node *new_node = malloc(sizeof(struct node));
    struct node *curr = *head;

    new_node->line = strdup(newLine);
    new_node->next = NULL;

    if (*head == NULL) {
        *head = new_node;
        return;
    }

    while (curr->next != NULL) {
        curr = curr->next;
    }

    curr->next = new_node;
    print(*head);
}

void print(const struct node *node) {
    printf("\n");

    while (node != NULL) {
        printf("%s\n", node->line);
        node = node->next;
    }
}

int main(int argc, char *argv[16]) {
    char newLine[81];
    struct node *head = NULL;
    FILE *fp = fopen(argv[1], "r");

    if (fp == NULL) {
        printf("ERROR: file open failed");
        exit(EXIT_FAILURE);
    }

    while (fgets(newLine, sizeof newLine, fp)) {
        newLine[strcspn(newLine, "\n")] = '\0'; // strip the newline if present
        add(&head, newLine);
    }

    add(&head, "why");
    add(&head, "does");
    add(&head, "this");
    add(&head, "work??");

    fclose(fp);

    print(head);

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM