如何更新指针以创建列表

How to update the pointer to create a list

我正在尝试学习 C,但在使用指针创建列表时遇到了一些问题。

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

typedef struct _tDateTimeNode
{
    struct _tDateTimeNode *next;
} tDateTimeNode;

typedef struct _ApiData
{
    tDateTimeNode *timeNodeList;
} tApiData;

void dateTimeNode_insert(tDateTimeNode **_list)
{
    bool found = false;
    tDateTimeNode *list = (*_list);
    while (list != NULL && !found)
    {
        printf("This code never runs!\n");
        list = list->next;
    }

    if (list == NULL)
    {
        printf("This if is always executed!\n");
        list = (tDateTimeNode *)malloc(sizeof(tDateTimeNode));
    }

    if (*_list == NULL)
    {
        printf("This if is also executed!\n");
        _list = &list;
    }
}

int main()
{
    tApiData data;
    data.timeNodeList = NULL;

    tDateTimeNode **timeNode = &(data.timeNodeList);
    dateTimeNode_insert(timeNode);
    dateTimeNode_insert(timeNode);
    dateTimeNode_insert(timeNode);
    dateTimeNode_insert(timeNode);
}

gcc -o t test.c && ./t 编译问题后,我得到以下输出:

This if is always executed!
This if is also executed!
This if is always executed!
This if is also executed!
This if is always executed!
This if is also executed!
This if is always executed!
This if is also executed!

如你所见,最后两个if总是被执行。但是 while 永远不会 运行。 while 块在函数第一次执行后应该是 运行,因为据推测我已经添加了一个新元素。我想我没有正确更新 _list 的值,但我已经 运行 没有可供尝试的选项。知道如何解决吗?

你写的方式有很多问题

void dateTimeNode_insert(tDateTimeNode **_list)
{
    bool found = false;
    tDateTimeNode *list = (*_list);
    while (list != NULL && !found)
    {
        printf("This code never runs!\n");
        list = list->next;
    }

    if (list == NULL)
    {
        printf("This if is always executed!\n");
        list = (tDateTimeNode *)malloc(sizeof(tDateTimeNode));
    }

    if (*_list == NULL)
    {
        printf("This if is also executed!\n");
        _list = &list;
    }
}

请注意,found 始终为假,可以删除,因为 !false 始终为真,从未更改

_listtDateTimeNode** 所以它应该在 *_list

中引入列表头部的地址

当你写作时

   _list = &list;

对列表的唯一引用永远消失了。也许你打算写 *_list = list; 以便在插入第一个元素时保存列表的新头

命名也很混乱:list, _list.

请注意,列表是一个容器。您不应将列表与数据混合。您今天的列表是 DateTimeNode,但它仍然只是一个列表。在你的下一个程序中可能是一本书,播放列表中的一首歌曲,所有经典列表练习。如果代码更通用,那么创建列表就很简单了。各种榜单

示例:一个列表和一个 DateTimeNode

我将post一个使用你的代码的例子,但是使用我上面写的

想象一下控制队列的门票列表。每个进入的客户都会得到一张带有序列号和时间戳的票,格式为 yyyy-mm-dd hh:mm:ss。客户在队列末尾进入。

这是一张可能的票

typedef struct
{
    char*    ts;   // time stamp
    unsigned USN;  // sequence number

}   Ticket;

这些门票的列表可能 Node

typedef struct _Node
{
    Ticket*       tk;
    struct _Node* next;

}   Node;

正如预期的那样,列表中的每个节点都指向一张票。列表只是一个容器。

列表本身可以是

typedef struct
{
    Node*    head;  // first node if any
    unsigned size;  // actual Node count

}   List;

这样比较好理解:一个列表有节点,每个节点指向一些数据。数据已编号,便于测试。并有一个时间戳。当然,计算机很快,时间戳分辨率是秒,所以我们需要数千个节点才能看到不同的时间戳...

一组最小的函数

List* create();
List* destroy(List*);
int   insert(Ticket*, List*);
int   show(List*, const char*);

show() 接受消息的可选字符串和 destroy() returns NULL 作为礼貌,因此我们可以在销毁的同一行中使列表指针无效列表。

