Re: [討論] 面試有鑑別度的問題??
避免原文愈回愈亂, 恕開文回覆。首先我要講的是,原文裡給的 code 是「故意給那麼醜
的」,留下思考空間。然後為了統一討論、避免 code 過冗長,假設要配置動態如下
int func() {
T1 arr1[h1];
T2 arr2[h2][w2];
T3 arr3[h3][w3];
}
請考慮實際上不只 3 個,維度也不盡相同。另回覆多,下面的 code 沒跑過,若有筆誤
請不吝指正,覺得解得不好的話也歡迎指正批判,謝謝。
---- 引言回覆時間 ---
[1] Allocate Once , Concate each pointers
→ loveme00835:http://ideone.com/IWKiYe 迴圈裡做的事情愈單純愈單 01/12 15:19
→ loveme00835:好, 你本來迴圈做的事情有兩個: (1) 串接指標 (2) 配 01/12 15:20
→ loveme00835:置記憶體, 所以一旦要考慮釋放, 當然也會在迴圈裡面作 01/12 15:21
沒錯,我想過其中一版的解決方案就是如此。一次把所有配置都做完,再一次配接,
然後接動作頻繁,所以再寫 sub-func 專門做 concate
/* 做二維記憶體連接動作, 最後傳回,接完後整份空間的 char * end */
char * concate2(void * beg, int w, int h , int Type_size)
{
int i ;
char ** ptr = (char**)beg;
char * space = ptr + w;
for(i=0; i<w; ++i) {
ptr[i] = space;
space += TypeSize * h;
}
return (void*)space;
}
concate1(一維) 個人覺得是可以用 #define 方便維護, 有必要時寫 concate3(三維),
而在 func 裡時變如此
/* 下面算空間用 #define macro 應較佳 */
size_t size1 = sizeof(T1) * w1;
size_t size2 = sizeof(T2*) * w2 + sizeof(T2) * h2 * w2;
size_t size3 = sizeof(T3*) * w3 + sizeof(T3) * h3 * w3;
/* 配置與串接 */
char *beg, *pool = (char*)malloc(size1+size2+size3);
if(!pool) return;
beg = pool;
arr1 = (T1* )beg, beg+=size1 ; // arr1[w1]
arr2 = (T2**)beg, beg = concate2(arr2, w2, h2, sizeof(T2)); // arr2[w2][h2]
arr3 = (T3**)beg, beg = concate3(arr3, w3, h3, sizeof(T3)); // arr3[w3][h3]
/* 釋放時 */
free((void*)pool);
這種撰碼方式優點二個,避開碎片化、不會 if(!ptr) everywhere,但也有缺點
(1) 若需 re-alloc 時,必須整塊 re-alloc,然後指標的連接要再重新接過。
(2) 指標的連接算 addr 時,維護比較雜一點,眼花時就出包了。
---
→ loveme00835:也不要用C++編譯器去編C code, 用什麼編譯器表示你寫 01/12 15:26
→ loveme00835:什麼語言, 不是取決於你用的關鍵字跟標頭檔 01/12 15:26
這兩點完全同意。
推 andyjy12:用一個int作標記,記錄在a6失敗 然後用switch 6->5->4... 01/12 15:33
→ suhorng:原本還想說用 static linked-list 串起來, 再迴圈釋放掉 01/12 15:35
這兩個方法都很有創意,而且都是好的方案,謝謝提供 :)
---
[2] goto
第一種方法我是認為維護上在算 addr 時很麻煩,而且 re-alloc 時花的成本大,
所以用 goto 去解。goto 本質上和 andyjy12 說的概念是一樣的,只是用到的是
寫 batch 的技巧。
void * alloc2(int w, int h, int ele_size)
{
int i;
char * trunk;
char ** ptr = (char**)malloc(sizeof(char*) * w + h*w*size);
if(!ptr) return NULL;
for(trunk = ptr + w, i=0; i<w ; ++i)
ptr[i] = trunk, trunk+=w*ele_size;
return (void*)ptr;
}
func 裡
int func() {
T1 * arr1 ;
T2 ** arr2 ;
T3 ** arr3 ;
if(! (arr1 = (T1*)malloc(sizeof(T1) * w1)) goto E1;
if(! (arr2 = (T2**)alloc2(w2, h2, sizeof(T2)) goto E2;
if(! (arr3 = (T3**)alloc3(w3, h3, sizeof(T3)) goto E3
/* ... whatever ... */
END: free( (void*) arr3);
E3: free( (void*) arr2);
E2: free( (void*) arr1);
return 1;
}
---
[3] catch allocate fail.
推 purpose:有人說通常情況是,還沒配置失敗,使用者就主動關程式了 01/12 16:37
→ purpose:也有人說,Linux不會malloc 失敗,因為有什麼 OOM killer 01/12 16:37
感謝 p 大的回覆 :) 這裡我想已是 team-code-style 問題 ? 聽過下面四種處理方式
(1) 連 allocate fail 不用抓,反正 error 由 user 退和由 sys 退最後結果都一樣。
(2) allocate fail 抓,抓到後直接 log to file, 再退。
(3) allocate fail 時跳出警告訊息,請用戶關閉其他記憶體大的 ap,該存的存一存,
最後再退
(4) 一開始先挖個 char garbge[REV_SIZE] 到 heap 不用它, allocate fail 時
先跳警告,該存的先存一下;再 fail 時作法再用第三種方案。
第四個方案個人是覺得有爭議,但這方案忘了是出現在哪本講 C 技巧的書裡面。
真正要怎麼處理 - 說真的我沒看過一種統一的講法,也可能是系統對於 alloc.
fail. catch 要求嚴謹度會因情況而有所不同。
→ purpose:反正我個人經驗上,Windows Linux 都還沒碰過 malloc 失敗 01/12 16:38
推 andyjy12:要單塊過大的記憶體會有失敗 01/12 16:47
可能一般人較寫少這些領域 : data mining , large data-base ,
要在一般 user PC 上運作這兩個領域的相關運算,allocated fail 小弟覺得機率不低。
< 記得影像處理要快的話,需要的 memory space 也不低 ? >
→ linotwo:每個矩陣配置一塊 http://ideone.com/DlKNRP 01/12 20:03
→ linotwo:如果能把矩陣元素的型態抽象化的話 code 應該會精簡許多 01/12 20:06
linotwo 大處理的方式好特別,我還在研究最上面的 #define @@
----
敘述至此,其實又留下了一些討論空間,若文章有誤,或做法不好的,歡迎不吝回覆指正
,謝謝各位收聽。
--
~ 這輩子與神手無緣
我只好當神獸了 ~
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 180.177.76.161
※ 編輯: EdisonX 來自: 180.177.76.161 (01/12 23:20)
討論串 (同標題文章)