通过在没有 strtok 的情况下标记字符串来学习 C
Learning C by Tokenizing a String without strtok
我正在通过查看斯坦福大学和其他大学的作业来学习 C
(我不是任何地方的学生)。
其中一项作业是实现更简单的 strtok
,但我无法正确完成。这是我目前所拥有的:
#include <stdio.h>
#include <string.h>
int tokenize(const char **input, const char *delimmter, char buf[], int buf_size)
{
int i = strcspn(*input, delimmter);
strncpy(buf, *input, i > buf_size ? buf_size : i);
*input += i+1;
if (i == strlen(*input))
return 0;
return 1;
}
int main(int argc, char *argv[])
{
const char *input = "super-duper-awesome-magnificent";
char buf[11];
while (tokenize(&input, "-", buf, sizeof(buf)))
{
printf("Next Token : %s\n", buf);
}
return 0;
}
Next Token : super
Next Token : duper
Next Token : awesome
Next Token : magnificent
Next Token : Next Token
如果我正确理解指针和内存 (stack/heap),那么我的实现中的错误包括:
1) It's incorrect: It prints all the tokens followed by the phrase
"Next Token" because that's the next piece of memory in the program.
It only stops because there's nothing left on the stack
2) I am not really using buf_size correctly. Any token longer than 11
characters will cause problems.
但我现在的目标只是解决第一个问题,即如何终止while循环。
当你这样做时:
int i = strcspn(*input, delimmter);
i
将具有完全由不在
delimmter
。如果 delimmter
中的字符在 *input
中,i
将更短
比 strlen(*input)
.
strncpy(buf, *input, i > buf_size ? buf_size : i);
这一行在buf
中最多复制i > buf_size ? buf_size : i
个字符,
假设 i
大于 buf_size
,这意味着您将复制 buf_size
buf
中的元素,但不会以“[=30=]
”结尾,因为 strncpy
不会
如果未找到,则写入 '[=32=]'
-终止符。所以你必须设置
'[=32=]'
终止字节。
strncpy(buf, *input, i > buf_size ? buf_size : i);
buf[(i >= buf_size ? buf_size - 1: i)] = 0;
如果i
小于buf_size
,那么位置i
就是
'[=32=]'
-终止字节应该去。如果 i
大于或等于 buf_size
或等于,
然后 buf_size-1
是缓冲区中的最后一个位置,这就是
'[=32=]'
-终止字节应该去。
这个
*input += i+1;
并非对所有情况都是正确的。如果在 *input
中找不到分隔符,则 i
将与 strlen(*input)
相同。在那种情况下,你想要 input
点
到 '[=32=]'
终止字节而不是超过它,因为您将访问
下一次迭代内存越界。如果i
小于长度,
那么增量就可以了。所以,正确的版本应该是
*input += i + (i != strlen(*input));
这个
if (i == strlen(*input))
return 0;
应该删除。在这种情况下,整个 *input
字符串必须是
returned 和函数应该 return 1. 这就是为什么你可以删除它。但
您必须测试的是 *input
是否为空字符串。在这种情况下,所有
令牌已被 returned,你应该 return 0。在
strcspn
呼唤。
所以
int tokenize(const char **input, const char *delimmter, char buf[], int buf_size)
{
if(**input == 0)
return 0;
int i = strcspn(*input, delimmter);
strncpy(buf, *input, i > buf_size ? buf_size : i);
buf[(i > buf_size ? buf_size - 1: i)] = 0;
*input += i + (i != strlen(*input));
return 1;
}
这会给你想要的结果。如果您更改 main
函数
buff
到 char buf[3]
的声明,这将是输出:
Next Token : su
Next Token : du
Next Token : aw
Next Token : ma
哪个是正确的。
我正在通过查看斯坦福大学和其他大学的作业来学习 C
(我不是任何地方的学生)。
其中一项作业是实现更简单的 strtok
,但我无法正确完成。这是我目前所拥有的:
#include <stdio.h>
#include <string.h>
int tokenize(const char **input, const char *delimmter, char buf[], int buf_size)
{
int i = strcspn(*input, delimmter);
strncpy(buf, *input, i > buf_size ? buf_size : i);
*input += i+1;
if (i == strlen(*input))
return 0;
return 1;
}
int main(int argc, char *argv[])
{
const char *input = "super-duper-awesome-magnificent";
char buf[11];
while (tokenize(&input, "-", buf, sizeof(buf)))
{
printf("Next Token : %s\n", buf);
}
return 0;
}
Next Token : super
Next Token : duper
Next Token : awesome
Next Token : magnificent
Next Token : Next Token
如果我正确理解指针和内存 (stack/heap),那么我的实现中的错误包括:
1) It's incorrect: It prints all the tokens followed by the phrase "Next Token" because that's the next piece of memory in the program. It only stops because there's nothing left on the stack
2) I am not really using buf_size correctly. Any token longer than 11 characters will cause problems.
但我现在的目标只是解决第一个问题,即如何终止while循环。
当你这样做时:
int i = strcspn(*input, delimmter);
i
将具有完全由不在
delimmter
。如果 delimmter
中的字符在 *input
中,i
将更短
比 strlen(*input)
.
strncpy(buf, *input, i > buf_size ? buf_size : i);
这一行在buf
中最多复制i > buf_size ? buf_size : i
个字符,
假设 i
大于 buf_size
,这意味着您将复制 buf_size
buf
中的元素,但不会以“[=30=]
”结尾,因为 strncpy
不会
如果未找到,则写入 '[=32=]'
-终止符。所以你必须设置
'[=32=]'
终止字节。
strncpy(buf, *input, i > buf_size ? buf_size : i);
buf[(i >= buf_size ? buf_size - 1: i)] = 0;
如果i
小于buf_size
,那么位置i
就是
'[=32=]'
-终止字节应该去。如果 i
大于或等于 buf_size
或等于,
然后 buf_size-1
是缓冲区中的最后一个位置,这就是
'[=32=]'
-终止字节应该去。
这个
*input += i+1;
并非对所有情况都是正确的。如果在 *input
中找不到分隔符,则 i
将与 strlen(*input)
相同。在那种情况下,你想要 input
点
到 '[=32=]'
终止字节而不是超过它,因为您将访问
下一次迭代内存越界。如果i
小于长度,
那么增量就可以了。所以,正确的版本应该是
*input += i + (i != strlen(*input));
这个
if (i == strlen(*input))
return 0;
应该删除。在这种情况下,整个 *input
字符串必须是
returned 和函数应该 return 1. 这就是为什么你可以删除它。但
您必须测试的是 *input
是否为空字符串。在这种情况下,所有
令牌已被 returned,你应该 return 0。在
strcspn
呼唤。
所以
int tokenize(const char **input, const char *delimmter, char buf[], int buf_size)
{
if(**input == 0)
return 0;
int i = strcspn(*input, delimmter);
strncpy(buf, *input, i > buf_size ? buf_size : i);
buf[(i > buf_size ? buf_size - 1: i)] = 0;
*input += i + (i != strlen(*input));
return 1;
}
这会给你想要的结果。如果您更改 main
函数
buff
到 char buf[3]
的声明,这将是输出:
Next Token : su
Next Token : du
Next Token : aw
Next Token : ma
哪个是正确的。