C गतिशील रूप से बढ़ रहा है


126

मेरे पास एक कार्यक्रम है जो इन-गेम संस्थाओं की "कच्ची" सूची को पढ़ता है, और मैं विभिन्न चीजों को संसाधित करने के लिए एक अनिश्चित संख्या वाली संस्थाओं की एक अनुक्रमणिका संख्या (int) को पकड़े हुए एक सरणी बनाने का इरादा रखता हूं। मैं ऐसे अनुक्रमित रखने के लिए बहुत अधिक मेमोरी या सीपीयू के उपयोग से बचना चाहूंगा ...

एक त्वरित और गंदा समाधान जो मैं अब तक उपयोग करता हूं, मुख्य प्रसंस्करण फ़ंक्शन (स्थानीय फ़ोकस) में अधिकतम गेम संस्थाओं के आकार के साथ सरणी, और सूची में कितने जोड़े गए हैं, इसका ट्रैक रखने के लिए एक और पूर्णांक है। यह संतोषजनक नहीं है, क्योंकि प्रत्येक सूची में 3000+ सरणियाँ होती हैं, जो कि बहुत अधिक नहीं है, लेकिन एक बेकार की तरह लगता है, क्योंकि मैं अलग-अलग कार्यों के लिए 6-7 सूचियों के समाधान का उपयोग कर सकता हूं।

इसे प्राप्त करने के लिए मुझे कोई C (C C ++ या C #) विशिष्ट समाधान नहीं मिला है। मैं पॉइंटर्स का उपयोग कर सकता हूं, लेकिन मैं उनका उपयोग करने से थोड़ा डरता हूं (जब तक कि यह एकमात्र संभव तरीका नहीं है)।

सरणियाँ स्थानीय फ़ंक्शन स्कोप को नहीं छोड़ती हैं (उन्हें किसी फ़ंक्शन में पास किया जाना है, फिर छोड़ दिया गया है), उस मामले में जो चीजों को बदलता है।

यदि पॉइंटर्स एकमात्र समाधान हैं, तो मैं लीक से बचने के लिए उन पर नज़र कैसे रख सकता हूं?


1
यह C में एक (बहुत, बहुत छोटी) समस्या है, लेकिन आपने इसके लिए सभी C ++ और C # समाधान कैसे याद किए?
इग्नासियो वाज़क्वेज़-अब्राम्स

11
"यदि पॉइंटर्स एकमात्र समाधान हैं, तो मैं लीक से बचने के लिए उन पर नज़र कैसे रख सकता हूं?" देखभाल, ध्यान और वैधता। यह ठीक उसी तरह है कि लोग पहले स्थान पर सी से डरते हैं।
क्रिस लुट्ज़

27
आप पॉइंटर्स का उपयोग किए बिना C का प्रभावी ढंग से उपयोग नहीं कर सकते। डरो मत।
qrdl

बड़े
कामों के

6
बिना पॉइंटर्स के C का उपयोग करना ईंधन के बिना कार का उपयोग करने जैसा है।
Martinkunev

जवाबों:


210

मैं पॉइंटर्स का उपयोग कर सकता हूं, लेकिन मैं उनका उपयोग करने से थोड़ा डरता हूं।

यदि आपको डायनेमिक ऐरे की आवश्यकता है, तो आप पॉइंटर्स से बच नहीं सकते। हालांकि आप क्यों डरते हैं? वे नहीं काटेंगे (जब तक आप सावधान हैं, वह है)। सी में बिल्ट-इन डायनेमिक ऐरे नहीं है, आपको बस खुद एक लिखना होगा। C ++ में, आप बिल्ट-इन std::vectorक्लास का उपयोग कर सकते हैं । C # और हर दूसरी उच्च-स्तरीय भाषा के बारे में भी कुछ इसी तरह की कक्षा है जो आपके लिए गतिशील सरणियों का प्रबंधन करती है।

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

typedef struct {
  int *array;
  size_t used;
  size_t size;
} Array;

void initArray(Array *a, size_t initialSize) {
  a->array = malloc(initialSize * sizeof(int));
  a->used = 0;
  a->size = initialSize;
}

void insertArray(Array *a, int element) {
  // a->used is the number of used entries, because a->array[a->used++] updates a->used only *after* the array has been accessed.
  // Therefore a->used can go up to a->size 
  if (a->used == a->size) {
    a->size *= 2;
    a->array = realloc(a->array, a->size * sizeof(int));
  }
  a->array[a->used++] = element;
}

void freeArray(Array *a) {
  free(a->array);
  a->array = NULL;
  a->used = a->size = 0;
}

इसका उपयोग करना उतना ही सरल है:

Array a;
int i;

initArray(&a, 5);  // initially 5 elements
for (i = 0; i < 100; i++)
  insertArray(&a, i);  // automatically resizes as necessary
printf("%d\n", a.array[9]);  // print 10th element
printf("%d\n", a.used);  // print number of elements
freeArray(&a);

1
नमूना कोड के लिए धन्यवाद। मैंने एक बड़े सरणी का उपयोग करके विशिष्ट फ़ंक्शन को कार्यान्वित किया, लेकिन इसके उपयोग से अन्य समान चीजों को लागू करेगा, और मुझे इसे नियंत्रित करने के बाद, दूसरों को वापस बदल दें :)
बाल्कनिया

