看板 C_and_CPP 關於我們 聯絡資訊
開發平台(Platform): (Ex: Win10, Linux, ...) Ubuntu 18.04 LTS 編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出) gcc 程式碼(Code):(請善用置底文網頁, 記得排版,禁止使用圖檔) https://ideone.com/jugcYC 重新上傳完整原始碼 補充說明(Supplement): 程式碼如以上連結 想請教版上各位先進 我的程式碼這一段是否出了什麼問題 這段code作用是這樣的 1. 我要寫一個自己用的CreateProcess() 在linux底下去call process起來做事 2. 中間是fork...exec 因為前面印出來就發現有問題了 我覺得應該是跟fork以後開始沒關係 3. 傳進來的參數 p_sAppName: process name p_sCmdArg: parameter, 以空白切割, 所以我會去呼叫一個自己寫的ParserCmd() 去把傳進來的參數去parser成一個vector<string> 把所有參數放裡面 ParserCmd()的結果我確定是對的所以忽略不貼 p_sEnvArg: 環境變數的參數, 作法如同上面的p_sCmdArg p_nRetVal: 在fork()...exec()這段拿來回傳呼叫process的成功或失敗 假設我今天call這個function的呼叫方式是這樣 MyCreateProcess("ffmpeg", "-vsync 0 -i file.cfg Compare.yuv"); p_sEnvArg/p_nRetVal有預設值NULL 我預計進入function後 1. 傳進來的p_sCmdArg, 會被ParserCmd()拆解然後存每一個cmd在vector裡面 2. 由於execve需要傳參數/環境變數型態為char**, 所以我先 char **ppCmdArg = new char*[vCmdSet.size() + 1]; 然後在迴圈中, 針對於每一個ppCmdArg[i], 我再 ppCmdArg[i] = new char[vCmdSet[i].length() + 1]; 由於參數不可能每個長度都相同 因此new出來的結果長度都不相同 3. 接下來我再把vector裡面儲存的參數字串拷貝到new出來的char* ppCmdArg[i] 4. 如果有傳環境變數我也是做一樣的處理 這次範例沒有可以無視 5. 接著就把ppCmdArg給execve當參數呼叫process 結果我發現程式在結束的地方 我做delete[] array出了問題 然後我把這段程式碼加了printf做debug 看到了無法理解的結果 輸出: -------------new-------------- ppCmdArg[0] = ffmpeg ppCmdArg[1] = -vsync ppCmdArg[2] = 0 ppCmdArg[3] = -i ppCmdArg[4] = file.cfg ppCmdArg[5] = Compare.yuv -------------new end-------------- -------------test 1-------------- ppCmdArg[0] = ffmpeg ppCmdArg[1] = (null) ppCmdArg[2] = (null) ppCmdArg[3] = -i ppCmdArg[4] = file.cfg ppCmdArg[5] = Compare.yuv ------------test 1 end-------------- ------------test 2-------------- ppCmdArg[0] = ffmpeg ppCmdArg[1] = (null) ppCmdArg[2] = (null) ppCmdArg[3] = -i ppCmdArg[4] = file.cfg ppCmdArg[5] = Compare.yuv -------------test 2 end-------------- vCmdSet size = 6 ppCmdArg[0] = ffmpeg ppCmdArg[1] = (null) ppCmdArg[2] = (null) ppCmdArg[3] = -i free(): invalid pointer Aborted (core dumped) 我new完, copy字串進去 可以正確printf 然後馬上在test 1區塊全部重印一次 結果ppCmdArg[1], ppCmdArg[2]變成NULL? 請教一下各位先進 是否我犯了什麼錯?或者gcc編譯的參數錯了嗎? 我用的是 -O2 -W -fPIC 先感謝各位了 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 210.242.38.175 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1605009218.A.846.html
nh60211as: ppCmdArg[vCmdSet[i].length()] = 0; 你這行是做什麼的 11/10 20:32
nh60211as: 還有你都寫C++了有什麼必要是要用C-style字串嗎 11/10 20:34
我把字串結尾設定為\0 您的意思是要怎麼用C++改寫比較好呢?
Lipraxde: L44、L62 在幹嘛?省略 code 可以,但是請弄一個 minim 11/10 20:42
L42就是我說的每一個char* ppCmdArg[i]去new char array L62一樣是把字串結尾設定為\0
Lipraxde: al working example 出來。不然看 code 還要腦補省略的 11/10 20:42
Lipraxde: 部分有沒有可能出問題很累,又不是在猜燈謎 = = 11/10 20:42
已經把完整code重新上傳 請多多指教 感恩 ※ 編輯: Keitaro (210.242.38.175 臺灣), 11/10/2020 21:22:06 ※ 編輯: Keitaro (210.242.38.175 臺灣), 11/10/2020 21:22:29
nh60211as: 字串的結尾是ppCmdArg[i][vCmdSet[i].length()] 11/10 21:28
ucrxzero: 58行 ppCmdArg[vCmdSet[i].length()] = 0; 11/10 21:28
ucrxzero: 錯兩個地方 11/10 21:28
stucode: 其實一樓已經說出問題所在了,L58 11/10 21:29
nh60211as: ppCmdArg[x]是char** ppCmdArg的第x個位置 11/10 21:29
ucrxzero: ppCmdArg[i][vCmdSet[i].length()] = \0; 11/10 21:29
ucrxzero: 不是0 是null才對 11/10 21:29
ucrxzero: 剛好其他人都有解出來請樓主幫我把整個有我的推文全刪 11/10 21:30
好喔
ucrxzero: 還有strcpy本來就會複製\0過去了 11/10 21:32
ucrxzero: 要不然strcpy這麼聰明就不會跟get一樣列為危險函示了 11/10 21:32
Lipraxde: 仔細對照一下 L56、L58、L61,再想想看 L58 真的有寫出 11/10 22:01
Lipraxde: 你想要的意思嗎? 11/10 22:01
Lipraxde: 當 i = 2 or 3 的時候 L58 做了什麼? 11/10 22:02
恍然大悟 唉我真的是蠢... 怎麼會這樣寫 看到樓上幾位的點名真的是覺得自己蠢到家了犯這種錯誤... 可見自己二維陣列的觀念生疏了QQ 非常感謝各位的指教 ※ 編輯: Keitaro (210.242.38.175 臺灣), 11/10/2020 22:13:53
Lipraxde: 另外 L110~L129 建議是拿 man waitpid 裡的範例來改 11/10 22:12
瞭解
nh60211as: 抱歉,看到後面的code應該真的只能用char**來寫 11/10 22:21
是的 我真的想不出其他寫法 他參數型態要求char**然後我要寫傳任意參數的 想來想去也只能這樣寫 ※ 編輯: Keitaro (210.242.38.175 臺灣), 11/10/2020 22:31:14
ucrxzero: C++寫法 (可過): vector<char*> char_vtr 11/10 23:40
ucrxzero: vector<char*> env_vtr 11/10 23:41
ucrxzero: execve(proc_name, &char_vtr, &env_vtr) 11/10 23:41
ucrxzero: execve(proc_name, &char_vtr[0], &env_vtr[0]) 11/10 23:42
ucrxzero: 但不建議使用 11/10 23:43
Killercat: 好像並不是所有的STL都保證data記憶體位置在前面 11/27 14:25
Killercat: 建議用std::vector::data取得資料段的pointer比較保險 11/27 14:25