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);
最后的评论,不要声明带有前导下划线的变量,它主要用于内部编译器变量,可能会导致您很难找到问题。
所以我正在研究 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);
最后的评论,不要声明带有前导下划线的变量,它主要用于内部编译器变量,可能会导致您很难找到问题。