Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c中的嵌套strtok导致无限循环_C_Linux - Fatal编程技术网

c中的嵌套strtok导致无限循环

c中的嵌套strtok导致无限循环,c,linux,C,Linux,我让用户输入一个用户名,然后转到该文件并提取对应于特定用户的值。我知道问题在于我使用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)/siz

我让用户输入一个用户名,然后转到该文件并提取对应于特定用户的值。我知道问题在于我使用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");
    }
}
如果您仅限于读取,则可以,但只能使用strtok一次\n来解析fileOutput中的每一行,而不能再次嵌套以解析“:”。否则,由于Strutk通过在找到的定界符中插入“0”来修改字符串,您将在行中写入NUL终止字符,这将导致外部Strutk考虑下一次迭代结束的字符串。 相反,在每一行上使用一个单独的指针和strhr行“:”来定位该行的第一个“:”,然后使用指向行开头的指针和指针定位“:”。例如,如果您有一个函数来检查文件中是否包含用户名,成功时返回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一次\n来解析fileOutput中的每一行,而不是再次嵌套来解析“:”。否则,由于Strutk通过在找到的定界符中插入“0”来修改字符串,您将在行中写入NUL终止字符,这将导致外部Strutk考虑下一次迭代结束的字符串。 相反,在每一行上使用一个单独的指针和strhr行“:”来定位该行的第一个“:”,然后使用指向行开头的指针和指针定位“:”。例如,如果您有一个函数来检查文件中是否包含用户名,成功时返回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是一个旧的遗留函数,编写此函数是为了处理bourne shell中用于分隔参数的三个字符。对于/etc/passwd,您需要处理可能为空的字段,这使得无法使用strtok解析它们

您可以轻松地使用strchr以非跳过的方式搜索:of/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;
}
这个函数有strtok3的所有问题,但是您可以使用它来处理它的不可重入性,并且它修改源字符串,使它不能嵌套在多个循环中,因为它不会在一次跳过所有分隔符,而是在找到第一个分隔符后停止

为了解决嵌套问题,您可以采用另一种方式,假设您在/etc/group文件中有多个标识符,它们之间用空格分隔,这应该是需要的。但是,由于名称字段是最后一个字段,您不需要在第一个循环中再次调用strtok,而是要得到一个NULL。您可以以级别优先而不是深度优先的方式处理文件。首先查找第一级中的所有字段,然后逐字段读取可能使用不同分隔符的子字段

由于所有这些修改都是在同一个字符串中完成的,所以在使用之前不需要为每个字符串分配缓冲区并对字符串进行strdup。。。这项工作可以在同一个文件中完成,如果需要存储不同的子字段,可以在开始时对字符串进行strdup

如果您对此有疑问,请发表任何意见。请小心,因为我没有测试上面的例程,它可能有一个bug

Strtok修改其输入字符串,这使得无法在嵌套模式下调用它,内部循环工作会破坏外部Strtok的工作,使其无法继续

显然,在您的问题中使用strtok是不够的,还有另一个原因:如果您试图使用它来解析/etc/passwd文件或我们今天处理的类似格式的文件,您将在空字段中遇到麻烦。如果有一个连续两个:字符的空字段,strtok将跳过这两个字符,完全跳过未检测到的空字段strtok是一个旧的遗留函数,编写此函数是为了处理bourne shell中用于分隔参数的三个字符。对于/etc/passwd,您需要处理可能为空的字段,这使得无法使用strtok 来解析它们

您可以轻松地使用strchr以非跳过的方式搜索:of/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;
}
这个函数有strtok3的所有问题,但是您可以使用它来处理它的不可重入性,并且它修改源字符串,使它不能嵌套在多个循环中,因为它不会在一次跳过所有分隔符,而是在找到第一个分隔符后停止

为了解决嵌套问题,您可以采用另一种方式,假设您在/etc/group文件中有多个标识符,它们之间用空格分隔,这应该是需要的。但是,由于名称字段是最后一个字段,您不需要在第一个循环中再次调用strtok,而是要得到一个NULL。您可以以级别优先而不是深度优先的方式处理文件。首先查找第一级中的所有字段,然后逐字段读取可能使用不同分隔符的子字段

由于所有这些修改都是在同一个字符串中完成的,所以在使用之前不需要为每个字符串分配缓冲区并对字符串进行strdup。。。这项工作可以在同一个文件中完成,如果需要存储不同的子字段,可以在开始时对字符串进行strdup


如果您对此有疑问,请发表任何意见。请小心,因为我没有测试上述例程,它可能有错误

@KagurazakaKotori how?char*strtok_rchar*str,const char*delim,char**saveptr;使用strtok,您可以按“\n”解析行,然后再按;。当你拜访时;插入“\0”修改行,以便下次调用外部strtok时遇到“\0”时失败。使用重新进入版本。。。或者更好-使用非修改方法提取令牌,如一对指针和/或对strcspn和strspn或strpbrk、strchr等的调用解析所需的任何东西——为什么不在fgets中使用面向行的读取——都有点令人困惑……@David C.Rankin我不能使用fgets。我的阅读能力有限。。我如何解决这个问题?:/你能写出代码片段吗?@KagurazakaKotori how?char*strtok_rchar*str,const char*delim,char**saveptr;使用strtok,您可以按“\n”解析行,然后再按;。当你拜访时;插入“\0”修改行,以便下次调用外部strtok时遇到“\0”时失败。使用重新进入版本。。。或者更好-使用非修改方法提取令牌,如一对指针和/或对strcspn和strspn或strpbrk、strchr等的调用解析所需的任何东西——为什么不在fgets中使用面向行的读取——都有点令人困惑……@David C.Rankin我不能使用fgets。我的阅读能力有限。。我如何解决这个问题?:/你能写出代码片段吗?C.Rankin实际上我想要单独的值。Salt值和加密值。在你的回答中,它给了我一个单一的价值观——没问题。不客气。我只是在做另一件事。很高兴你把它整理好了。这是一种巧妙的方法。C.兰金实际上我想要单独的值。Salt值和加密值。在你的回答中,它给了我一个单一的价值观——没问题。不客气。我只是在做另一件事。很高兴你把它整理好了。这是一种巧妙的方式。