Moh*_*nde 3 c file-io token text-files
可能重复:
在C中解析文本
假设我已经以这种格式写入文本文件:
key1/value1
key2/value2
akey/withavalue
anotherkey/withanothervalue
Run Code Online (Sandbox Code Playgroud)
我有一个链表,如:
struct Node
{
char *key;
char *value;
struct Node *next;
};
Run Code Online (Sandbox Code Playgroud)
保持价值观.我如何读取key1和value1?我想在缓冲区中逐行放置并使用strtok(缓冲区,'/').那会有用吗?还有哪些其他方法可以工作,可能更快或更不容易出错?如果可以,请附上代码示例!
由于您的问题非常适合优化内存碎片,因此这里有一个实现,它使用一些简单的奥术魔法将所有字符串和结构本身分配到单个内存中.
在销毁节点时,您只需要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;
}
Run Code Online (Sandbox Code Playgroud)
有20个评论和一个无法解释的downvote,我认为代码需要一些解释,特别是关于所用的技巧:
建立链表:
struct Node *list = NULL, **nextp = &list;
...
*nextp = node;
nextp = &node->next;
Run Code Online (Sandbox Code Playgroud)
这是以向前顺序迭代地创建链表的技巧,而不必特殊情况下列表的头部.它使用指向下一个节点的指针.首先,nextp指针指向列表头指针; 在第一次迭代中,列表头通过此指针指向设置,然后nextp移动到该节点的下一个指针.后续迭代填充最后一个节点的下一个指针.
单一分配:
node = malloc(sizeof(struct Node) + strlen(buffer) + 1);
node->key = ... strcpy((char*)(node+1), buffer) ...
Run Code Online (Sandbox Code Playgroud)
我们必须处理三个指针:节点本身,键字符串和值字符串.这通常需要三个单独的分配(malloc,calloc,strdup ......),因此需要免费的单独版本(免费).相反,在这种情况下,树元素的空间被求和sizeof(struct Node) + strlen(buffer) + 1并传递给单个malloc调用,该调用返回单个内存块.这块内存的开头被分配给node结构本身.附加内存(strlen(缓冲区)+1)紧跟在节点之后,它的地址是使用指针算法获得的node+1.它用于复制从文件中读取的整个字符串("key/value \n").
由于malloc每个节点被称为单个时间,因此进行单个分配.这意味着你不需要打电话free(node->key)和free(node->value).事实上,它根本不起作用.只需一个free(node)就可以解决在一个块中释放结构和两个字符串的问题.
行解析:
node->key = strtok(strcpy((char*)(node+1), buffer), "/\r\n");
node->value = strtok(NULL, "\r\n");
Run Code Online (Sandbox Code Playgroud)
第一次调用strtok将指针返回缓冲区本身的开头.它寻找一个'/'(另外用于行尾标记)并用NUL字符打破那里的字符串.因此,"key/value \n"在"key"和"value \n"中被中断,其间有一个NUL字符,并返回并存储指向第一个的指针node->key.第二次调用strtok将对剩余的"值\n"起作用,去掉行尾标记并返回指向"值"的指针,该指针存储在其中node->value.
我希望这可以清除所有关于上述解决方案的问题......这对于一个封闭的问题来说太过分了.完整的测试代码在这里.