Strtok 无限返回相同且不正确的字符串

Strtok returning the same and incorrect string infinitly

所以我正在研究 c 中的系统调用,我正在做这个练习,我必须制作一个简单的程序来搜索 PATH 中的文件(有点类似于 which Linux) 这就是我所做的:

int main(int ac, char **av)
{
    int i = 1;
    struct stat buf;
    char *_path, *token, *temp;

    if (ac < 2)
    {
        printf("Usage: %s path_to_file ...\n", av[0]);
        exit(-1);
    }
    while (i < ac)
    {
        if (stat(av[i], &buf) == 0)
        {
            printf("%s\n", av[i]);
        }
        else
        {
            _path = getenv("PATH");
            token = strtok(_path, ":");
            while (token != NULL)
            {
                temp = token;
                strcat(temp, "/");
                strcat(temp, av[i]);
                if(stat(temp, &buf) == 0)
                {
                    printf("%s\n", temp);
                    break;
                }
                token = strtok(NULL, ":");
            }
            printf("%s: no %s in (\"%s\")\n", av[0], av[i], _path);
        }
        i++;
    }
    return (0);
}

以下是我的问题:

$ ./_which ls
Segmentation fault (core dumped)

如果我加一个printf如下:

while (token != NULL)
{
    temp = token;
    strcat(temp, "/");
    strcat(temp, av[i]);
    printf("%s\n", temp);
    if(stat(temp, &buf) == 0)
    {
        printf("%s\n", temp);
        break;
    }
    token = strtok(NULL, ":");
}

然后我可以看到 strtok 从未返回 NULL 并且之后甚至没有返回正确的字符串。

$ ./_which ls
/ls/ls
/ls/ls
/ls/ls
/ls/ls
/ls/ls
/ls/ls
/ls/ls
/ls/ls
Segmentation fault (core dumped)

我已经仔细检查了如何使用 strtok,但找不到我的问题。

strtok 修改第一个参数,每次调用它时,都会将静态指针移到内部以指向传递的参数的另一部分。

所以当你这样做时

        temp = token;

它将 temp 设置为指向传递的数组中的子字符串,下次以 NULL 作为第一个参数调用它时,temp 将指向数组中的下一个子字符串,您不能使用从 strtok 返回的内容除了作为复制来源。

所以首先创建一个足够大的缓冲区来容纳整个路径。

char path[MAX_PATH+1]={'[=11=]'};

然后 strcat 到那个缓冲区。

 strcpy(path, token);
 strcat(path, "/");
 strcat(path, av[i]);

您的代码的另一个问题是更改从 getenv() 返回的内容。首先将其复制到缓冲区,然后在该缓冲区上调用 strtok

例如

 char* env = getenv("PATH");
 char* fullEnv = malloc(strlen(env)+1);  
 strcpy(fullEnv,env);
 // alternatively use
 // char* fullEnv=strdup(getenv("PATH"));

 token = strtok(fullEnv, ":");
 ...

 free(fullEnv);

最后的评论,不要声明带有前导下划线的变量,它主要用于内部编译器变量,可能会导致您很难找到问题。