用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 欢迎光临!