c - 如何更新指针以创建列表
问题描述
我正在尝试学习 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
始终为真,永不更改
_list
是tDateTimeNode**
这样的,它应该带入列表头的地址*_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;
}
推荐阅读
- javascript - 您可以在 .filter() 中使用 if/else / 还有其他方法吗?
- android - Android UI:我可以使用 Material Design 制作类似游戏的 UI
- git - 自动添加任务相关工作的链接?
- firebase - Firebase 托管部署缺少文件
- python - Python:按列表切片数据框会返回比预期更长的列表
- javascript - 如何在 Angular 中将 ngStyle 设置为默认值
- android - 当内存清除时,viewpager 中的片段不会被破坏
- content-management-system - 如何在 Craft CMS 中建立新频道?
- python - 如何进行远程数据访问(来自股票市场)并将它们组合成一个数据框?
- python - 在 TensorFlow 中设计一个表示网络的类