首页 > 解决方案 > 如何更新指针以创建列表

问题描述

我正在尝试学习 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正确更新 的值,但我已经没有办法尝试了。知道如何解决吗?

标签: clinked-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

我将使用您的代码发布一个示例,但使用我上面写的

想象一个用于控制队列的工单列表。进入的每个客户都会收到一张带有序列号和格式时间戳的票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()返回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;
}

推荐阅读