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