【发布时间】:2016-10-24 15:52:45
【问题描述】:
我的大学教授给我布置了作业,我似乎发现了strtok 的一些奇怪行为
基本上,我们必须为我的班级解析一个 CSV 文件,其中 CSV 中的标记数量是已知的,并且最后一个元素可能有额外的 "," 字符。
一行示例:
Hello,World,This,Is,A lot, of Text
标记应该在哪里输出
1. Hello
2. World
3. This
4. Is
5. A lot, of Text
对于这项任务,我们必须使用strtok。因此,我在其他一些 SOF 帖子中发现,使用带有空字符串的strtok(或将"\n" 作为第二个参数传递)会导致读取到行尾。这非常适合我的应用程序,因为多余的逗号总是出现在最后一个元素中。
我创建了这个有效的代码:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define NUM_TOKENS 5
const char *line = "Hello,World,This,Is,Text";
char **split_line(const char *line, int num_tokens)
{
char *copy = strdup(line);
// Make an array the correct size to hold num_tokens
char **tokens = (char**) malloc(sizeof(char*) * num_tokens);
int i = 0;
for (char *token = strtok(copy, ",\n"); i < NUM_TOKENS; token = strtok(NULL, i < NUM_TOKENS - 1 ? ",\n" : "\n"))
{
tokens[i++] = strdup(token);
}
free(copy);
return tokens;
}
int main()
{
char **tokens = split_line(line, NUM_TOKENS);
for (int i = 0; i < NUM_TOKENS; i++)
{
printf("%s\n", tokens[i]);
free(tokens[i]);
}
}
现在这可行,应该得到我的充分信任,但我讨厌这个不应该需要的三元:
token = strtok(NULL, i < NUM_TOKENS - 1 ? ",\n" : "\n");
我想用这个版本替换方法:
char **split_line(const char *line, int num_tokens)
{
char *copy = strdup(line);
// Make an array the correct size to hold num_tokens
char **tokens = (char**) malloc(sizeof(char*) * num_tokens);
int i = 0;
for (char *token = strtok(copy, ",\n"); i < NUM_TOKENS - 1; token = strtok(NULL, ",\n"))
{
tokens[i++] = strdup(token);
}
tokens[i] = strdup(strtok(NULL, "\n"));
free(copy);
return tokens;
}
这更让我觉得好笑,因为更容易看出有一个最终案例。你也摆脱了奇怪的三元运算符。
可悲的是,这个段错误!我一辈子都想不通为什么。
编辑:添加一些输出示例:
[11:56:06] gravypod:test git:(master*) $ ./test_no_fault
Hello
World
This
Is
Text
[11:56:10] gravypod:test git:(master*) $ ./test_seg_fault
[1] 3718 segmentation fault (core dumped) ./test_seg_fault
[11:56:14] gravypod:test git:(master*) $
【问题讨论】:
-
啊,我现在看到了 \n 的困惑。使用带有 \n 的 strtok 是您如何逐行解析加载到内存中的整个文本文件。如果你只处理一个不包含换行符的单行,那么它就没有神奇的意义。