Re: [問題] qsort compare 與 strcmp 轉型問題

看板C_and_CPP作者 (-858993460)時間13年前 (2012/03/17 22:24), 編輯推噓1(102)
留言3則, 1人參與, 最新討論串2/2 (看更多)
※ 引述《manoeuvre (策)》之銘言: : qsort 的參數4 沒辦法直接丟 strcmp 進去, : 是因為型態的問題嗎?還是兩個 compare 比較對象不同? : ---- : QSORT(3) FreeBSD Library Functions Manual QSORT(3) : void : qsort(void *base, size_t nmemb, size_t size, : int (*compar)(const void *, const void *)); : STRCMP(3) FreeBSD Library Functions Manual STRCMP(3) : int : strcmp(const char *s1, const char *s2); : ---- : 原本的想法是 : qsort 的參數 要傳的 compare function 參數型態是 (const void *, const void *) : strcmp 的參數型態是 (const char *, const char *) : 所以參數要從 void 換成 char : 不過不知道怎麼轉型這種函式庫的 function ,所以 Google 出這個: : http://twpug.net/docs/ccfaq/node228.html : ---- : int pstrcmp(const void *p1, const void *p2) : { : return strcmp(*(char * const *)p1, *(char * const *)p2); : } : ---- : 不過看到這裡,感覺像不只是 void -> char 的問題而已 : 看很久看不懂 return strcmp(*(char * const *)p1, *(char * const *)p2); : 的意義為何..... 網頁好像一堆大陸用語,也看不太懂..... : 意思是不是,qsort 和 strcmp 的比較對象不同? : 所以要另外生一個用指標指向字串的 compare function? : 那行轉型的邏輯也搞不清楚... : 另外,這麼看來每次要用 qsort 時 compare function 都要自己寫一個來轉型才行囉? : 原本系統裡的函式庫是不是都無法直接塞入 qsort? : 抱歉問題很多,謝謝解惑! 嚴格說來, void * 和 char * 是「兩種」指標 標準只保證說你像上面 pstrcmp 這樣明寫著轉型時能夠轉得過去 因此如果要寫 portable 的程式的話 使用類似上面這個 pstrcmp 這種才是正道 這個 pstrcmp 所使用的情境是 那個要排序的字串陣列裡面存放的是指向每個字串的指標 (也就是說是個指標的陣列 每個元素是個指標 指向字串) 也就是說這 qsort 的呼叫是長得這樣: char *strarray[MAX]; ... qsort(strarray, count, sizeof(char *), compare); 這麼一來 由 qsort 傳進 pstrcmp 的 p1 p2 這兩個指標會是那個陣列上的位置 那將是個指向一個 char * 的指標 於是我們必須將其傳入的 const void * 轉型成 char * const * 再提取之才能得到字串 這便是那一行的意義了 有的時候 (我想這才是你的問題) 字串陣列是直接使用字元的二維陣列表示的 這時 qsort 的呼叫會長得像這樣: char strarray[MAX][MAXLEN]; ... qsort(strarray, count, sizeof(strarray[0]), compare); 第三個參數表示這二維陣列的每一列多大 在上行的情形裡就會是 MAXLEN 這時的 compare 是這樣寫的: int compare(const void *p1, const void *p2) { return strcmp((const char *)p1, (const char *)p2); } 一樣的道理 由於 qsort 傳進 compare 的 p1 p2 會是指向 strarray 的一列的指標 因此直接將它轉型成 const char * 即是我們的字串了 照理來說啦 這裡理應也要寫個像這樣的 compare 函式 不過有些人(如原 PO)會想要把 strcmp 直接塞進 compare 的位置 (扯了一長串總算回到原題了...) 這樣的 hack 是有的 由於 strcmp 根本就只是拿兩個指標當參數 因此如果讓 strcmp 直接收 qsort 傳進去的那兩個 const void * 指標的話 只要「把 const void * 指標的樣子直接當成 const char * 來解釋」行得通的話 (用 C++ 的話來說就是: 若 compare 函式裡的 const void *p1 滿足 (p2 亦同) reinterpret_cast<const char *>(p1) == static_cast<const char *>(p1) (直接硬解為 const char *) (正常轉型成 const char *) 這個等號的話) 那 strcmp 就能如你所想的工作 這麼的話 要做的事情就是把 strcmp 假裝成 int (*)(const void *, const void *) 這個型態的函式指標 (它正是 qsort 第四個參數的型態) 也就是 (int (*)(const void *, const void *))strcmp 把上面這一串丟到 qsort 的第四個參數去 實際上 compiler 在編譯時認為這樣轉過去應該沒什麼問題 就會直接把 strcmp 的位址丟進去給 qsort 於是就這樣什麼事都沒有 工作完成了 不過這個 hack 要有上面這個條件成立才行 (雖然一些常見平台是都成立的沒錯啦...) 因此嚴格說來這只能算是 hack 不是個 portable 的寫法 要 portable 的話還是乖乖寫 compare 函式吧 (因為很重要所以要說兩次(爆 -- 1985/01/12 三嶋鳴海 1989/02/22 優希堂悟 1990/02/22 冬川こころ 1993/07/05 小町 つぐみ 歡迎來到 1994/05/21 高江ミュウ 1997/03/24 守野いづみ 1997/03/24 伊野瀬 チサト 1998/06/18 守野くるみ 打越鋼太郎的 1999/10/19 楠田ゆに 2000/02/15 樋口遙 2002/12/17 八神ココ 2011/01/11 HAL18於朱倉岳墜機 ∞與∫的世界 2011/04/02 茜崎空 啟動 2012/05/21 第貮日蝕計畫預定 2017/05/01~07 LeMU崩壞 2019/04/01~07 某大學合宿 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.112.28.91

03/18 03:24, , 1F
謝謝回答 雖然還是不懂.可能是我不懂char*const*的意思.
03/18 03:24, 1F

03/18 03:26, , 2F
另外.我是傳指標陣列沒錯, 所以原來的pstrcmp寫法會過
03/18 03:26, 2F
其實把 const 拿掉出現的東西你應該比較熟悉: char ** 就是個指向 char * 的指標 加 const 在那表示這個指標指向的東西不能變動 其實這樣對比就清楚了: const void * ==等同於== void const * 指標指向不知啥 但不能變動它 char * const * 指標指向char * 但不能變動它 然後也因為 qsort 有間接這一層的關係 (qsort 傳入比較函式的是指向欲比較元素的 const void * 指標) 這就不能使用文中所述的那個 hack 了 而必須要另寫一個比較函式出來 ※ 編輯: LPH66 來自: 140.112.28.91 (03/18 15:33)

03/20 02:59, , 3F
謝謝 還是好難懂 XD 我會再想想的!!!
03/20 02:59, 3F
文章代碼(AID): #1FP9woq8 (C_and_CPP)
文章代碼(AID): #1FP9woq8 (C_and_CPP)