2012-05-13 12 views
48

के साथ आवंटित सरणी प्रकार और सरणी के बीच अंतर आज मैं कुछ सी कोड के साथ अपने एक दोस्त की मदद कर रहा था, और मुझे कुछ अजीब व्यवहार मिला है कि मैं उसे समझा नहीं सकता था कि यह क्यों हो रहा था। हमारे पास प्रत्येक पंक्ति में int के साथ पूर्णांक की एक सूची के साथ टीएसवी फ़ाइल थी। पहली पंक्ति सूची की लाइनों की संख्या थी।मॉलोक

हमारे पास एक बहुत ही सरल "readfile" के साथ एक सी फ़ाइल भी थी। पहली पंक्ति n को पढ़ रहा था, लाइनों की संख्या है, तो वहाँ के एक प्रारंभ किया गया था:

int list[n] 

और अंत में एक एक fscanf के साथ n के पाश के लिए।

छोटे एन (तक ~ 100.000) के लिए, सबकुछ ठीक था। हालांकि, हमने पाया है कि जब एन बड़ा था (10^6), एक segfault होगा।

अंत में, हम सूची प्रारंभ

int *list = malloc(n*sizeof(int)) 

और सब कुछ करने के लिए जब अच्छी तरह से भी बहुत बड़ी n के साथ बदल गया है,।

