【问题标题】:Error traversing and printing singly linked list in C在C中遍历和打印单链表时出错
【发布时间】:2019-03-04 23:14:48
【问题描述】:

Lost Noob,试图逐行读取文件,即“一”、“二”、“三”并将其添加到有序链表(我相信我已经在工作)。但是,我无法弄清楚我的 traverse_and_print 列表函数的语法/逻辑(并且不明白 *(go to here and get value)、&(get address) 和 -> 很好。我的主要工作代码是repl.it https://repl.it/@MichaelB4/DeafeningTreasuredMathematics

// A complete working C program to demonstrate all insertion methods 
// from https://www.geeksforgeeks.org/linked-list-set-2- inserting-a-node/

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

// Create structure for a linked list node 

struct Node 
{ 
    const char *data; 
    struct Node *next; 
}; 

struct Node *head;

// Given a reference (pointer to pointer) to the head of a list and a char*, appends a new node at the end
void append(struct Node** head_ref, const char *new_data) 
{ 
    // 1. allocate node
    struct Node* new_node = (struct Node*) malloc(sizeof(struct Node)); 

    struct Node *last = *head_ref;  // used in step 5

    // 2. put in the data
    new_node-> data  = new_data; 

    // 3. Set new_node.next to Null, as it will be inserted at tail of list 
    new_node -> next = NULL;

    // 4. If the Linked List is empty, then make the new node as head
    if (*head_ref == NULL) 
    { 
        *head_ref = new_node;
        //printf("head\n");
        printf("%s", new_node -> data); 
        return; 
    } 

    // 5. Else traverse till the last node

    while (last -> next != NULL)  
        last = last -> next;
        printf("%s", new_node -> data); 

    // 6. Change the next of last node, have last node point to one just inserted, the new node at the end of the list, tail 

    last -> next = new_node; 
    return; 
} 

void traverse_and_printList(head){
    struct Node* current = (struct Node*) malloc(sizeof(struct Node));
    current = head;
    while (head -> next != NULL)
        printf("%s", current -> data);
        current -> next = current;

}

/* Driver program to test above functions*/
int main() 
{ 
    // set up a file point to File to be opened
    FILE* fp;
    // holds contents of each line/word 
    char buffer[255]; 

    fp = fopen("words.txt", "r");
    if (fp == NULL)
    {
        fprintf(stderr, "Could not open infile"); 
        return 2;
    }

    /* create an empty node */
    struct Node* head = NULL; 

    int counter = 0;
    char *head_value[255]; 

    while(fgets(buffer, 255, (FILE*) fp)){
        //printf("%s", buffer);
        append(&head, buffer);
    }

    fclose(fp);
    traverse_and_printList(head);
    printf("\n");
    return 0; 
}

【问题讨论】:

    标签: c pointers printing linked-list


    【解决方案1】:

    您对current 指针的用途感到困惑。

    首先,您不需要为它分配内存。你不是想存储任何新的东西。 current 指针只是一个值,可帮助您移动列表中的项目。

    其次,您不应该修改列表的数据。 current-&gt;next = current 这行是假的。它修改列表创建一个循环。不好。

    第三,您的缩进表明您的 while 循环包含两个单独的语句,但它们周围没有块范围( { ... })。因此,只有第一条语句将成为循环的一部分。

    最后,关于风格的一点。请不要在-&gt; 周围放置空格。虽然编译器并不关心,但它会让你的代码很难被人类阅读。

    正确遍历你的列表就这么简单:

    for(struct Node* current = head; current != NULL; current = current->next)
    {
        printf("%s\n", current->data);
    }
    

    【讨论】:

    • 感谢 Paddy,但是当我在 main 函数的末尾添加该代码时,我最终得到了 foxfoxfoxfoxfoxfox
    • 这是为了替换您的 traverse_and_printList 函数的内容。如果您仍在调用该函数,请注意我对您现有代码如何在列表中创建循环的评论。
    • 对不起,我只是没有关注你。当我用你的建议替换我的代码时,我得到了“指向整数转换的不兼容指针”。 repl.it/@MichaelB4/DeafeningTreasuredMathematics
    • 您错误地定义了您的函数。通过不为head 参数指定类型,C 将默认采用int。将定义更改为void traverse_and_printList(struct Node* head) { ... }。您还有其他问题超出了您的问题范围。我不会在 cmets 中进行实时调试会话。至少,您需要学习如何复制字符串,因为现在您正在存储指向行缓冲区的指针。这意味着列表中的所有项目看起来都是相同的。这里有成千上万的问题,或者打开一本关于 C 的书。
    【解决方案2】:

    在我看来,您的“遍历和打印”功能有问题。你有:

    void traverse_and_printList(head){
        struct Node* current = (struct Node*) malloc(sizeof(struct Node));
        current = head;
        while (head -> next != NULL)
            printf("%s", current -> data);
            current -> next = current;
    
    }
    
    • 现代的 GCC 会警告您有关误导性缩进 - current-&gt;next = current; 行不受 while 循环控制(C 不是 Python!)。
    • 在循环中测试head-&gt;current 是错误的;您测试的应该是 current-&gt;head
    • 作为一种风格,点 . 和箭头 -&gt; 运算符绑定非常紧密,它们的两侧不应有空格。
    • 打印函数不应进行任何节点分配。

    因为您在函数定义行中省略了类型信息,head 被解释为int(使用准标准 C 的规则,C90 必须允许该规则才能有机会被接受) — 而且您必须使用未配置为抱怨 C99 之前的代码的编译器进行编译。这是21世纪;你不应该使用 30 年前的符号。弄清楚如何至少指定 C99 以及如何获得警告。使用 GCC,这将类似于 -std=c99 -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes;我也使用-Wextra,而且通常还有更多选择。

    void traverse_and_printList(struct Node *head)
    {
        struct Node *current = head;
        while (current->next != NULL)
        {
            printf("%s", current->data);
            current->next = current;
        }
    }
    

    特别是在调试时,我可能会使用类似于以下的格式,用标记包围数据(我选择了[[]],但选择权在你),因为它可以揭示问题(例如不需要的'\r' 在行尾):

    printf("[[%s]]\n", current->data);
    

    我也可以打印指针:

    printf("C %p N %p [[%s]]\n", (void *)current, (void *)current->next, current->data);
    

    您可能更喜欢更冗长的符号(Current 而不是 CNext 而不是 N),但紧凑性也有其优点。

    警告:修改后的代码尚未靠近编译器。

    【讨论】:

    • 谢谢。我可以看到我在追加时还有另一个错误,因为传递的最后一个值是 head,当传递给 traverse_and_printList 函数时,它将有一个空指针。我仍然无法很好地操作节点和指针,所以希望我能得到一些关于 codementor 的快速辅导,以了解我所缺少的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多