2010-12-04 16 views
26

मुझे पता है कि यह malloc का उपयोग करके किया जा सकता है, लेकिन मुझे नहीं पता कि अभी तक इसका उपयोग कैसे किया जाए।मैं अपरिभाषित या प्रारंभिक आकार की सरणी कैसे घोषित करूं?

उदाहरण के लिए, मैं चाहता था कि उपयोगकर्ता एक सेंटीनल के साथ एक अनंत लूप का उपयोग करके कई संख्याओं को इनपुट करने के लिए इनपुट करें (यानी -1), लेकिन चूंकि मुझे अभी तक पता नहीं है कि वह कितना इनपुट करेगा, मैं। प्रारंभिक आकार के साथ एक सरणी घोषित करना है, लेकिन मुझे यह भी पता है कि यह इस int arr की तरह काम नहीं करेगा []; संकलन समय पर क्योंकि इसमें तत्वों की एक निश्चित संख्या होनी चाहिए।

तरह पूर्णांक आगमन [1000] एक अतिरंजित आकार के साथ यह घोषणा; काम करेगा, लेकिन यह गूंगा (और अपशिष्ट स्मृति के बाद से यह आवंटन होगा 1000 पूर्णांक स्मृति में बाइट्स) लगता है और मैं एक अधिक सुरुचिपूर्ण तरीका यह है पता करना चाहते हैं।

+0

'malloc' के बारे में कैसे? Arrays पॉइंटर्स नहीं हैं, और पॉइंटर्स सरणी नहीं हैं। लेकिन पॉइंटर्स को आसानी से सरणी की तरह एक्सेस किया जा सकता है और एक वर्णित सरणी पहले तत्व को पॉइंटर को मूल्यांकन करती है। –

+2

@pst: क्या आपने सवाल बिल्कुल पढ़ा था? "मुझे पता है कि यह मॉलोक का उपयोग करके किया जा सकता है, लेकिन मुझे नहीं पता कि इसका अभी तक उपयोग कैसे किया जाए।" –

+0

मैंने सर को बताया कि मुझे इसके बारे में पता है, लेकिन मुझे नहीं पता कि इसका उपयोग कैसे किया जाए, यह बताएं कि मेरे लिए सबसे अच्छा जवाब कैसे होगा: डी – arscariosus

उत्तर

25

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

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(int argc, char** argv) 
{ 
    /* declare a pointer do an integer */ 
    int *data; 
    /* we also have to keep track of how big our array is - I use 50 as an example*/ 
    const int datacount = 50; 
    data = malloc(sizeof(int) * datacount); /* allocate memory for 50 int's */ 
    if (!data) { /* If data == 0 after the call to malloc, allocation failed for some reason */ 
    perror("Error allocating memory"); 
    abort(); 
    } 
    /* at this point, we know that data points to a valid block of memory. 
    Remember, however, that this memory is not initialized in any way -- it contains garbage. 
    Let's start by clearing it. */ 
    memset(data, 0, sizeof(int)*datacount); 
    /* now our array contains all zeroes. */ 
    data[0] = 1; 
    data[2] = 15; 
    data[49] = 66; /* the last element in our array, since we start counting from 0 */ 
    /* Loop through the array, printing out the values (mostly zeroes, but even so) */ 
    for(int i = 0; i < datacount; ++i) { 
    printf("Element %d: %d\n", i, data[i]); 
    } 
} 

यही है। इसका क्या मतलब है यह एक और अधिक शामिल स्पष्टीकरण है कि यह क्यों काम करता है :)

मुझे नहीं पता कि आप सी पॉइंटर्स को कितनी अच्छी तरह जानते हैं, लेकिन सी में सरणी पहुंच (जैसे array[2]) वास्तव में एक पॉइंटर के माध्यम से स्मृति तक पहुंचने के लिए एक शॉर्टेंड है। data द्वारा इंगित स्मृति तक पहुंचने के लिए, आप *data लिखते हैं। यह सूचक को dereferencing के रूप में जाना जाता है। चूंकि dataint * प्रकार है, तो *dataint प्रकार का है। अब जानकारी के एक महत्वपूर्ण टुकड़े के लिए: (data + 2) का अर्थ है "data द्वारा इंगित एड्रेस को 2 इंच का बाइट आकार जोड़ें"।

