使用 strtok 获取行中的最后一个词
Taking of the last word in the line with strtok
给定一个包含以下行的文件:
word1 word2 word3 word4
我试着写了下面的代码:
FILE* f = fopen("my_file.txt", "r");
char line[MAX_BUFFER + 1];
if (fgets(line, MAX_LENGTH_LINE, f) == NULL) {
return NULL;
}
char* word = strtok(line, " ");
for (int i = 0; i < 4; i++) {
printf("%s ", word);
word = strtok(NULL, " ");
}
用于打印 "words"。
它正在工作。但是,我有些不明白。
最后一个词是如何实现的word4
? (我不明白,因为在 "word4" 之后不存在 space)..
我不太确定你在问什么。您是在问程序如何能够从文件中正确读取 word4
,即使它后面没有跟 space?或者你问为什么,当程序打印 word4
退出时,它似乎没有在它之后打印 space?
第一个问题的答案是 strtok
旨在为您提供标记 由 分隔符分隔,而不是 由 [=50= 终止] 分隔符。不要求最后一个标记后跟定界符。
看到第二个问题的答案,如果我们稍微调整程序和打印输出可能会更清楚:
char* word = strtok(line, " ");
for (int i = 0; word != NULL; i++) {
printf("%d: \"%s\"\n", i, word);
word = strtok(NULL, " ");
}
我在这里做了两处修改:
- 循环运行s直到
word
为NULL,即只要strtok
再找一个词就行了。 (这是为了确保我们看到 所有 个单词,并确保我们不会试图以任何方式特殊对待第四个单词。如果您是 试图以某种方式特殊对待第四个词,请这样说。)
- 这些单词用引号括起来打印出来,这样我们就可以准确地看到它们包含的内容。
当我运行修改程序时,我看到:
0: "word1"
1: "word2"
2: "word3"
3: "word4
"
最后一行乍一看很奇怪,但解释很简单。您最初使用 fgets
读取该行,它会将终止 \n
字符复制到 line
缓冲区中。所以它最终停留在 word4
上;即第四个"word"是"word4\n"
.
因此,将 \n
包含在您交给 strtok
的一组白色 space 定界字符中通常是个好主意——也就是说,您可以调用 strtok(line, " \n")
代替。如果我这样做(在两个 strtok
调用中),输出变为
0: "word1"
1: "word2"
2: "word3"
3: "word4"
这可能更接近您的预期。
您的代码不检查 strtok()
的 return 值,在某些情况下可能不安全。
/* Split string
@content origin string content
@delim delimiter for splitting
@psize pointer pointing at the variable to store token size
@return tokens after splitting
*/
const char **split(char *content, const char *delim, int *psize)
{
char *token;
const char **tokens;
int capacity;
int size = 0;
token = strtok(content, delim);
if (!token)
{
return NULL;
}
// Initialize tokens
tokens = malloc(sizeof(char *) * 64);
if (!tokens)
{
exit(-1);
}
capacity = 64;
tokens[size++] = token;
while ((token = strtok(NULL, delim)))
{
if (size >= capacity)
{
tokens = realloc(tokens, sizeof(char *) * capacity * 2);
if (!tokens)
{
exit(-1);
}
capacity *= 2;
}
tokens[size++] = token;
}
// if (size < capacity)
// {
// tokens = realloc(tokens, sizeof(char *) * size);
// if (!tokens)
// {
// exit(-1);
// }
// }
*psize = size;
return tokens;
}
给定一个包含以下行的文件:
word1 word2 word3 word4
我试着写了下面的代码:
FILE* f = fopen("my_file.txt", "r");
char line[MAX_BUFFER + 1];
if (fgets(line, MAX_LENGTH_LINE, f) == NULL) {
return NULL;
}
char* word = strtok(line, " ");
for (int i = 0; i < 4; i++) {
printf("%s ", word);
word = strtok(NULL, " ");
}
用于打印 "words"。
它正在工作。但是,我有些不明白。
最后一个词是如何实现的word4
? (我不明白,因为在 "word4" 之后不存在 space)..
我不太确定你在问什么。您是在问程序如何能够从文件中正确读取 word4
,即使它后面没有跟 space?或者你问为什么,当程序打印 word4
退出时,它似乎没有在它之后打印 space?
第一个问题的答案是 strtok
旨在为您提供标记 由 分隔符分隔,而不是 由 [=50= 终止] 分隔符。不要求最后一个标记后跟定界符。
看到第二个问题的答案,如果我们稍微调整程序和打印输出可能会更清楚:
char* word = strtok(line, " ");
for (int i = 0; word != NULL; i++) {
printf("%d: \"%s\"\n", i, word);
word = strtok(NULL, " ");
}
我在这里做了两处修改:
- 循环运行s直到
word
为NULL,即只要strtok
再找一个词就行了。 (这是为了确保我们看到 所有 个单词,并确保我们不会试图以任何方式特殊对待第四个单词。如果您是 试图以某种方式特殊对待第四个词,请这样说。) - 这些单词用引号括起来打印出来,这样我们就可以准确地看到它们包含的内容。
当我运行修改程序时,我看到:
0: "word1"
1: "word2"
2: "word3"
3: "word4
"
最后一行乍一看很奇怪,但解释很简单。您最初使用 fgets
读取该行,它会将终止 \n
字符复制到 line
缓冲区中。所以它最终停留在 word4
上;即第四个"word"是"word4\n"
.
因此,将 \n
包含在您交给 strtok
的一组白色 space 定界字符中通常是个好主意——也就是说,您可以调用 strtok(line, " \n")
代替。如果我这样做(在两个 strtok
调用中),输出变为
0: "word1"
1: "word2"
2: "word3"
3: "word4"
这可能更接近您的预期。
您的代码不检查 strtok()
的 return 值,在某些情况下可能不安全。
/* Split string
@content origin string content
@delim delimiter for splitting
@psize pointer pointing at the variable to store token size
@return tokens after splitting
*/
const char **split(char *content, const char *delim, int *psize)
{
char *token;
const char **tokens;
int capacity;
int size = 0;
token = strtok(content, delim);
if (!token)
{
return NULL;
}
// Initialize tokens
tokens = malloc(sizeof(char *) * 64);
if (!tokens)
{
exit(-1);
}
capacity = 64;
tokens[size++] = token;
while ((token = strtok(NULL, delim)))
{
if (size >= capacity)
{
tokens = realloc(tokens, sizeof(char *) * capacity * 2);
if (!tokens)
{
exit(-1);
}
capacity *= 2;
}
tokens[size++] = token;
}
// if (size < capacity)
// {
// tokens = realloc(tokens, sizeof(char *) * size);
// if (!tokens)
// {
// exit(-1);
// }
// }
*psize = size;
return tokens;
}