【问题标题】:C tokenize and store into arrayC标记化并存储到数组中
【发布时间】:2014-03-13 09:48:23
【问题描述】:

我有一个文件,我想读取每一行,用制表符标记它并存储到一个数组中。但事实证明,token[0]..token[4] 指向的是 strtok() 产生的每个字符的地址。所以 token[0]...token[4] 每次我在文件的下一行调用 strtok 时都会改变。我该如何纠正?如果我尝试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 到 4。我试图找出问题所在。
  • 如果我打印整个令牌数组,它将显示为 45 21 55 18 46 45 21 55 18 46 45 21 55 18 46
  • @LearningC 我不确定你在说什么。我想获取文件中每个值的大小为 15 的数组。
  • char tokens[MAX_SIZE][3];...token=strtok(...);strcpy(tokens[i],token);

标签: c arrays pointers


【解决方案1】:

您没有正确使用从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 各个令牌。您还需要在外部while 循环结束时释放getline 返回的缓冲区:

free(line);

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

【讨论】:

  • 尊敬的先生,谢谢!现在我明白为什么了。所以只需要复制令牌!我会找到有关 strtok_r 的信息。非常感谢
  • 如果我没记错的话,strtok_r 不是标准的
  • @Dabo 正确。不过,getline 也是如此。
  • aahh,没注意到 OP 正在使用getline,+1
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多