【问题标题】:Linked list traversal skips first element链表遍历跳过第一个元素
【发布时间】:2016-12-31 02:48:45
【问题描述】:

我有一个 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)

程序正常运行,但我仍然无法理解原因。

【问题讨论】:

  • 因为在一个中检查指向一个元素的指针,而在另一个中检查指向 next 元素的指针,即您以不同的条件终止。尝试使用更长的列表,您会看到会发生什么。 PS:全局变量是邪恶的。
  • 如果你检查while(temp1-&gt;next!=NULL),那么你总是会跳过第一个元素。
  • 更改后第二个问题的答案是:插入第一个节点时会发生什么?此时HEAD 的价值是多少? (提示:NULL)。由于您始终在列表的开头插入,因此您的 first 节点将始终是打印的 last 节点。打印 last 节点时,node-&gt;next 的值是多少? (它是NULL)。如果在到达最后一个节点(第一个值)temp1-&gt;next == NULL 时使用while(temp1-&gt;next!=NULL),则循环终止,最后一个节点(第一个值)不打印。进行建议的更改可以消除该问题。

标签: c data-structures linked-list singly-linked-list


【解决方案1】:

while(temp1-&gt;next!=NULL)

把这个改成

while(temp1 != NULL)

它应该可以正常工作。

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

示例:输入:1 2 3

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

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

  • temp1指向3的地址

  • temp1 -&gt; next != NULL(真为temp1 -&gt; next指向2的地址)

  • 现在打印3temp1 指向2 的地址

  • temp1 -&gt; next != NULL(真为temp1 -&gt; next指向1的地址)

  • 打印2temp1 现在指向1 的地址

  • temp1 -&gt; next != NULL 这变为 False,因为 temp1 指向 1 的地址,而 temp1 -&gt; next 为 NULL。

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

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

【讨论】:

  • 很好的解释!!你来自哪个 JNV??
  • 什么是 JNV,我不知道。
【解决方案2】:

您描述的问题可以通过将PrintElements() 函数中的控制表达式更改为temp1 != NULL 来解决。这样,如果temp1 指向一个节点,则打印datanext 字段,并且循环继续,直到没有更多节点为止。当迭代一个链表时,当你查看下一个节点来决定你将如何处理当前节点时,它通常看起来很混乱。但是这段代码还有其他问题。

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

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

这是您的代码的修改版本,它实现了建议的更改。请注意,如果发生分配错误,则会向stderr 和程序exits 打印一条消息。对malloc() 的调用已被简化:没有理由在C 中强制转换malloc() 的结果,最好使用分配内存的指针的名称来代替显式类型给malloc() 的参数。 new_node 返回给调用函数,其中指向列表中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;
}

【讨论】:

    猜你喜欢
    • 2011-04-04
    • 1970-01-01
    • 1970-01-01
    • 2019-03-07
    • 2011-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多