簡體   English   中英

c 中的嵌套 strtok 導致無限循環

[英]Nested strtok in c resulting in an infinite loop

我讓用戶輸入用戶名,然后將 go 放入此文件並提取與特定用戶對應的值。 我知道問題出在我使用strtok的方式上,因為它只適用於第一個用戶。

找到用戶后,我想停止在文件中搜索。

int fd;
fd=open(fileName,O_RDONLY,0744);

if (fd==-1)
{
    printf("The file userDetails.txt failed to open.\n");
    exit(1);
}

int fileSize = sizeof(fileOutput)/sizeof(fileOutput[0]); //size of file

printf("%d\n",fileSize);

int bytesRead = read(fd,&fileOutput,fileSize);

//TERMINATING BUFFER PROPERLY
fileOutput[bytesRead] = '\0';

printf("%s\n",fileOutput);
//READING LINE BY LINE IN FILE
char *line;
char *data;
char *name;
char *saltValue;
char *encryptedValue;

line = strtok(fileOutput,"\n"); //SPLIT ACCORDING TO LINE

while (line != NULL)
{
    data = strtok(line, ":");
    while (data != NULL)
    {
        name = data;

        if (strcmp(name,userName)==0)
        {
            printf("%s\n","User exists");

            saltValue = strtok(NULL,":");
            printf("%s\n",saltValue);

            encryptedValue = strtok(NULL, ":");
            printf("%s\n",encryptedValue);
            break;
        }
        else
        {
            break;
        }
    }

    if (strcmp(name,userName)==0) //user found
    {
        break;
    }
    else //user not found
    {
        strtok(NULL,"\n");
    }
}

如果您僅限於read ,那很好,但您只能在"\n"上使用一次strtokfileOutput中的每一行,而不是再次嵌套來解析':' 否則,由於strtok通過在找到的分隔符處插入'\0'來修改字符串,因此您將在行內寫入nul 終止字符,這將導致外部strtok認為字符串在下一次迭代中完成。

相反,使用strchr (line, ':')在每一行上使用單個指針來定位第一個':'行,然后使用strncmp()使用指向行首的指針,然后使用指針定位':' 例如,如果您有一個userName來檢查用戶名是否包含在您的文件中(成功返回0 ,失敗返回1 ),您可以執行以下操作:

    ...
    for (char *line = strtok(fileOutput,"\n"); line; line = strtok (NULL, "\n"))
    {
        char *p = strchr (line, ':');                   /* find first ':' */
        if (!p)                                         /* if not found, bail */
            break;
        if (strncmp (userName, line, p - line) == 0) {  /* check name */
            printf ("found user: %s  hash: %s\n", userName, p+1);
            return 0;
        }
    }

    fputs ("user not found.\n", stdout);
    return 1;

這可能是您可以采取的更簡單的方法之一。

Strtok修改了它的輸入字符串,這使得在嵌套模式下無法調用它,內部循環工作破壞了外部strtok()的工作,使其無法繼續。

除此之外,在您的問題中使用strtok()是不夠的,還有一個原因:如果您嘗試使用它來解析/etc/passwd文件(或我們今天處理的類似格式文件之一),您將運行有空字段的麻煩。 如果您有一個空字段(兩個連續的:字符順序, strtok()將跳過這兩個字符,跳過完全未檢測到的空字段), Strtok是一個舊的、遺留的 function,它是為處理三個字符( \n\t ) 用於在 bourne shell 中分隔 arguments。 /etc/passwd的情況下,您需要處理可能為空的字段,這使得無法使用strtok()解析它們。

您可以輕松地使用strchr()以非跳過方式搜索/etc/passwd: ,只需編寫類似的內容(您可以將其封裝在一個函數中):

char *not_strtok_but_almost(char *s, char *delim)
{
    static char *p = NULL; /* this makes the function non-reentrant, like strtok() */
    char *saved = NULL;
    if (s) {
        p = s;
        while (strchr(delim, *p)) /* while *p is in the delimiters, skip */ 
            p++; 
        /* *p is not more in the delimiters. save as return value */
        saved = p;
    }
    /* search for delimiters after value */
    while (*p && !strchr(delim, *p)) /* while *p not null, and not in the delimiter set */
        p++;
    /* *p is at the end of the string or p points to one of the delimiters */
    *p = '\0';

    return saved;
}

這個 function 有strtok(3)的所有麻煩,但你可以使用它(注意它的不可重入性並修改源字符串,使其不能嵌套在多個循環中),因為它不會跳過所有的分隔符一次拍攝,但在找到第一個分隔符后停止。

為了解決嵌套問題,您可以采取不同的方式,假設您有幾個由空格分隔的標識符(如/etc/group文件中),這些標識符應該需要(它不需要,因為名稱字段是最后一個,您不會在第一個循環上再次調用 strtok ,而是要獲得NULL 。您可以按級別優先級而不是深度優先級優先級處理文件。您首先查找第一級中的所有字段,然后查找 go,逐個字段,讀取其子字段(可能會使用不同的分隔符)

由於所有這些修改都是在同一個字符串中完成的,因此無需在使用前為每個字符串和strdup()分配一個緩沖區......工作可以在同一個文件中完成,然后strdup()將字符串設置為如果您需要存儲不同的子字段,請從頭開始。

如果您對此有疑問,請發表任何評論(請小心,因為我沒有測試上面的例程,它可能有錯誤)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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