用strtok填充链表的问题
Problem with filling the linked list with strtok
我在处理下一段代码时遇到问题...
我定义了一个链表结构体
typedef struct node {
char *cmd;
char *value;
int delay;
struct node *next;
} node_t;
我正在从名为 commands.txt
的文本文件中读取命令
write:0x02:1
read:0x04:2
set:0xff:2
reset:0xfa:2
如果我使用两个缓冲区(temp 和 temp1),下面的代码可以工作,但是如果我用 temp 替换 temp1,它就不能正确解析它。它给了我
Tokenized2 read x04 1
Tokenized2 read 0x04 2
Tokenized2 read x04 1
Tokenized2 read 0x04 2
密码是:
char *filename = "commands.txt";
FILE *fp = fopen(filename, "r");
node_t *head = (node_t *)malloc(sizeof(node_t));
node_t *hp = head;
char temp[14];
char temp1[14];
fgets(temp, 14, fp);
hp->cmd = strtok(temp, ":");
hp->value = strtok(0, ":");
hp->delay = atoi(strtok(0, ":"));
hp->next = (node_t *)malloc(sizeof(node_t));
hp = (node_t *)hp->next; Blaz
fgets(temp1, 14, fp);
hp->cmd = strtok(temp1, ":");
hp->value = strtok(0, ":");
hp->delay = atoi(strtok(0, ":"));
hp->next = NULL;
hp = head;
printf("Tokenized2 %s %s %d\n", hp->cmd, hp->value, hp->delay);
hp = hp->next;
printf("Tokenized2 %s %s %d\n", head->next->cmd, head->next->value, head->next->delay);
printf("Tokenized2 %s %s %d\n", head->cmd, head->value, head->delay);
printf("Tokenized2 %s %s %d\n", head->next->cmd, head->next->value, head->next->delay);
fclose(fp);
底部的 printfs 是多余的,我只是在测试它是否适用于对 head 的经典访问和通过指针。
最终我想让这段代码工作。
const unsigned MAX_LENGTH = 256;
char cmdbuffer[MAX_LENGTH];
node_t *head = (node_t *)malloc(sizeof(node_t));
node_t *hp = head;
while (fgets(cmdbuffer, MAX_LENGTH, fp)) {
hp->cmd = strtok(cmdbuffer, ":");
hp->value = strtok(0, ":");
hp->delay = atoi(strtok(0, ":"));
hp->next = (node_t *)malloc(sizeof(node_t));
hp = (node_t *)hp->next;
}
hp->next = NULL;
printf("Tokenized %s %s %d\n", head->cmd, head->value, head->delay);
printf("Tokenized2 %s %s %d\n", head->next->cmd, head->next->value, head->next->delay);
我该如何解决这个问题?
那是因为这些行:
hp->cmd = strtok(temp, ":");
hp->value = strtok(0, ":");
// ...
fgets(temp, 14, fp); // here temp1 was replaced with temp
您基本上是用终止符 ([=14=]
) 替换 temp
中的第一个和第二个 :
,然后分配 hp->cmd = temp;
和 hp->value = temp + some_offset;
。
然后,如果您再次读入 temp
,旧的内容将被覆盖,旧的赋值将引用缓冲区中新数据中一些错误的无关偏移量。使用两个缓冲区解决了这个问题,因为您不再用第二次读取的数据覆盖第一次读取的数据。
如果您只想使用一个临时缓冲区进行读取,那么在使用 strtok()
并分配 ->cmd
和 [=21 之前,您必须使用 strdup()
将其复制到其他地方=],或者直接 malloc()
缓冲区,这样每次你做这些赋值时,它们都会引用不同的新分配的字符串。如果这样做,请记住稍后还要 free()
分配的缓冲区。
类似的东西(自己检查代码,我没有测试):
const unsigned MAX_LENGTH = 256;
node_t *head = malloc(sizeof(node_t));
node_t *hp = head;
char *cmdbuffer;
head->next = NULL;
while (1) {
cmdbuffer = malloc(MAX_LENGTH);
if (fgets(cmdbuffer, MAX_LENGTH, fp)) {
break;
}
hp->cmd = strtok(cmdbuffer, ":");
hp->value = strtok(0, ":");
hp->delay = atoi(strtok(0, ":"));
hp->next = malloc(sizeof(node_t));
hp = hp->next;
}
if (hp->next) {
// careful here you need to free before assigning NULL
// or you leak memory
free(hp->next);
hp->next = NULL;
}
// ...
node_t *tmp;
hp = head;
while (hp) {
tmp = hp;
hp = hp->next;
free(tmp->cmd);
free(tmp);
}
无论如何,do not cast the return value of malloc()
。
我设法用 strdup 解决了它。这是代码...
FILE *fp = fopen("commands.txt", "r");
if (fp == NULL){
printf("Error: could not open text file");
return 1;
}
const unsigned MAX_LENGTH = 256;
char cmdbuffer[MAX_LENGTH];
node_t* head = malloc(sizeof(node_t));
node_t* hp = head;
char* sdup;
while (fgets(cmdbuffer, MAX_LENGTH, fp)){
sdup = strdup(cmdbuffer);
hp->cmd = strtok(sdup, ":");
hp->value = strtok(0, ":");
hp->delay = atoi(strtok(0, ":"));
hp->next = malloc(sizeof(node_t));
hp = (node_t*) hp->next;
}
hp->next = NULL;
hp = head;
while(hp){
printf("Tokenized: %s %s %d\n", hp->cmd, hp->value, hp->delay);
free(hp);
hp = hp->next;
}
Comments/corrections 欢迎光临!
我在处理下一段代码时遇到问题...
我定义了一个链表结构体
typedef struct node {
char *cmd;
char *value;
int delay;
struct node *next;
} node_t;
我正在从名为 commands.txt
的文本文件中读取命令write:0x02:1
read:0x04:2
set:0xff:2
reset:0xfa:2
如果我使用两个缓冲区(temp 和 temp1),下面的代码可以工作,但是如果我用 temp 替换 temp1,它就不能正确解析它。它给了我
Tokenized2 read x04 1
Tokenized2 read 0x04 2
Tokenized2 read x04 1
Tokenized2 read 0x04 2
密码是:
char *filename = "commands.txt";
FILE *fp = fopen(filename, "r");
node_t *head = (node_t *)malloc(sizeof(node_t));
node_t *hp = head;
char temp[14];
char temp1[14];
fgets(temp, 14, fp);
hp->cmd = strtok(temp, ":");
hp->value = strtok(0, ":");
hp->delay = atoi(strtok(0, ":"));
hp->next = (node_t *)malloc(sizeof(node_t));
hp = (node_t *)hp->next; Blaz
fgets(temp1, 14, fp);
hp->cmd = strtok(temp1, ":");
hp->value = strtok(0, ":");
hp->delay = atoi(strtok(0, ":"));
hp->next = NULL;
hp = head;
printf("Tokenized2 %s %s %d\n", hp->cmd, hp->value, hp->delay);
hp = hp->next;
printf("Tokenized2 %s %s %d\n", head->next->cmd, head->next->value, head->next->delay);
printf("Tokenized2 %s %s %d\n", head->cmd, head->value, head->delay);
printf("Tokenized2 %s %s %d\n", head->next->cmd, head->next->value, head->next->delay);
fclose(fp);
底部的 printfs 是多余的,我只是在测试它是否适用于对 head 的经典访问和通过指针。 最终我想让这段代码工作。
const unsigned MAX_LENGTH = 256;
char cmdbuffer[MAX_LENGTH];
node_t *head = (node_t *)malloc(sizeof(node_t));
node_t *hp = head;
while (fgets(cmdbuffer, MAX_LENGTH, fp)) {
hp->cmd = strtok(cmdbuffer, ":");
hp->value = strtok(0, ":");
hp->delay = atoi(strtok(0, ":"));
hp->next = (node_t *)malloc(sizeof(node_t));
hp = (node_t *)hp->next;
}
hp->next = NULL;
printf("Tokenized %s %s %d\n", head->cmd, head->value, head->delay);
printf("Tokenized2 %s %s %d\n", head->next->cmd, head->next->value, head->next->delay);
我该如何解决这个问题?
那是因为这些行:
hp->cmd = strtok(temp, ":");
hp->value = strtok(0, ":");
// ...
fgets(temp, 14, fp); // here temp1 was replaced with temp
您基本上是用终止符 ([=14=]
) 替换 temp
中的第一个和第二个 :
,然后分配 hp->cmd = temp;
和 hp->value = temp + some_offset;
。
然后,如果您再次读入 temp
,旧的内容将被覆盖,旧的赋值将引用缓冲区中新数据中一些错误的无关偏移量。使用两个缓冲区解决了这个问题,因为您不再用第二次读取的数据覆盖第一次读取的数据。
如果您只想使用一个临时缓冲区进行读取,那么在使用 strtok()
并分配 ->cmd
和 [=21 之前,您必须使用 strdup()
将其复制到其他地方=],或者直接 malloc()
缓冲区,这样每次你做这些赋值时,它们都会引用不同的新分配的字符串。如果这样做,请记住稍后还要 free()
分配的缓冲区。
类似的东西(自己检查代码,我没有测试):
const unsigned MAX_LENGTH = 256;
node_t *head = malloc(sizeof(node_t));
node_t *hp = head;
char *cmdbuffer;
head->next = NULL;
while (1) {
cmdbuffer = malloc(MAX_LENGTH);
if (fgets(cmdbuffer, MAX_LENGTH, fp)) {
break;
}
hp->cmd = strtok(cmdbuffer, ":");
hp->value = strtok(0, ":");
hp->delay = atoi(strtok(0, ":"));
hp->next = malloc(sizeof(node_t));
hp = hp->next;
}
if (hp->next) {
// careful here you need to free before assigning NULL
// or you leak memory
free(hp->next);
hp->next = NULL;
}
// ...
node_t *tmp;
hp = head;
while (hp) {
tmp = hp;
hp = hp->next;
free(tmp->cmd);
free(tmp);
}
无论如何,do not cast the return value of malloc()
。
我设法用 strdup 解决了它。这是代码...
FILE *fp = fopen("commands.txt", "r");
if (fp == NULL){
printf("Error: could not open text file");
return 1;
}
const unsigned MAX_LENGTH = 256;
char cmdbuffer[MAX_LENGTH];
node_t* head = malloc(sizeof(node_t));
node_t* hp = head;
char* sdup;
while (fgets(cmdbuffer, MAX_LENGTH, fp)){
sdup = strdup(cmdbuffer);
hp->cmd = strtok(sdup, ":");
hp->value = strtok(0, ":");
hp->delay = atoi(strtok(0, ":"));
hp->next = malloc(sizeof(node_t));
hp = (node_t*) hp->next;
}
hp->next = NULL;
hp = head;
while(hp){
printf("Tokenized: %s %s %d\n", hp->cmd, hp->value, hp->delay);
free(hp);
hp = hp->next;
}
Comments/corrections 欢迎光临!