2
कोड के लिए बहुत बहुत धन्यवाद। एक removeArrayविधि है कि पिछले तत्व से छुटकारा मिलता है यह भी साफ हो जाएगा। यदि आप इसकी अनुमति देते हैं, तो मैं इसे आपके कोड नमूने में जोड़ दूंगा।
ब्रिम्बोरियम

5
% d और size_t ... बिट ऑफ़ नो-नो वहाँ। यदि आप C99 या बाद में उपयोग करते हैं
रेंडी हॉवर्ड

13
मेमोरी आवंटन और पुनः प्राप्ति के साथ सुरक्षा जांच को कभी भी न छोड़ें।
एलेक्स रेनॉल्ड्स

3
यह एक प्रदर्शन व्यापार है। यदि आप हर बार दोगुना करते हैं, तो आपके पास कभी-कभी 100% ओवरहेड और औसतन 50% होता है। 3/2 आपको 50% सबसे खराब और 25% ठेठ देता है। यह सीमा (फी) में फाइबियोनेस सीक्वेंस के प्रभावी आधार के करीब है जो अक्सर प्रशंसा की जाती है और इसका उपयोग "घातीय लेकिन बेस -2" की तुलना में बहुत कम हिंसक रूप से किया जाता है, लेकिन गणना करना आसान है। +8 का मतलब है कि एरे जो कि बहुत छोटे हैं, बहुत अधिक प्रतियां करने से समाप्त नहीं होते हैं। यह एक गुणक शब्द जोड़ता है जिससे सरणी जल्दी से बढ़ सकती है यदि उसका आकार अप्रासंगिक है। विशेषज्ञ उपयोग में यह ट्यून करने योग्य होना चाहिए।
दान शापार्ड

10

कुछ विकल्प हैं जिनके बारे में मैं सोच सकता हूं।

  1. लिंक्ड सूची। आप डायनामिक रूप से बढ़ते एरे जैसी चीज़ बनाने के लिए लिंक की गई सूची का उपयोग कर सकते हैं। लेकिन आप पहले array[100]से चलने के बिना नहीं कर पाएंगे 1-99। और यह आपके लिए उपयोग करने के लिए उतना आसान नहीं हो सकता है।
  2. बड़ी सरणी। बस हर चीज के लिए पर्याप्त जगह के साथ एक सरणी बनाएं
  3. सरणी का आकार बदलना। एक बार जब आप आकार को जान लेते हैं तो सरणी को फिर से बनाएँ और / या हर बार जब आप कुछ मार्जिन के साथ अंतरिक्ष से बाहर जाते हैं तो एक नया सरणी बनाएं और सभी डेटा को नए सरणी में कॉपी करें।
  4. लिंक्ड सूची सरणी संयोजन। बस एक निश्चित आकार के साथ एक सरणी का उपयोग करें और एक बार जब आप अंतरिक्ष से बाहर निकलते हैं, तो एक नया सरणी बनाएं और उससे लिंक करें (यह एक ट्रैक में सरणी के लिंक और अगले सरणी के लिंक को रखने के लिए बुद्धिमान होगा)।

यह कहना मुश्किल है कि आपकी स्थिति में कौन सा विकल्प सबसे अच्छा होगा। बस एक बड़ा सरणी बनाना सबसे आसान समाधानों में से एक है और जब तक यह वास्तव में बड़ा नहीं होता तब तक आपको बहुत समस्या नहीं देनी चाहिए।


