簡體   English   中英

通過不帶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

如果我正確地理解了指針和內存(堆棧/堆),那么實現的錯誤包括:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM