Re: [討論] 面試有鑑別度的問題??

看板C_and_CPP作者 (閉上眼的魚)時間11年前 (2013/01/12 23:12), 編輯推噓0(000)
留言0則, 0人參與, 最新討論串14/14 (看更多)
避免原文愈回愈亂, 恕開文回覆。首先我要講的是,原文裡給的 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)
文章代碼(AID): #1GyNrNlt (C_and_CPP)
討論串 (同標題文章)
文章代碼(AID): #1GyNrNlt (C_and_CPP)