[英]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"
上使用一次strtok
來fileOutput
中的每一行,而不是再次嵌套來解析':'
。 否則,由於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.