आधुनिक-ईश 2 डी गेम के लिए 3264 पूर्णांक के सात ऐरे कैसे ध्वनि करते हैं? अगर मैं सिर्फ पागल हो रहा हूं, तो समाधान बड़े पैमाने पर होगा।
बलकानिया

3
यहां # 1 और # 4 दोनों को किसी भी तरह पॉइंटर्स और डायनामिक मेमोरी एलोकेशन का उपयोग करने की आवश्यकता है। मैं realloc# 3 के साथ उपयोग करने का सुझाव देता हूं - सरणी को एक सामान्य आकार आवंटित करें, और फिर जब भी आप बाहर निकलते हैं तो इसे बढ़ाएं। reallocयदि आवश्यक हो तो अपने डेटा की नकल संभाल लेंगे। स्मृति प्रबंधन पर ओपी के सवाल के लिए, आपको बस mallocएक बार शुरू करने की जरूरत है , freeएक बार अंत में, और reallocहर बार जब आप कमरे से बाहर निकलते हैं। यह बहुत खराब नहीं है।
बोरेलिड

1
@ बाल्कनिया: 3264 पूर्णांकों में से सात सरणियाँ 100KB के अंतर्गत एक बाल है। यह बहुत ज्यादा स्मृति नहीं है।
बोरेलिड

1
@ बलकानिया: 7 * 3264 * 32 bitलगता है 91.39 kilobytes। इन दिनों किसी भी मानक से ज्यादा नहीं;)
वोल्फ

1
यह विशेष रूप से चूक एक शर्म की बात है, क्योंकि यह पूरी तरह से स्पष्ट नहीं है कि reallocरिटर्न होने पर क्या होना चाहिए NULL: a->array = (int *)realloc(a->array, a->size * sizeof(int));... शायद यह सबसे अच्छा लिखा गया होगा: int *temp = realloc(a->array, a->size * sizeof *a->array); a->array = temp;... इस तरह यह स्पष्ट होगा कि जो कुछ भी होता है उससे पहले होना चाहिए NULLमूल्य को सौंपा गया है a->array(अगर यह सब पर है)।
ऑटिस्टिक

10

जैसा कि पहले था कि बाद में सब कुछ डरावना लगता है, प्रारंभिक भय पर काबू पाने का सबसे अच्छा तरीका है कि आप अपने आप को अज्ञात की असुविधा में डुबो दें ! यह कई बार ऐसा होता है, जिसे हम सबसे अधिक सीखते हैं, आखिरकार।

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

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

एरियर ऑपरेटर पॉइंटर ऑपरेटर हैं। array[x]वास्तव में एक शॉर्टकट है *(array + x), जिसे नीचे तोड़ा जा सकता है: *और (array + x)। यह सबसे अधिक संभावना है कि वही *है जो आपको भ्रमित करता है। हम आगे संभालने से समस्या से इसके समाप्त कर सकते हैं xहोने के लिए 0, इस प्रकार, array[0]हो जाता है *arrayक्योंकि जोड़ने 0मूल्य में परिवर्तन नहीं होगा ...

... और इस प्रकार हम देख सकते हैं कि *arrayइसके बराबर है array[0]। आप एक का उपयोग कर सकते हैं जहां आप दूसरे का उपयोग करना चाहते हैं, और इसके विपरीत। एरियर ऑपरेटर पॉइंटर ऑपरेटर हैं।

malloc, reallocऔर दोस्तों एक पॉइंटर की अवधारणा का आविष्कार न करें जो आप सभी के साथ उपयोग कर रहे हैं; वे इसका उपयोग केवल कुछ अन्य विशेषता को लागू करने के लिए करते हैं, जो भंडारण अवधि का एक अलग रूप है, जब आप आकार में कठोर, गतिशील परिवर्तन चाहते हैं, तो यह सबसे उपयुक्त है ।