一个测试

int main(void)
{
    Ticket ticket;
    List*  one = create();
    for (int i = 1; i <= 10; i += 1)
    {
        ticket.USN = i;
        ticket.ts  = get_ts();
        insert(&ticket, one);
    };
    show(one, "After 10 tickets inserted...\n");
    one = destroy(one);  // destroys list, invalidate pointer
    return 0;
}

该代码创建了一个包含 10 张门票的列表,显示它们并删除该列表。

输出

After 10 tickets inserted...

   List has 10 elements:

    1  2021-11-15 14:12:06
    2  2021-11-15 14:12:06
    3  2021-11-15 14:12:06
    4  2021-11-15 14:12:06
    5  2021-11-15 14:12:06
    6  2021-11-15 14:12:06
    7  2021-11-15 14:12:06
    8  2021-11-15 14:12:06
    9  2021-11-15 14:12:06
   10  2021-11-15 14:12:06

示例代码

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

typedef struct
{
    char*    ts;   // time stamp
    unsigned USN;  // sequence number
} Ticket;

typedef struct _Node
{
    Ticket*       tk;
    struct _Node* next;

} Node;

typedef struct
{
    Node*    head;  // first node if any
    unsigned size;  // actual Node count
} List;

// List stuff
List* create();
List* destroy(List*);
int   insert(Ticket*, List*);
int   show(List*, const char*);

// helpers
char* get_ts();  // get time in format "yyyy-mm-dd hh:mm:ss"

int main(void)
{
    Ticket ticket;
    List*  one = create();
    for (int i = 1; i <= 10; i += 1)
    {
        ticket.USN = i;
        ticket.ts  = get_ts();
        insert(&ticket, one);
    };
    show(one, "After 10 tickets inserted...\n");
    one = destroy(one);  // destroys list, invalidate pointer
    return 0;
};  // main()



List* create()
{
    List* list = (List*)malloc(sizeof(List));
    if (list == NULL) return NULL;
    list->head = NULL;
    list->size = 0;
    return list;
}

List* destroy(List* list)
{
    if (list == NULL) return NULL;
    Node* tmp = list->head->next;
    Node* p   = list->head;
    for (unsigned i = 0; i < list->size - 1; i += 1)
    {  // delete ticket and node at p
        free(p->tk);
        free(p);
        p   = tmp;
        tmp = p->next;
    }
    // p now points to last
    free(p->tk);
    free(p);
    free(list);  // the List itself
    return NULL;
}

int insert(Ticket* tk, List* L)
{  // insert tk into list L, at the end
    if (L == NULL) return -1;
    if (tk == NULL) return -2;
    // get a new ticket
    Ticket* nt = (Ticket*)malloc(sizeof(Ticket));
    *nt        = *tk;
    // now creates a new Node for this ticket
    Node* nnd = (Node*)malloc(sizeof(Node));
    nnd->next = NULL;
    nnd->tk   = nt;

    // list is empty?
    if (L->size == 0)
    {
        L->head = nnd;
        L->size = 1;
        return 0;  // ok
    }

    // search List end
    Node* p = L->head;
    while (p->next != NULL) p = p->next;
    p->next = nnd;  // last now points to new
    L->size += 1;
    return 0;  // ok
}

int show(List* L, const char* msg)
{
    if (msg != NULL) printf("\n%s\n", msg);
    if (L == NULL)
    {
        printf("There is no list: nothing to display");
        return -1;
    }
    printf("   List has %d elements:\n\n", L->size);
    Node* p = L->head;
    for (unsigned i = 0; i < L->size; i += 1)
    {
        printf("%5u  %s\n", p->tk->USN, p->tk->ts);
        p = p->next;
    }
    printf("\n\n");
    return L->size;
}

char* get_ts()
{  // return string in format: "yyyy-mm-dd hh:mm:ss"
    time_t moment;
    time(&moment);  // get time
    // convert time to struct tm
    struct tm* t_info     = localtime(&moment);
    char*      time_stamp = (char*)malloc(20);
    // format time stamp and return to caller
    strftime(time_stamp, 20, "%Y-%m-%d %H:%M:%S", t_info);
    return time_stamp;
}