我有一个文件,我想读取每一行,通过制表符对其进行标记并存储到数组中。但事实证明,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
答案 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第一次才有效。我不知道原因,但我曾经遇到过这个问题。