[英]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
如果我正確地理解了指針和內存(堆棧/堆),那么實現的錯誤包括:
1)這是不正確的:它打印所有令牌,后跟短語“ Next Token”,因為這是程序中的下一個內存。 它只是停止了,因為堆棧上什么也沒剩下
2)我不是真正使用buf_size正確。 任何超過11個字符的令牌都將引起問題。
但是我現在的目的只是解決第一個問題,即如何終止while循環。
執行此操作時:
int i = strcspn(*input, delimmter);
i
將具有段的長度,該段的長度完全由不包含在delimmter
的字節組成。 如果delimmter中的delimmter
位於*input
,則i
會比strlen(*input)
短。
strncpy(buf, *input, i > buf_size ? buf_size : i);
此行最多復制i > buf_size ? buf_size : i
i > buf_size ? buf_size : i
buf
i > buf_size ? buf_size : i
字符,假設i
大於buf_size
,這意味着您將在buf
復制buf_size
元素,但不會以' \\0
'終止,因為strncpy
不會寫'\\0'
終止如果未找到。 因此, 您必須設置'\\0'
終止字節。
strncpy(buf, *input, i > buf_size ? buf_size : i);
buf[(i >= buf_size ? buf_size - 1: i)] = 0;
如果i
小於buf_size
,則位置i
是終止位置'\\0'
的位置。 如果i
大於或大於buf_size
或等於buf_size-1
,則buf_size-1
是緩沖區中的最后一個位置,該位置應為'\\0'
終止字節。
這個
*input += i+1;
並非在所有情況下都是正確的。 如果在*input
找不到定界符,那么i
將與strlen(*input)
。 在那種情況下,您希望input
指向'\\0'
終止字節而不是超過它,因為在下一次迭代中您將超出范圍訪問內存。 如果i
小於長度,則增量很好。 因此,正確的版本是
*input += i + (i != strlen(*input));
這個
if (i == strlen(*input))
return 0;
應該刪除。 在這種情況下,必須返回整個*input
字符串,並且函數應返回1。這就是為什么可以刪除它。 但是,您需要測試的是*input
是否為空字符串。 在這種情況下,所有令牌都已返回,您應該返回0。對strcspn
調用執行此檢查prioir。
所以
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
這是正確的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.