C令牌化并存储到数组中

时间:2014-03-13 09:48:23

标签: c arrays pointers

我有一个文件,我想读取每一行,通过制表符对其进行标记并存储到数组中。但事实证明,token [0] .. token [4]指向由strtok()产生的每个char的地址。因此,每当我在文件的下一行调用strtok时,token [0] ... token [4]就会改变。我该如何纠正?如果我尝试char tokens[MAX_SIZE]而不是char* tokens[MAX_SIZE],则会发生转换错误,因为strtok会返回char *。

文件是

20  34  90  10  77

80  12  37  29  63

45  21  55  18  46

我的代码是:

FILE *f;
if ((f = fopen("myinput.txt","r")) == NULL) {
    perror("Failed to open file:");
    return -1;
}
char * line;
size_t len = 0;
char *tokens[MAX_SIZE];
int i = 0;
while (getline(&line, &len, f) !=-1) {

    char* lineWithoutNullByte = strtok(line,"\n");
    tokens[i]=strtok(lineWithoutNullByte,"\t");
    i++;
    int x = 1;
    while (x){

                tokens[i] = strtok(NULL, "\t");
                if (tokens[i] == NULL){
                    x=0;
                }else{
                    i++;
                }


    }
    printf("test: %s %s %s %s %s\n", tokens[0],tokens[1],tokens[2],tokens[3],tokens[4] );


}

预期输出

    test: 20 34 90 10 77
    test: 20 34 90 10 77
    test: 20 34 90 10 77

但我得到了:

    test: 20 34 90 10 77
    test: 80 12 37 29 63
    test: 45 21 55 18 46

澄清: 这意味着,如果我打印整个tokens数组,我将会得到

45 21 55 18 46
45 21 55 18 46
45 21 55 18 46

2 个答案:

答案 0 :(得分:3)

您没有使用从strtok正确获得的令牌:您获得的令牌来自getline返回的缓冲区。第一个调用为您提供了一个新缓冲区;后续调用写入同一缓冲区,因为该行适合分配的空间。

由于您将指针存储到该缓冲区中,下一次将包含新数据的行放入旧空间时,指向该地址的所有标记都将显示"参见"新数据。要避免此问题,您需要在从strtok获取令牌后立即复制令牌,例如,将其传递给strdup

char *tmp = strtok(NULL, "\t");
if (tmp == NULL) {
    x = 0;
    tokens[i] = NULL;
} else {
    i++;
    tokens[i] = strdup(tmp);
}

您还需要strdup第一个令牌。

注意:如果你采用这种方法,一旦你的程序完成,你需要free个人代币。您还需要在外部getline循环的末尾释放while返回的缓冲区:

free(line);

此外,strtok是不可重入的,这意味着它不能在并发环境中使用,甚至不能在嵌套循环中对字符串进行标记。您应该使用strtok_r代替。

答案 1 :(得分:0)

你应该使用strtok_r而不是strtok。因为strtok第一次才有效。我不知道原因,但我曾经遇到过这个问题。