2016-05-26 4 views
5

मैं मुख्य रूप से की व्यवहार्यता में रुचि रखता हूं इस तरह की एक सरणी।एक गतिशील आवंटित 2 डी सरणी पर realloc() का उपयोग कर रहा है एक अच्छा विचार?

मैं एक ऐसे प्रोजेक्ट पर काम कर रहा हूं जहां मैंने एकल मॉलोक() कॉल का इस्तेमाल प्रत्येक व्यक्ति को सामान्य रूप से बड़े 2 डी सरणी बनाने के लिए किया है। (एमआईबी का केवल कुछ ही मिनट, सबसे बड़ा है।) बात यह है कि एक सरणी के जीवन में, इसकी सामग्री नाटकीय रूप से आकार में आधा हो जाती है (आधा से अधिक)। जाहिर है, मैं कार्यक्रम के जीवन के लिए अकेले सरणी आकार छोड़ सकता था। (यह केवल x एमआईबी रैम के जीबीबी के साथ एक सिस्टम पर उपलब्ध है।) लेकिन, हम कार्यक्रम समाप्त होने से पहले आवंटित आवंटित स्थान के आधे से अधिक के बारे में बात कर रहे हैं, और, मैं कैसे हूं सरणी का उपयोग करके, सभी जीवित डेटा पंक्तियों के एक संगत सेट (ब्लॉक की शुरुआत में) में रखा जाता है। ऐसा लगता है कि अगर मुझे वास्तव में इसकी ज़रूरत नहीं है तो वह रैम पर पकड़ने के लिए एक अपशिष्ट की तरह लगता है।

जबकि मुझे पता है कि realloc() गतिशील रूप से बनाए गए सरणी को कम करने के लिए उपयोग किया जा सकता है, एक 2 डी सरणी अधिक जटिल है। मुझे लगता है कि मैं इसके मेमोरी लेआउट को समझता हूं (जैसा कि मैंने इसे कार्यान्वित करने वाले फ़ंक्शन को कार्यान्वित किया है), लेकिन यह भाषा की मेरी समझ और उसके कंपाइलरों के कामकाज की सीमा को दबा रहा है। जाहिर है, मुझे पंक्तियों के साथ काम करना होगा (और पंक्ति बिंदुओं से निपटना होगा), न केवल बाइट्स, बल्कि मुझे नहीं पता कि यह सब के परिणाम कितने अनुमानित होंगे।

और, हाँ, मुझे एक एकल malloc() के साथ सरणी बनाने की आवश्यकता है। प्रश्न में वस्तु में कई मिलियन पंक्तियां हैं। मैंने प्रत्येक पंक्ति को अलग-अलग malloc() में लूप का उपयोग करने का प्रयास किया, लेकिन कार्यक्रम हमेशा लगभग 100,000 malloc() s पर जम गया।

char ** alloc_2d_arr(int cnum, int rnum) { 
     /* ((bytes for row pointers + (bytes for data)) */ 
     char **mtx = malloc(rnum * sizeof (char *) + rnum * cnum * sizeof (char)); 

     /* Initialize each row pointer to the first cell of its row */ 
     char *p = (char *) (mtx + rnum); 
     for (int i = 0; i < rnum; i++) { 
       mtx[i] = p + i * cnum; 
     } 

     return mtx; 
} 
+2

'realloc' ऐसी बड़ी तालिकाओं के लिए एक अच्छा विचार नहीं है, "avl" और "लाल-काले" पेड़ों को देखें। –

+1

"अगर मुझे वास्तव में इसकी आवश्यकता नहीं है तो यह रैम पर पकड़ने के लिए एक अपशिष्ट की तरह लगता है।" - पहला * प्रोफ़ाइल *।दूसरा, एक पुनर्विक्रय आपके सभी अभी भी आंतरिक डेटा को अलग-अलग पृष्ठों पर प्रतिलिपि बनाने का उच्च जोखिम चलाता है, गैर-मामूली व्यय जिसमें आप पूरी तरह से राम को बचाने की कोशिश करने के कारण होते हैं, आप दावा करते हैं कि वास्तव में कोई समस्या नहीं है। यहां एकमात्र जीत-परिदृश्य 'रीयलोक' है जो उसी क्षेत्र-सिर को आपके मेमोरी बेस के रूप में रखता है, और अन्य उपयोग के लिए पूंछ-पृष्ठ लौटाया जाता है; कुछ 'realloc' के बारे में कोई गारंटी नहीं है .... – WhozCraig

+0