क्या कोई यह समझा सकता है कि ऐसा क्यों हुआ? int सूची [n] के साथ segfault का कारण क्या था, जब हम सूची = malloc (n * sizeof (int) का उपयोग शुरू करते हैं तो रोक दिया गया था?

उत्तर

109

यहां खेलने पर कई अलग-अलग टुकड़े हैं।

पहले के रूप में

int array[n]; 

और

int* array = malloc(n * sizeof(int)); 

पहले संस्करण में एक सरणी की घोषणा के बीच का अंतर है, तो आप स्वत: भंडारण अवधि के साथ एक वस्तु की घोषणा कर रहे हैं। इसका मतलब है कि सरणी केवल तब तक रहती है जब तक कि यह कार्य मौजूद न हो। दूसरे संस्करण में, आपको गतिशील भंडारण अवधि के साथ स्मृति मिल रही है, जिसका अर्थ यह है कि यह तब तक अस्तित्व में रहेगा जब तक इसे free के साथ स्पष्ट रूप से अस्वीकार नहीं किया जाता है।

कारण यह है कि दूसरा संस्करण यहां काम करता है यह एक कार्यान्वयन विवरण है कि सी को आम तौर पर कैसे संकलित किया जाता है। आम तौर पर, सी मेमोरी को कई क्षेत्रों में विभाजित किया जाता है, जिसमें स्टैक (फ़ंक्शन कॉल और स्थानीय चर के लिए) और ढेर (malloc एड ऑब्जेक्ट्स के लिए) शामिल हैं। ढेर में आमतौर पर ढेर की तुलना में बहुत छोटा आकार होता है; आमतौर पर यह 8 एमबी की तरह कुछ है। नतीजतन, आप segfault के कारण

int array[n]; 

साथ एक विशाल सरणी आवंटित करने के लिए तो फिर तुम ढेर के भंडारण स्थान से अधिक जा सकता कोशिश, अगर। दूसरी तरफ, ढेर में आमतौर पर एक बड़ा आकार होता है (कहें, जितना अधिक स्थान सिस्टम पर मुफ़्त है), और इसलिए malloc एक बड़ी वस्तु में आईएनजी से बाहर की त्रुटि त्रुटि नहीं होगी।

सामान्य रूप से, सी में परिवर्तनीय-लंबाई सरणी से सावधान रहें। वे आसानी से ढेर आकार से अधिक हो सकते हैं। malloc पसंद करें जब तक आपको पता न हो कि आकार छोटा है या आप वास्तव में केवल थोड़े समय के लिए सरणी चाहते हैं।

आशा है कि इससे मदद मिलती है!

+1

बहुत स्पष्ट जवाब ... धन्यवाद! –

+1

महान जवाब! मैं सोच रहा था कि गति में कोई अंतर है या नहीं? –

+1

संदर्भ के इलाके के प्रभावों के कारण मुझे संदेह होगा कि स्टैक-आवंटित सरणी पहुंचने के लिए तेज़ है, और 'मॉलोक' केवल एक स्टैक पॉइंटर को बंपिंग करने से बहुत धीमी है। लेकिन वास्तव में, काम के लिए जो भी दृष्टिकोण अधिक उपयुक्त है उसका उपयोग करना सबसे अच्छा है। – templatetypedef

2

int list [n] स्टैक में डेटा स्टोर करता है, जबकि मॉलोक इसे ढेर में संग्रहीत करता है।

ढेर सीमित है, और वहां बहुत अधिक जगह नहीं है, जबकि ढेर बहुत बड़ा है।

1

int list[n] एक वीएलए है, जो ढेर के बजाय ढेर पर आवंटित करता है। आपको इसे मुक्त करने की आवश्यकता नहीं है (यह फ़ंक्शन कॉल के अंत में स्वचालित रूप से मुक्त हो जाती है) और यह जल्दी से आवंटित हो जाती है लेकिन स्टोरेज स्पेस बहुत सीमित है, जैसा आपने पाया है। आपको ढेर पर बड़े मूल्य आवंटित करना होगा।

1

इस घोषणा ढेर

int list[n] 

malloc ढेर पर आवंटित पर स्मृति आवंटित करता है।

ढेर आकार आमतौर पर ढेर से छोटा होता है, इसलिए यदि आप ढेर पर बहुत अधिक स्मृति आवंटित करते हैं तो आपको एक स्टैक ओवरफ्लो मिलता है।

भी देखें this answer for further information

0

जब आप एक malloc का उपयोग कर आवंटित स्मृति ढेर से और ढेर है, जो बहुत अधिक आकार में सीमित है से नहीं आवंटित किया जाता है। पर n पूर्णांकों ढेर, जो आमतौर पर बहुत छोटा है के लिए

8
int list[n] 

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

दूसरी ओर mallocढेर, जो आमतौर पर ढेर की तुलना में बहुत बड़ी है में अंतरिक्ष आवंटित करता है।आपको इसे निकालने के लिए ढेर पर बहुत अधिक मात्रा में स्मृति आवंटित करनी होगी, लेकिन ढेर पर स्मृति की आवृत्ति को आवंटित करने के लिए यह बहुत धीमी है, और जब आप इसका उपयोग कर रहे हैं तो आपको इसे free के माध्यम से मैन्युअल रूप से डिलीकेट करना होगा यह।

+1

"स्टैक पर स्मृति का उपयोग वैकल्पिक से बहुत तेज़ है", क्या आपका मतलब "आवंटन" या "एक्सेसिंग" से है? AFAIK, स्टैक आवंटन बहुत तेज है, लेकिन क्या यह भी पहुंच (पढ़ने/लिखने) के लिए सच है? धन्यवाद – dragonxlwang

1

मान लिया जाये कि आप अपने कार्यान्वयन में एक विशिष्ट कार्यान्वयन है यह सबसे अधिक संभावना है कि:

int list[n] 

अपने ढेर पर आवंटित सूची है, जहां के रूप में: अपने ढेर पर

int *list = malloc(n*sizeof(int)) 

आबंटित स्मृति।

स्टैक के मामले में आम तौर पर यह बढ़ने की सीमा है कि ये कितने बड़े हो सकते हैं (यदि वे बिल्कुल बढ़ सकते हैं)। एक ढेर के मामले में अभी भी एक सीमा है, लेकिन यह आपके रैम + स्वैप + एड्रेस स्पेस से काफी हद तक और (व्यापक रूप से) बाधित होता है जो आमतौर पर कम से कम परिमाण का क्रम होता है, यदि अधिक नहीं होता है।

0

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

आम तौर पर, ढेर बड़े स्मृति आवंटन के लिए उपयोग किया जाना चाहिए।

0
int array[n]; 

यह स्थिर आवंटित सरणी का एक उदाहरण है और संकलन समय पर सरणी का आकार ज्ञात होगा। और सरणी ढेर पर आवंटित किया जाएगा।

int *array(malloc(sizeof(int)*n); 

यह गतिशील रूप से आवंटित सरणी का एक उदाहरण है और सरणी का आकार रन टाइम पर उपयोगकर्ता को ज्ञात होगा। और सरणी ढेर पर आवंटित किया जाएगा।

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