2016-09-25 73 views
3

我正在写一个玩具bash外壳。我现在的目标是在环境中循环寻找特定命令的路径。现在我通过“:”分隔PATH(例如“/home/user/bin:home/user/.local/bin:/usr/local/sbin”等),并且对于每个给我的路径,复制路径到新字符串finalPath,然后将“/ cmd”连接到结尾。strtok()覆盖其源字符串

我的问题是,当我尝试将路径的内容复制到finalPath时,我对finalPath所做的任何更改都会反映到路径上。由于代码现在,path将只设置为“home/user/bin”一次,循环并重新设置为相同的事物,然后标记器点击“NULL”并终止while循环。

这表明pathfinalPath共享一个内存地址,但由于理论上strcpy的进行新的副本在内存中,我必须做一些错误与我的琴弦和指针。

任何想法是什么导致这种意外的行为?

编辑:此代码执行时,我注释掉的strcpy

我的代码的精简版本,正如预期低于:

int findpath(char* cmd, command_t* p_cmd) { 
    char* path_var; 

    path_var = getenv("PATH"); 

    char* path; 
    char tempEnv[sizeof(path_var)]; 
    strcpy(tempEnv, path_var); 
    path = strtok(tempEnv, ":"); 

    while(path != NULL) { 
     char fullPath[1000]; 
     strcpy(finalPath, path); 
     printf("path: %s\n", path); 
     printf("finalPath: %s\n", finalPath); 
     path = strtok(NULL, ":"); 
    } 
+3

是的,'strtok'确实改变了源字符串。这是记录的行为。 – alain

+3

'sizeof(path_var)'不是'path_var'的长度。它是指针大小。 – BLUEPIXY

+0

Strtok改变源字符串是好的,这是strcpy我很困惑。编辑:一些澄清是,当我注释掉strcpy时,此代码循环良好 – teleTele

回答

3

BLUEPIXY是正确的:tempEnv不够大为你的字符串。尝试:

char *tempEnv; 
tempEnv = malloc(strlen(path_var)+1); 
strcpy(tempEnv, path_var); 

,并在年底

free(tempEnv); 

条件是这是千疮百孔。您应该使用更安全的字符串函数,例如,如here所述。例如,使用strnlen来强制对path_var的长度设置一些合理的限制。确保path_var在该限制内以NULL结尾。使用strncpy而不是strcpy。必要时在strncpy之后添加NULL。还有其他一些规则,我不在这里列出,因为你的目标似乎是学习而不是生产代码。快乐黑客!

+0

在什么情况下,您认为'path_var'可能不是空终止?该程序如何说明?我没有发现这个警告远程引人注目 - 来自'getenv()'的输出是一个以空字符结尾的字符串。使用'strncpy()'是一个混杂的包 - 当源比目标长时,它不能保证空终止,并且当源比目标短时,它保证空填充的全长。 '这是一个奇怪的功能;这不是对安全问题的普遍回答(尽管如果你小心的话可以安全地使用它)。 –

+1

'char tempEnv [strlen(path_var)+1];'也很好 –

+0

@JonathanLeffler编辑澄清。我试图得到的是'while(* C++)i ++;''''c'不在程序的控制下时是个坏主意。无论如何,我同意这个答案在安全字符串操作方面是不完整的---我把这一点留给那些比我有更多经验的人。 :) – cxw