सी में एक सरणी आसन्न स्मृति में मूल्यों का एक अनुक्रम है। array[1]array[0] के बगल में है। इसलिए जब हम स्मृति का एक बड़ा ब्लॉक आवंटित करते हैं और इसे एक सरणी के रूप में उपयोग करना चाहते हैं, तो हमें अंदर के प्रत्येक तत्व को प्रत्यक्ष पता लगाने का एक आसान तरीका चाहिए। सौभाग्य से, सी हमें पॉइंटर्स पर सरणी नोटेशन का भी उपयोग करने देता है। data[0] का अर्थ *(data+0) जैसा है, अर्थात् "data द्वारा दी गई स्मृति तक पहुंच"। data[2] का अर्थ *(data+2) है, और स्मृति ब्लॉक में तीसरे int का उपयोग करता है।

+1

धन्यवाद। यह मुझे व्यापक व्याख्या है, अतिरिक्त प्रयास के लिए धन्यवाद, महोदय, अब मैं आपकी स्पष्टीकरण के आधार पर कुछ चीजों को आजमाने के लिए कोड कर सकता हूं। आखिरी सवाल हालांकि, मैं सरणी आकार को कैसे बढ़ाऊंगा, मान लीजिए कि मैं इसे पिछले 50 तत्वों का विस्तार करना चाहता हूं? – arscariosus

+0

सरणी आकार को बढ़ाने के लिए, आपको 'realloc' का उपयोग करना होगा। यह _might_ कॉपी करें और संपूर्ण मेमोरी ब्लॉक को ले जाएं, इसलिए यह सस्ता नहीं है। http://linux.die.net/man/3/realloc – gnud

+0

इस तरह की एक अच्छी व्याख्या, अगर मैं कर सकता हूं तो दो अपवॉट्स देगा। – marcusshep

0

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

एक और तरीका buffered इनपुट करना है। लूप आवंटित करें, इसे भरें, फिर आवंटित करें, यदि लूप जारी रहता है (सुरुचिपूर्ण नहीं है, लेकिन दिए गए उपयोग-मामले के लिए सबसे तर्कसंगत है)।

हालांकि मुझे वर्णन करने के लिए वर्णित नहीं माना जाता है। शायद, मैं उपयोग-केस (सबसे तर्कसंगत) बदल दूंगा।

2

प्रयास इस तरह के एक linked list

+1

एघ। मैं उन "दिग्गजों" की संख्या की गिनती नहीं कर सकता हूं, जिन्हें मैंने महसूस किया है कि किसी अन्य प्रकार की गतिशील भंडारण योजना भी संभव नहीं है, अकेले ही इष्टतम हो सकता है। ऐसा लगता है जैसे लोग कभी इस पर आगे बढ़ते नहीं हैं। मैं बहुत अधिक अनुशंसा करता हूं कि वे एक वेक्टर की तरह कुछ और लागू करने शुरू करें, जैसा कि एक्स सुझाव देता है - यदि वे आगे बढ़ते हैं तो उस मामले में क्षति बहुत कम होती है। –

+0

निश्चित रूप से अधिक कुशल डेटा संरचनाएं बाहर हैं, असल में, मेरे सामने पहली चीज एसटीएल वेक्टर का उपयोग कर रही थी, यह ध्यान देने से पहले कि वह वास्तव में सी के बारे में पूछ रहा था, लिंक्ड लिस्ट वास्तविक डेटा संरचना का उपयोग करने के लिए एक अवधारणा की तरह है। –

10

जिस तरह से यह अक्सर किया जाता है इस प्रकार है के रूप में गतिशील डेटा संरचना को लागू करने:

  • कुछ प्रारंभिक (काफी छोटे) आकार की एक सरणी आवंटित;
  • इस सरणी में पढ़ा गया है, यह ट्रैक रखें कि आपने कितने तत्व पढ़े हैं;
  • एक बार सरणी भरने के बाद, इसे पुन: आवंटित करें, आकार को दोगुना करें और सामग्री को संरक्षित करें (यानी प्रतिलिपि बनाना);
  • पूर्ण होने तक दोहराना।

