为什么strtok会返回错误的令牌数量?

时间:2017-12-08 09:19:28

标签: c

我一直在用C解决代码问题,我遇到了一些我不理解的问题。我的C非常生疏,我知道这不是C代码的一个很好的例子。我已将程序剥离到最小的部分,以显示让我感到困惑的行为。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int ae_load_file_to_memory(const char *filename, char **result)
{
    int size = 0;
    FILE *f = fopen(filename, "rb");
    if (f == NULL)
    {
        *result = NULL;
        return -1; 
    }
    fseek(f, 0, SEEK_END);
    size = ftell(f);
    fseek(f, 0, SEEK_SET);
    *result = (char *)malloc(sizeof(char) * (size + 1));
    if (size != fread(*result, sizeof(char), size, f))
    {
        free(*result);
        return -2; 
    }
    fclose(f);
    (*result)[size] = 0;
    return size;
}

int main(void)
{
    const char delim = '\n';
    int fill_index = 0;
    char *token = NULL;
    char *content = NULL;

    ae_load_file_to_memory("input.txt", &content);

    token = strtok(content, &delim);

    while (token != NULL)
    {
        fill_index++;
        token = strtok(NULL, &delim);
    }
    printf("Fill index %d\n", fill_index);
}

此代码从磁盘读取文件,然后使用换行符作为分隔符将其拆分为标记。最终printf返回正确的令牌数,1044。

但是,如果我更改main方法的开头以移动fill_index的声明:

int main(void)
{
    int fill_index = 0;
    const char delim = '\n';

...现在strtok会返回1050个令牌,这是错误的。这是两个文件之间的唯一区别。我在Mac OS X Sierra上运行,gcc --version报告其Apple LLVM version 9.0.0 (clang-900.0.38)

我确定我在某个地方踩着记忆,而第一个版本只是巧合。但是,我不知道为什么移动这个声明会产生如此大的影响。谁能解释一下发生了什么?

1 个答案:

答案 0 :(得分:4)

您没有正确使用delim。它将是const char delim[] = "\n";(Null终止的char数组不是单个字符)。

之前您通过传递错误的参数来调用未定义的行为。

来自标准§7.24.5.8

char *strtok(char * restrict s1,const char * restrict s2);

还有一些例子

static char str[] = "?a???b,,,#c";
         char *t;
         t   =   strtok(str, "?");         //   t   points to the token "a"
         t   =   strtok(NULL, ",");        //   t   points to the token "??b"
         t   =   strtok(NULL, "#,");       //   t   points to the token "c"
         t   =   strtok(NULL, "?");        //   t   is a null pointer