यह शर्म की बात है कि वर्तमान में स्वीकार किया गया उत्तर स्टैकऑवरफ्लो पर कुछ अन्य बहुत अच्छी तरह से स्थापित सलाह के अनाज के खिलाफ भी जाता है , और साथ ही, एक छोटी-ज्ञात सुविधा को पेश करने का अवसर याद करता है जो वास्तव में इस usecase के लिए चमकता है: लचीला सरणी सदस्यों! यह वास्तव में एक बहुत ही टूटा हुआ जवाब है ... :(

जब आप अपने को परिभाषित करते हैं struct, तो संरचना के अंत में अपने सरणी की घोषणा करें , बिना किसी ऊपरी सीमा के। उदाहरण के लिए:

struct int_list {
    size_t size;
    int value[];
};

यह आपको अपने intआबंटन में अपनी सरणी को अपने समान करने की अनुमति देगा count, और उन्हें इस तरह से बाध्य करना बहुत आसान हो सकता है !

sizeof (struct int_list)हालांकि value0 के आकार के अनुसार कार्य करेगा , इसलिए यह आपको खाली सूची के साथ संरचना का आकार बताएगा । आपको अभी भी reallocअपनी सूची का आकार निर्दिष्ट करने के लिए दिए गए आकार में जोड़ना होगा।

एक और आसान टिप यह याद रखना है कि realloc(NULL, x)यह समकक्ष है malloc(x), और हम इसका उपयोग अपने कोड को सरल बनाने के लिए कर सकते हैं। उदाहरण के लिए:

int push_back(struct int_list **fubar, int value) {
    size_t x = *fubar ? fubar[0]->size : 0
         , y = x + 1;

    if ((x & y) == 0) {
        void *temp = realloc(*fubar, sizeof **fubar
                                   + (x + y) * sizeof fubar[0]->value[0]);
        if (!temp) { return 1; }
        *fubar = temp; // or, if you like, `fubar[0] = temp;`
    }

    fubar[0]->value[x] = value;
    fubar[0]->size = y;
    return 0;
}

struct int_list *array = NULL;

struct int_list **प्रथम तर्क के रूप में उपयोग करने का कारण मैंने तुरंत स्पष्ट नहीं हो सकता है, लेकिन यदि आप दूसरे तर्क के बारे में सोचते हैं, तो valueभीतर से किए गए कोई भी परिवर्तन push_backउस फ़ंक्शन को दिखाई नहीं देंगे, जिसे हम सही कह रहे हैं? वही पहले तर्क के लिए जाता है, और हमें अपने को संशोधित करने में सक्षम होना चाहिए array, न केवल यहां बल्कि संभवतः किसी अन्य फ़ंक्शन में भी / हम इसे पास करते हैं ...

arrayकुछ भी नहीं की ओर इशारा करते हुए शुरू होता है; यह एक खाली सूची है। इसे शुरू करना इसे जोड़ने के समान है। उदाहरण के लिए:

struct int_list *array = NULL;
if (!push_back(&array, 42)) {
    // success!
}

पुनश्च जब आप इसके साथ कर रहे हैं याद रखेंfree(array); !


" array[x]वास्तव में एक शॉर्टकट है *(array + x), [...]" क्या आप इसके बारे में निश्चित हैं ???? उनके विभिन्न व्यवहारों का एक विवरण देखें: eli.thegreenplace.net/2009/10/21/…
सी-स्टार-डब्ल्यू-स्टार

1
काश, @ सी-स्टार-पप्पी, आपके संसाधन का उल्लेख नहीं करने वाला एक संदर्भ सी मानक है। यही वह विनिर्देश है जिसके द्वारा आपके कंपाइलरों को कानूनी रूप से स्वयं को सी कंपाइलर का पालन करना चाहिए। आपके संसाधन को मेरी जानकारी बिल्कुल भी विरोधाभासी नहीं लगती। बहरहाल, मानक वास्तव में इस तरह के रूप में कुछ उदाहरण है इस मणि जहां यह पता चला है कि array[index]वास्तव में है ptr[index]भेस में ... "सबस्क्रिप्ट ऑपरेटर की परिभाषा []है कि E1[E2]के समान है (*((E1)+(E2)))" आप एसटीडी का खंडन नहीं कर सकते हैं
ऑटिस्टिक

इस प्रदर्शन का प्रयास करें, @ C-Star-Puppy: int main(void) { unsigned char lower[] = "abcdefghijklmnopqrstuvwxyz"; for (size_t x = 0; x < sizeof lower - 1; x++) { putchar(x[lower]); } }... आपको शायद इसकी आवश्यकता होगी #include <stdio.h>और <stddef.h>... क्या आप देखते हैं कि मैंने x[lower]( xपूर्णांक प्रकार होने के बजाय) कैसे लिखा lower[x]? सी संकलक परवाह नहीं करता है, क्योंकि *(lower + x)उसी के रूप में एक ही मूल्य है *(x + lower), और lower[x]पूर्व है जहां-जैसा x[lower]बाद वाला है। ये सभी भाव समतुल्य हैं। उन्हें आज़माएं ... अपने लिए देखें, अगर आप मेरा वचन नहीं ले सकते ...
ऑटिस्टिक

... और फिर निश्चित रूप से यह हिस्सा है, जिस पर मैंने अपना जोर दिया है, लेकिन आपको वास्तव में बिना जोर दिए पूरी बोली पढ़नी चाहिए: "सिवाय इसके कि जब यह आकार के ऑपरेटर, _Alignof ऑपरेटर, या यूनिरी एंड ऑपरेटर, या एक स्ट्रिंग शाब्दिक है जिसका उपयोग किसी सरणी को आरंभीकृत करने के लिए किया जाता है, एक अभिव्यक्ति जिसमें 'टाइप का प्रकार' होता है, को '' पॉइंटर टू टाइप '' के साथ एक अभिव्यक्ति में बदल दिया जाता है जो सरणी के प्रारंभिक तत्व को इंगित करता है। ऑब्जेक्ट और एक लैवल्यू नहीं है । यदि एरे ऑब्जेक्ट में स्टोरेज क्लास रजिस्टर है, तो व्यवहार अपरिभाषित है। " फ़ंक्शन, btw के लिए भी यही सच है।
ऑटिस्टिक

ओह और एक अंतिम नोट पर, @ C-Star-Puppy, Microsoft C ++ एक सी संकलक नहीं है और पिछले 20 वर्षों से एक नहीं है। आप C89 मोड, suuuure को सक्षम कर सकते हैं , लेकिन हम कंप्यूटिंग में 1980 के दशक के उत्तरार्ध से आगे निकल चुके हैं। उस विषय पर अधिक जानकारी के लिए, मैं इस लेख को पढ़ने का सुझाव देता हूं ... और फिर एक वास्तविक सी कंपाइलर पर स्विच कर रहा हूं जैसे कि gccया clangआपके सभी सी संकलन के लिए, क्योंकि आप पाएंगे कि बहुत सारे पैकेज हैं जिन्होंने C99 सुविधाओं को अपनाया है ...
ऑटिस्टिक

3

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

Storage.h फ़ाइल इस तरह दिखती है ...

#ifndef STORAGE_H
#define STORAGE_H

#ifdef __cplusplus
extern "C" {
#endif

    typedef struct 
    {
        int *array;
        size_t size;
    } Array;

    void Array_Init(Array *array);
    void Array_Add(Array *array, int item);
    void Array_Delete(Array *array, int index);
    void Array_Free(Array *array);

#ifdef __cplusplus
}
#endif

#endif /* STORAGE_H */

Storage.c फ़ाइल इस तरह दिखाई देती है ...

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

/* Initialise an empty array */
void Array_Init(Array *array) 
{
    int *int_pointer;

    int_pointer = (int *)malloc(sizeof(int));

    if (int_pointer == NULL)
    {       
        printf("Unable to allocate memory, exiting.\n");
        free(int_pointer);
        exit(0);
    }
    else
    {
        array->array = int_pointer; 
        array->size = 0;
    }
}

/* Dynamically add to end of an array */
void Array_Add(Array *array, int item) 
{
    int *int_pointer;

    array->size += 1;

    int_pointer = (int *)realloc(array->array, array->size * sizeof(int));

    if (int_pointer == NULL)
    {       
        printf("Unable to reallocate memory, exiting.\n");
        free(int_pointer);
        exit(0);
    }
    else
    {
        array->array = int_pointer;
        array->array[array->size-1] = item;
    }
}

/* Delete from a dynamic array */
void Array_Delete(Array *array, int index) 
{
    int i;
    Array temp;
    int *int_pointer;

    Array_Init(&temp);

    for(i=index; i<array->size; i++)
    {
        array->array[i] = array->array[i + 1];
    }

    array->size -= 1;

    for (i = 0; i < array->size; i++)
    {
        Array_Add(&temp, array->array[i]);
    }

    int_pointer = (int *)realloc(temp.array, temp.size * sizeof(int));

    if (int_pointer == NULL)
    {       
        printf("Unable to reallocate memory, exiting.\n");
        free(int_pointer);
        exit(0);
    }
    else
    {
        array->array = int_pointer; 
    } 
}

/* Free an array */
void Array_Free(Array *array) 
{
  free(array->array);
  array->array = NULL;
  array->size = 0;  
}

Main.c इस तरह दिखता है ...

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

int main(int argc, char** argv) 
{
    Array pointers;
    int i;

    Array_Init(&pointers);

    for (i = 0; i < 60; i++)
    {
        Array_Add(&pointers, i);        
    }

    Array_Delete(&pointers, 3);

    Array_Delete(&pointers, 6);

    Array_Delete(&pointers, 30);

    for (i = 0; i < pointers.size; i++)
    {        
        printf("Value: %d Size:%d \n", pointers.array[i], pointers.size);
    }

    Array_Free(&pointers);

    return (EXIT_SUCCESS);
}

आगे की रचनात्मक आलोचना के लिए आगे देखें ...


1
यदि यह रचनात्मक आलोचना है जिसे आप चाहते हैं, तो कोड समीक्षा में पोस्ट करना बेहतर होगा । उस ने कहा, सुझावों की एक जोड़ी: यह जरूरी है कि malloc()आवंटन का उपयोग करने से पहले कॉल की सफलता के लिए कोड की जाँच करता है । एक ही नस में, यह realloc()सूचक को मूल स्मृति को पुनः प्राप्त करने के लिए सीधे निर्दिष्ट करने के लिए एक गलती है ; यदि realloc()विफल रहता है, NULLतो वापस कर दिया जाता है, और कोड को स्मृति रिसाव के साथ छोड़ दिया जाता है। एक बार में 1 स्थान जोड़ने के बजाय आकार बदलने पर डबल मेमोरी के लिए यह अधिक कुशल है: कम कॉल realloc()
पूर्व निहिलो

1
मुझे पता था कि मैं अलग हो

2
इसके अलावा किसी को चीरने की कोशिश नहीं की जा रही है, बस कुछ रचनात्मक आलोचना की पेशकश की जा रही है, जो शायद आपके हल्के-फुल्के करीबी के बिना भी आगे
बढ़ रही है

1
डेविड, मैं आपकी टिप्पणी के बारे में सोच रहा हूं "जब एक बार में 1 स्थान जोड़ने की तुलना में यह डबल मेमोरी के लिए बहुत अधिक कुशल है: realloc ()" के लिए कम कॉल। क्या आप मेरे लिए कृपया इस पर विस्तार से चर्चा करेंगे कि स्मृति की मात्रा को दोगुना करना क्यों बेहतर है और संभवतः इसका उपयोग नहीं करना है, इसलिए स्मृति को बर्बाद करना, कार्य के लिए आवश्यक राशि आवंटित करने के बजाय? मुझे वह मिलता है जो आप कॉल के बारे में कह रहे हैं realloc (), लेकिन क्यों हर बार realloc () एक मुद्दा है? क्या यह वह नहीं है जिसके लिए स्मृति को पुनः प्राप्त करना है?

1
जबकि सख्त दोहरीकरण इष्टतम नहीं हो सकता है, यह निश्चित रूप intसे एक समय में मेमोरी बाइट (या एक , आदि) को बढ़ाने से बेहतर है । दोहरीकरण एक विशिष्ट समाधान है, लेकिन मुझे नहीं लगता कि कोई भी इष्टतम समाधान है जो सभी परिस्थितियों में फिट बैठता है। यहां बताया गया है कि दोहरीकरण एक अच्छा विचार है (कुछ अन्य कारक जैसे कि 1.5 भी ठीक होगा): यदि आप एक उचित आवंटन के साथ शुरू करते हैं, तो आपको बिल्कुल भी पुनः प्राप्त करने की आवश्यकता नहीं हो सकती है। जब अधिक मेमोरी की आवश्यकता होती है, तो उचित आवंटन दोगुना हो जाता है, और इसी तरह। इस तरह से आपको केवल एक या दो कॉल करने की आवश्यकता है realloc()
पूर्व निहिलो

2

जब तुम कह रहे हो

किसी अनिश्चित संख्या वाली संस्थाओं की अनुक्रमणिका संख्या (int) को पकड़े हुए एक सरणी बनाएं

आप मूल रूप से कह रहे हैं कि आप "पॉइंटर्स" का उपयोग कर रहे हैं, लेकिन एक जो मेमोरी-वाइड पॉइंटर के बजाय एक सरणी-वाइड लोकल पॉइंटर है। चूँकि आप वैचारिक रूप से पहले से ही "पॉइंटर्स" का उपयोग कर रहे हैं (यानी एक सरणी में एक तत्व को संदर्भित करता है), इसलिए आप नियमित पॉइंटर्स का उपयोग क्यों नहीं करते हैं (यानी आईडी संख्या जो सबसे बड़े सरणी में एक तत्व को संदर्भित करता है: संपूर्ण मेमोरी )।

अपनी वस्तुओं के बजाय एक संसाधन आईडी संख्या जमा करने के बजाय, आप उन्हें एक सूचक स्टोर कर सकते हैं। मूल रूप से एक ही बात है, लेकिन बहुत अधिक कुशल है क्योंकि हम "सरणी + इंडेक्स" को "पॉइंटर" में बदलने से बचते हैं।

पॉइंटर्स डरावने नहीं हैं यदि आप उन्हें पूरी मेमोरी के लिए एरे इंडेक्स मानते हैं (जो वास्तव में वे हैं)


2

किसी भी प्रकार की असीमित वस्तुओं की एक सरणी बनाने के लिए:

typedef struct STRUCT_SS_VECTOR {
    size_t size;
    void** items;
} ss_vector;


ss_vector* ss_init_vector(size_t item_size) {
    ss_vector* vector;
    vector = malloc(sizeof(ss_vector));
    vector->size = 0;
    vector->items = calloc(0, item_size);

    return vector;
}

void ss_vector_append(ss_vector* vec, void* item) {
    vec->size++;
    vec->items = realloc(vec->items, vec->size * sizeof(item));
    vec->items[vec->size - 1] = item;
};

void ss_vector_free(ss_vector* vec) {
    for (int i = 0; i < vec->size; i++)
        free(vec->items[i]);

    free(vec->items);
    free(vec);
}

और इसका उपयोग कैसे करें:

// defining some sort of struct, can be anything really
typedef struct APPLE_STRUCT {
    int id;
} apple;

apple* init_apple(int id) {
    apple* a;
    a = malloc(sizeof(apple));
    a-> id = id;
    return a;
};


int main(int argc, char* argv[]) {
    ss_vector* vector = ss_init_vector(sizeof(apple));

    // inserting some items
    for (int i = 0; i < 10; i++)
        ss_vector_append(vector, init_apple(i));


    // dont forget to free it
    ss_vector_free(vector);

    return 0;
}

यह वेक्टर / सरणी किसी भी प्रकार की वस्तु को पकड़ सकता है और यह आकार में पूरी तरह से गतिशील है।


0

ठीक है, मुझे लगता है कि यदि आपको किसी तत्व को निकालने की आवश्यकता है तो आप उस तत्व की तिरस्कार की एक प्रतिलिपि बना देंगे जिसमें तत्व को बाहर रखा जाएगा।

// inserting some items
void* element_2_remove = getElement2BRemove();

for (int i = 0; i < vector->size; i++){
       if(vector[i]!=element_2_remove) copy2TempVector(vector[i]);
       }

free(vector->items);
free(vector);
fillFromTempVector(vector);
//

मान लें कि getElement2BRemove(), copy2TempVector( void* ...)और fillFromTempVector(...)अस्थायी वेक्टर को संभालने के लिए सहायक विधियां हैं।


यह स्पष्ट नहीं है कि यह वास्तव में प्रश्न का उत्तर है, या यदि यह एक टिप्पणी है।

यह "कैसे" के लिए एक राय है और मैं पुष्टि के लिए पूछ रहा हूं (क्या मैं गलत हूं?) यदि किसी के पास बेहतर विचार है। ;)
जोसेम बारबोसा - M4NOV3Y

मुझे लगता है कि मैं आपके अंतिम वाक्य को नहीं समझता। चूंकि SO एक थ्रेडेड फ़ोरम नहीं है, इसलिए उत्तर में इस तरह के खुले प्रश्न अजीब लगते हैं।

1
मैंने आपका अंतिम वाक्य तय कर दिया है कि मुझे लगता है कि आप क्या कहना चाहते हैं।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.