... तो क्या आपने इसके बजाय केवल 2 (या 3 या 4, जो भी) आवंटन करना है, याद रखें कि आप अंततः कौन से हैं, और 'मुक्त() '- एक बार उस घटना को पार करने के बाद आपको अब आवश्यकता नहीं है? अर्थात। आपके मैट्रिक्स का "रखा" आधा पहले आवंटन में है, दूसरा आधा दूसरे आवंटन में है, और अंततः आप दूसरे छमाही को मुक्त करते हैं। – WhozCraig

उत्तर

2

बहुआयामी सरणियों का उपयोग करना, इस के साथ या चर लंबाई सरणियों की ओर इशारा बिना किया जा सकता:

पृष्ठभूमि के लिए, स्रोत मैं इन सरणी के निर्माण के लिए उपयोग कर रहा हूँ इस प्रकार है। चूंकि आप शायद कोई अतिरिक्त मेमोरी आवंटित नहीं करना चाहते हैं, यह जगह पर किया जाएगा।

int (*array)[10] = malloc(sizeof(int) * 20 * 10); 
for(size_t i = 0 ; i < 20 ; i++) 
    for(size_t j = 0 ; j < 10 ; j++) 
      array[i][j] = i * 100 + j; 

आप पंक्तियों की संख्या बदलना चाहते हैं, कोई तत्वों को स्थानांतरित किया जाना है, केवल एक realloc की जरूरत है:

पहले 10 से 20 सरणी का आवंटन। पंक्ति गणना को 15 में बदलना मामूली है:

array = realloc(array , sizeof(int) * 15 * 10); 

यदि आप कॉलम गिनती बदलना चाहते हैं, तो तत्वों को स्थानांतरित करना होगा। चूंकि हमें पहले कॉलम की प्रतिलिपि बनाने की आवश्यकता नहीं है, इसलिए प्रतिलिपि दूसरे पर शुरू होती है। मेमोरी ओवरलैप से बचने के लिए फंक्शन मेममोव का उपयोग किया जाता है, जो इस मामले में नहीं हो सकता है, लेकिन अगर नई कॉलम गिनती बड़ी हो तो यह हो सकता है। इसके अलावा यह एलियासिंग समस्याओं से बचाता है। ध्यान दें कि यह कोड केवल इसलिए परिभाषित किया गया है क्योंकि हम आवंटित स्मृति का उपयोग कर रहे हैं।

int (*newarray)[3] = (int(*)[3])array; 
for(size_t j = 1 ; j < 15 ; j++) 
    memmove(newarray[j] , array[j] , sizeof(int) * 3); 
newarray = realloc(array , sizeof(int) * 15 * 3); 

कार्य उदाहरण: https://ideone.com/JMdJO0

नया स्तंभ संख्या वर्ष से बड़ा होता है, तो स्मृति पहले पुनः आवंटन करना होगा (करने के लिए बस मिल के स्तंभ से 3 गिनती बदल दें अधिक जगह), और उसके बाद कॉलम प्रतिलिपि, अंतिम कॉलम से शुरू होने के बजाय होगी।

+0

यह मुझे स्वीकार करने के लिए शर्मिंदा करता है, लेकिन मुझे 'int (* सरणी) [10] = malloc (...);' समझने में परेशानी हो रही है। सी की स्पष्ट रूप से कम समझ के आधार पर, ऐसा लगता है कि एक नवनिर्मित चर को प्रारंभिक सूचक के साथ पहचानकर्ता के रूप में शुरू किया गया है। यह एक तिहाई पॉइंटर (दो बार) को कम करने और उस पर malloc() आउटपुट देने के लिए एक बात होगी, लेकिन सामने एक प्रकार डालने से यह एक राम पते की तरह दिखता है जो प्रतीक के रूप में उपयोग किया जा रहा है (जो समझ में नहीं आता है) । मुझे लगता है कि मैंने देखा कि जब भी मैं सी सीख रहा था, लेकिन प्रासंगिक शब्दों को गुगल करने से प्रदूषित परिणाम मिलते हैं। – CircleSquared

+0

@CircleSquared यह एक बहुआयामी सरणी के लिए एक सूचक है। मेरे उदाहरण में दो आयाम। इस तरह: 'int [7] [9]; int (* pa) [9] = ए; ', मेरे उदाहरण को छोड़कर मैं पॉइंटर को स्वचालित सरणी पर इंगित नहीं करता, लेकिन आवंटित स्मृति के लिए। – 2501

+0

मुझे अपने प्रश्न का उत्तर देने के लिए ** एक बहुआयामी सरणी ** गतिशील रूप से आवंटित करने के लिए एक और अधिक प्रभावी तरीका दिखाने के लिए धन्यवाद। * तो, यह काफी सुरक्षित है, लेकिन यह सरणी सेट अप करने का एक बेहतर तरीका है। * – CircleSquared

संबंधित मुद्दे