2016-09-25 44 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