Possible Duplicate:
Parsing text in C
假设我已经写入了这种格式的文本文件:
key1/value1
key2/value2
akey/withavalue
anotherkey/withanothervalue
我有一个像这样的链表:
struct Node
{
char *key;
char *value;
struct Node *next;
};
保存值。我将如何读取 key1 和 value1?我正在考虑逐行放入缓冲区并使用 strtok(buffer, '/')。那行得通吗?还有什么其他方法可以工作,也许更快或更不容易出错?如果可以,请附上代码示例!
由于您的问题是优化内存碎片的一个很好的候选者,这里有一个实现,它使用一些简单的神秘魔法将所有字符串和结构本身分配到一 block 内存中。
当销毁节点时,您只需要对节点本身调用一次 free()
。
struct Node *list = NULL, **nextp = &list;
char buffer[1024];
while (fgets(buffer, sizeof buffer, file) != NULL) {
struct Node *node;
node = malloc(sizeof(struct Node) + strlen(buffer) + 1);
node->key = strtok(strcpy((char*)(node+1), buffer), "/\r\n");
node->value = strtok(NULL, "\r\n");
node->next = NULL;
*nextp = node;
nextp = &node->next;
}
说明:
有 20 条评论和 1 条无法解释的反对票,我认为代码需要一些解释,特别是关于所采用的技巧:
构建链表:
struct Node *list = NULL, **nextp = &list;
...
*nextp = node;
nextp = &node->next;
这是一个以正向顺序迭代创建链表的技巧,而不必对列表的头部进行特殊处理。它使用指向下一个节点的指针。首先nextp
指针指向链表头指针;在第一次迭代中,列表头通过这个指针到指针设置,然后 nextp
被移动到该节点的下一个指针。随后的迭代填充最后一个节点的下一个指针。
单一分配:
node = malloc(sizeof(struct Node) + strlen(buffer) + 1);
node->key = ... strcpy((char*)(node+1), buffer) ...
我们必须处理三个指针:节点本身、键字符串和值字符串。这通常需要三个单独的分配(malloc、calloc、strdup ...),因此需要单独的释放(免费)。相反,在这种情况下,树元素的空间在 sizeof(struct Node) + strlen(buffer) + 1
中求和并传递给单个 malloc
调用,它返回单个内存块。此内存块的开头分配给结构本身的 node
。附加内存 (strlen(buffer)+1) 紧跟在节点之后,它的地址是通过使用 node+1
的指针算法获得的。它用于复制从文件中读取的整个字符串(“key/value\n”)。
由于 malloc
对每个节点调用一次,因此进行一次分配。这意味着您不需要调用 free(node->key)
和 free(node->value)
。事实上,它根本行不通。只需一个 free(node)
就可以在一个 block 中释放结构和两个字符串。
行解析:
node->key = strtok(strcpy((char*)(node+1), buffer), "/\r\n");
node->value = strtok(NULL, "\r\n");
对 strtok
的第一次调用返回指向缓冲区本身开头的指针。它查找“/”(另外用于行尾标记)并用 NUL 字符断开字符串。因此,“key/value\n”在“key”和“value\n”之间被打破,中间有一个 NUL 字符,返回指向第一个的指针并存储在 node->key
.对 strtok
的第二次调用将处理剩余的“value\n”,去除行尾标记并返回指向“value”的指针,该指针存储在 node->值
。
我希望这能解决所有关于上述解决方案的问题……对于一个封闭的问题来说太多了。 The complete test code is here .