C 列表头:如果从第二个元素开始解析,则获取垃圾

C 列表头:如果从第二个元素开始解析,则获取垃圾,c,linux,list,linked-list,garbage,C,Linux,List,Linked List,Garbage,我在我的C项目列表头结构中使用来定义一个链接列表。在某些情况下,我需要从第二个元素解析列表,但在本例中,我会得到一个额外的元素和一个垃圾值。我试着在我的电脑里用一个小程序来模拟同样的场景。我也有同样的问题: #include<stdio.h> #include<stdlib.h> #include "list.h" struct struct_report{ struct list_head list; char *report; };

我在我的C项目列表头结构中使用来定义一个链接列表。在某些情况下,我需要从第二个元素解析列表,但在本例中,我会得到一个额外的元素和一个垃圾值。我试着在我的电脑里用一个小程序来模拟同样的场景。我也有同样的问题:

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

struct struct_report{
        struct list_head list;
        char *report;
};


//Add an element to the linked list
void add_report_to_list(struct list_head *reports, char *report) {
        struct struct_report *report_strct;
        report_strct = calloc(1, sizeof(struct struct_report));
        list_add_tail(&report_strct->list, reports);
        report_strct->report= strdup(report);
}

int main() {
        struct struct_report *retreport;
        LIST_HEAD(reports); //instantiate a struct list_head instance
        add_report_to_list(&reports, "elt1");
        add_report_to_list(&reports, "elt2");
        add_report_to_list(&reports, "elt3");
        add_report_to_list(&reports, "elt4");
        list_for_each_entry(retreport, &reports, list){
                printf("============> no next retreport: %s\n", retreport->report);
        }
        printf("\n");
        list_for_each_entry(retreport, reports.next, list){
                printf("============> Next retreport: %s\n", retreport->report);
        }
        return 1;
} 
很明显,在我从第一个元素开始正常解析的情况下,我没有任何问题。但是如果我从列表中的第二个元素开始,我会得到一个额外的元素,它的值很奇怪,比如垃圾


有什么解释为什么我会得到一个额外的元素吗?以及如何将其修复为解析到elt4?

如果从列表的第一个元素开始(而不是从头部开始),则每个条目的
列表将停止在同一个列表对象中,因为它是循环列表

因此,每个条目()的
列表将通过头部。并且头部没有连接到条目。所以当你试图引用头部列表中的条目时,你会得到垃圾


解决方案:从列表的开头开始循环,跳过第一个元素。列表实现实际上创建了一个环。列表头是一个虚拟元素,它将
next
指向第一个元素,将
prev
指向最后一个元素。(最初两者都指向列表头本身。)在尾部添加元素实际上是在“列表头之前”添加元素。当在这个环上循环时,头部由一个指向它的单独指针标记。没有其他方法将其与列表中的其他元素区分开来

list\u for\u中的
for
循环每个\u条目
都与
head
指针进行比较,作为循环条件,因此当它再次到达作为列表头提供的对象时,它将停止

/**
 * list_for_each_entry  -   iterate over list of given type
 * @pos:    the type * to use as a loop cursor.
 * @head:   the head for your list.
 * @member: the name of the list_head within the struct.
 */
#define list_for_each_entry(pos, head, member)              \
    for (pos = list_first_entry(head, typeof(*pos), member);    \
         &pos->member != (head);                    \
         pos = list_next_entry(pos, member))
list\u first\u entry
list\u next\u entry
使用宏
container\u of
返回指向用户定义结构的指针,该结构应包含
struct list\u head

如果将
reports.next
而不是
reports
传递到
列出每个条目的列表()
,它将把它作为虚拟列表头元素,并将环中的所有其他元素视为真实列表条目

您的代码为尾部元素后面的元素打印垃圾,因为这是一个纯
struct list\u head
,它未嵌入
struct struct\u报表
,因此宏
list\u next\u条目
返回指向
main()中
struct list\u head报表
之前的内存指针
这是未定义的行为

如果您的程序没有崩溃,如果您通过例如
reports.next->next
,您将在
elt4
之后得到相同的垃圾。在这种情况下,我希望输出如下:

=============>下一次重新报告:elt3
==========>下一次更新报告:elt4
==========>下一次报告:
==========>下一次更新报告:elt1

而相同的类型—
列表头
用于以下两种:

  • 名单头
  • 列出元素
它们是不可互换的。如果某个宏希望列表头作为参数,则需要提供指向列表头的指针,而不是指向列表元素的指针

list\u for\u每个\u条目
接受指向列表头的指针作为第二个参数,因此不应将指针传递给元素

对于在列表上迭代时跳过第一个元素,宏

  • 列出来自的每个条目的列表
  • 列出每个条目的列表\u继续
可以使用

这两个宏对每个条目采用与列表相同的参数,但它们考虑了光标的初始值(第一个参数):

  • list\u for\u来自
    的每个条目在光标指向的元素处开始迭代
  • list\u for\u每个条目继续
    在光标指向的元素之后开始迭代
因此,在列表上迭代并跳过第一个元素可能如下所示:

// Set cursor to the first element in the list
retreport = list_first_entry(reports, typeof(*retreport), list);
// Iterate starting after the cursor
list_for_each_entry_continue(retreport, reports, list){
    printf("============> Next retreport: %s\n", retreport->report);
}

什么是
列表头(报告)
.next
字段未在任何位置定义。什么是每个条目的
列表()?每个条目(…){printf…}的部分“列表”看起来很奇怪。请您的问题添加此信息,而不是添加注释。请为每个条目显示
list\u的定义
function和
struct list\u head
structure@Bodo负责人名单(报告);实例化结构列表\u head rports变量。接下来是列表头中的一个属性:struct list头{struct list头*next;struct list头*prev;}@RishikeshRaje@KallelOmar请回答您的问题,并在问题中添加所有信息,而不是写评论。
// Set cursor to the first element in the list
retreport = list_first_entry(reports, typeof(*retreport), list);
// Iterate starting after the cursor
list_for_each_entry_continue(retreport, reports, list){
    printf("============> Next retreport: %s\n", retreport->report);
}