मुझे लगता है कि इस पद्धति बहुत अक्सर ऊपर आता है।

क्या इस विधि के बारे में दिलचस्प बात यह है कि यह एक पहले से N जानने के बिना परिशोधित O(N) समय में एक खाली सरणी एक-एक करके में N तत्वों सम्मिलित कर सकते हैं।

+0

अच्छी चाल। यह एक सरल, और इसलिए समझदार उत्तर की तरह लगता है। –

1

malloc() (और उसके दोस्तों को free() और realloc()) रास्ता सी

5

आधुनिक सी, उर्फ ​​C99 में यह करने के लिए है, variable length arrays, VLA है। दुर्भाग्यवश, सभी कंपाइलर्स इसका समर्थन नहीं करते हैं, लेकिन यदि आपका ऐसा करता है तो यह एक विकल्प होगा।

+1

दुर्भाग्य से यह आपको प्रारंभिक अनुमान से अधिक के रूप में आकार बदलने की अनुमति नहीं देता है। – wnoise

+0

धन्यवाद, मुझे बस इसके बारे में पता चला और यह सहायक है।मैं अभी भी पोर्टेबिलिटी के लिए सी 8 9 में ऐसा करने का तरीका जानने का प्रयास करूंगा। बहुत बहुत धन्यवाद। – arscariosus

1

यहां एक नमूना प्रोग्राम है जो stdin को मेमोरी बफर में पढ़ता है जो आवश्यकतानुसार बढ़ता है। यह इतना आसान है कि आपको इस तरह की चीज़ को संभालने में कुछ अंतर्दृष्टि देनी चाहिए। वास्तविक बात यह है कि एक वास्तविक कार्यक्रम में शायद अलग-अलग किया जा सकता है कि प्रत्येक आवंटन में सरणी कैसे बढ़ती है - यदि आप डीबगर में कदम उठाना चाहते हैं तो मैंने चीजों को सरल रखने में मदद के लिए इसे छोटा रखा। एक वास्तविक कार्यक्रम शायद अधिक आवंटन वृद्धि का उपयोग करेगा (अक्सर, आवंटन आकार दोगुना हो जाता है, लेकिन यदि आप ऐसा करने जा रहे हैं तो आपको शायद कुछ उचित आकार में वृद्धि 'कैप' करना चाहिए - शायद इसे दोगुना करने का अर्थ न हो आवंटन जब आप सैकड़ों मेगाबाइट में आते हैं)।

इसके अलावा, मैंने उदाहरण के रूप में यहां बफर को अनुक्रमित पहुंच का उपयोग किया, लेकिन एक वास्तविक कार्यक्रम में मैं शायद ऐसा नहीं करूँगा।

#include <stdlib.h> 
#include <stdio.h> 


void fatal_error(void); 

int main(int argc, char** argv) 
{ 
    int buf_size = 0; 
    int buf_used = 0; 

    char* buf = NULL; 
    char* tmp = NULL;  

    char c; 
    int i = 0; 

    while ((c = getchar()) != EOF) { 
     if (buf_used == buf_size) { 
      //need more space in the array 

      buf_size += 20; 
      tmp = realloc(buf, buf_size); // get a new larger array 
      if (!tmp) fatal_error(); 

      buf = tmp; 
     } 

     buf[buf_used] = c; // pointer can be indexed like an array 
     ++buf_used; 
    } 

    puts("\n\n*** Dump of stdin ***\n"); 

    for (i = 0; i < buf_used; ++i) { 
     putchar(buf[i]); 
    } 

    free(buf); 

    return 0; 
} 

void fatal_error(void) 
{ 
    fputs("fatal error - out of memory\n", stderr); 
    exit(1); 
} 

यह उदाहरण अन्य उत्तरों में उदाहरणों के साथ संयुक्त है, आपको इस बारे में एक विचार देना चाहिए कि इस तरह की चीज़ को निम्न स्तर पर कैसे संभाला जाता है।

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