链表遍历跳过第一个元素

Linked list traversal skips first element

我有一个 C 程序可以在链表的开头插入元素,但是当我尝试打印元素时,它总是跳过第一个元素。有人可以指出我在我的程序中做错了什么吗?

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


void PrintElements();
void InsertElement(int x);

struct node
{
    int data;
    struct node* next;
};

struct node* HEAD;
struct node* temp;
struct node* temp1;


void PrintElements()
{
    temp1=HEAD;
    while(temp1->next!=NULL)
    {
        printf("\n\r Data %d\n\r",temp1->data);
        printf("\n\r Address %x\n\r",temp1->next);
        temp1=temp1->next;
    }
}

void InsertElement(int x)
{
    struct node* temp=(struct node*)malloc(sizeof(struct node));
    temp->data=x;
    temp->next=HEAD;
    HEAD=temp;

}

int main()
{

    int i, x;
    int n;   //n stores the number of elements to be added to the linked list
    HEAD=NULL; //Assigning HEAD to null when there are no elements in the list
    printf("Enter the number of elements\n");
    scanf("%d",&n);
    for(i=0;i<n;i++)
    {
        printf("\n\rEnter the number");
        scanf("%d",&x);
        InsertElement(x);
        PrintElements();
    }

    return 0;
}

当我更改以下行时

while(temp1->next!=NULL)

while(temp1!=NULL)

程序运行正常,但我仍然不明白为什么。

while(temp1->next!=NULL)

将此更改为

while(temp1 != NULL)

它应该可以正常工作。

原因:我认为它不会打印您输入的第一个元素。

示例:输入:1 2 3

链接列表形成为:3 -> 2 -> 1 -> NULL 使用的符号:每个数字都是data,箭头表示指针next

然后当你开始循环时,对于每次迭代:

  • temp1指向3

  • 的地址
  • temp1 -> next != NULL(正确,因为 temp1 -> next 指向 2 的地址)

  • 打印 3temp1 现在指向 2

  • 的地址
  • temp1 -> next != NULL(正确,因为 temp1 -> next 指向 1 的地址)

  • 打印 2temp1 现在指向 1

  • 的地址
  • temp1 -> next != NULL 这变成了 False 因为 temp1 指向 1 的地址并且 temp1 -> next 是无效的。

所以我们永远不会进入循环来打印 1

所以正确的做法是使用 temp1 != NULL 因为这将消除上述错误。

您描述的问题可以通过将 PrintElements() 函数中的控制表达式更改为 temp1 != NULL 来解决。这样,如果 temp1 指向一个节点,则打印 datanext 字段,并继续循环直到没有更多节点。当遍历一个链表时,当你查看下一个节点来决定你将对当前节点做什么时,通常会让人感到困惑。但是这段代码还有其他问题。

首先,在main()中声明struct指针并将它们传递给函数会更好,而不是将它们声明为全局变量。您应该尽可能检查您调用的函数的 return 值。您应该检查 scanf() 以确保输入符合预期;这也提供了一种控制输入循环的方法,用户无需在输入数据之前明确输入计数。您还应该通过调用 malloc() 检查值 return 以捕获分配错误。当在下一行取消引用 temp 时,代码中的此类分配错误会导致未定义的行为。

您应该 free 所有内存分配,每次调用 malloc() 一个 free()。当您在函数 PrintElements() 中打印列表中 next 节点的地址时,您调用了未定义的行为。要打印指针的值,您应该使用 %p 格式说明符,并且必须将指针转换为 (void *)。终于不用#include <malloc.h>了; stdlib.h 满足您的需求。

这是您的代码的修改版本,它实现了建议的更改。请注意,在分配错误的情况下,一条消息将打印到 stderr,程序将打印到 exits。对 malloc() 的调用已被简化:没有理由在 C 中强制转换 malloc() 的结果,最好使用分配内存的指针的名称来代替给 malloc() 的参数中的显式类型。 new_node 被 returned 到调用函数,其中指向列表 head 的指针被重新分配以指向 new_node.

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

struct node
{
    int data;
    struct node* next;
};

void print_elements(struct node *start);
struct node * insert_element(int x, struct node *head);


int main(void)
{
    struct node* head = NULL;
    struct node* curr = NULL;
    int x;

    /* Read data into linked list */
    printf("Enter the first integer (q to quit): ");
    while (scanf("%d", &x) == 1) {
        head = insert_element(x, head);
        print_elements(head);
        printf("Enter another integer (q to quit): ");
    }

    /* Free allocated memory */
    while (head) {
        curr = head;
        head = curr->next;
        free(curr);
    }

    return 0;
}

void print_elements(struct node *curr)
{
    while(curr) {
        printf("   Data: %d\n",curr->data);
        printf("Address: %p\n\n",(void *) curr->next);
        curr = curr->next;
    }
}

struct node * insert_element(int x, struct node *head)
{
    struct node *new_node = malloc(sizeof(*new_node));

    if (new_node == NULL) {
        fprintf(stderr, "Allocation error in function insert_element()\n");
        exit(EXIT_FAILURE);
    }

    new_node->data = x;
    new_node->next = head;

    return new_node;
}