C令牌化并存储到数组中

我有一个文件,我想读取每一行,通过制表符标记它并存储到一个数组中。 但事实certificate,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 

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

由于您将指针存储到该缓冲区中,下次将具有新数据的行放入旧空间时,指向该地址的所有标记将“看到”新数据。 要避免这个问题,您需要在从strtok获取它们之后立即复制它们,例如,将它们传递给strdup

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

您还需要限制第一个令牌。

注意:如果采用这种方法,一旦程序完成,您将需要free单个令牌。 您还需要在外部while循环结束时释放getline返回的缓冲区:

 free(line); 

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

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