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

इस तरह की एक सरणी कैसे बनाई जाती है इसका एक उदाहरण यहां दिया गया है:

int *array; 
array = malloc(sizeof(int) + sizeof(double) + (n * sizeof(int)))
*(array) = n;
array++;
(double*)array++;
return array;

इस उदाहरण में, मॉलोक स्टेटमेंट में sizeof(int) और sizeof(double) ऐसे तत्व हैं जो चीजों को स्टोर करेंगे, जैसे कि इंट एलिमेंट में एरे का आकार, और डबल एलिमेंट में हम कुछ इस तरह स्टोर कर सकते हैं सरणी में सभी संख्याओं का औसत (इन दो तत्वों को छोड़कर)

(n * sizeof(int)) सरणी में शेष तत्वों को बनाने के लिए है, जहां n तत्वों की संख्या है, और sizeof(int) इन तत्वों के लिए वांछित डेटा प्रकार है, और सिद्धांत रूप में यह काम करना चाहिए किसी भी डेटा प्रकार की एक सरणी के लिए।

अब, मुझे यह परेशानी हो रही है:

मैंने सरणी के आकार को पुनः प्राप्त करने के लिए एक और फ़ंक्शन बनाया है, लेकिन मुझे सरणी को कम करने और बढ़ाने में समस्या हो रही है। यहाँ मेरा कोड है:

getArraySize(void* array){
(double*)array--;//Decrement past the double element
(int*)array--;//Decrement past the int element

int size = *((int*)array);//Acquire size of the array

(int*)array++;//Increment past int element
(double*)array++;//Increment past the double element

return size;}

यह फ़ंक्शन सरणी के आकार को प्राप्त करने में विफल रहता है, और मुझे इसका एहसास हुआ है क्योंकि संकलक पहले सरणी को बढ़ाता है फिर प्रकार इसे कास्ट करता है। हालांकि, जब मैं इस तरह के वेतन वृद्धि/कमी विवरण को निम्नानुसार ठीक करने का प्रयास करता हूं:

((int*)array)++;

मुझे एक त्रुटि मिलती है जो कहती है lvalue required as increment operand। मुझे नहीं पता कि इस नोटेशन को इस तरह से कैसे ठीक किया जाए कि यह सही ढंग से इंक्रीमेंट और डिक्रीमेंट हो जाए। किसी भी सुझाव को सराहा जाएगा।

1
Makrovich 19 फरवरी 2020, 10:19
1
प्रश्नों/उत्तरों की एक अतिरिक्त पंक्ति अंत में आकार 0 की सरणी संरचना का
 – 
David C. Rankin
19 फरवरी 2020, 10:45

2 जवाब

मेरे कंप्यूटर साइंस कोर्स में, हमें एक मॉलोज्ड एरे के 0वें एलिमेंट में वैल्यू स्टोर करने की एक विधि सिखाई गई है, फिर ऐरे को बढ़ाना ताकि एरे के आकार जैसी चीजों को उस एलिमेंट में स्टोर किया जा सके और बाद में पुनः प्राप्त किया जा सके।

यह सुनकर खेद है, क्योंकि यह पूरी तरह बकवास है। इसके बजाय struct का प्रयोग करें।

हालाँकि, कार्य के बकवास होने से भी बदतर यह है कि यह अपरिभाषित व्यवहार को भी आमंत्रित करता है (सी मानक 6.5.6 देखें)। आप पॉइंटर अंकगणित नहीं कर सकते हैं, जो कि पॉइंटर के समान प्रकार के साथ एक सरणी की ओर इशारा नहीं कर रहे हैं।

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

साथ ही, डेटा प्रकार के अंदर विभिन्न प्रकार के संचालन के परिणाम को संग्रहीत करना, जैसे कि औसत, डेटा प्रकार के अंदर ही कोई समझ नहीं आता है। जैसे ही मूल्य बदलता है, उन्हें अपडेट करना होगा, जो अनावश्यक ब्लोट और अप्रभावी कोड का कारण बनता है।

यह सब बकवास तुरंत भूल जाओ। आपका प्रोग्राम ठीक या मरम्मत नहीं हो सकता, क्योंकि इसके पीछे का विचार मौलिक रूप से गलत है। इसके बजाय इसे पसंद करें:

typedef struct
{
  int i;
  double d;
  int array[];
} something;

something* s = malloc(sizeof(something) + sizeof(int[n]));
s->i = ...;
s->d = ...;
for(int i=0; i<n; i++)
  s->array[i] = ...;

...
free(s);

विशेष रूप से, आपका कोड C17 6.5.6 §7 और §8 प्रति अपरिभाषित व्यवहार को आमंत्रित करता है:

इन ऑपरेटरों के प्रयोजनों के लिए, किसी ऑब्जेक्ट के लिए एक पॉइंटर जो किसी सरणी का तत्व नहीं है, ऑब्जेक्ट के प्रकार के साथ उसके तत्व प्रकार के साथ लंबाई की एक सरणी के पहले तत्व के सूचक के समान व्यवहार करता है।

जब एक एक्सप्रेशन जिसमें पूर्णांक प्रकार होता है, को पॉइंटर से जोड़ा या घटाया जाता है, तो परिणाम में पॉइंटर ऑपरेंड का प्रकार होता है। /--/ यदि सूचक संकार्य और परिणाम दोनों एक ही सरणी वस्तु के तत्वों की ओर इशारा करते हैं... /--/ ...अन्यथा, व्यवहार अपरिभाषित है।

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

गलत संरेखण के संबंध में प्रासंगिक भाग C17 6.3.2.3/7 है:

किसी ऑब्जेक्ट प्रकार के सूचक को किसी भिन्न ऑब्जेक्ट प्रकार के सूचक में परिवर्तित किया जा सकता है। यदि परिणामी सूचक संदर्भित प्रकार के लिए सही ढंग से संरेखित नहीं है, तो व्यवहार अपरिभाषित है।

6
Lundin 19 फरवरी 2020, 10:47

आप अपने लक्ष्य तक पहुँचने के लिए क्या कर सकते हैं और (मेरी राय में) वैसे भी अधिक पठनीय है:

array -= sizeof(double);  // get to position where double starts
array -= sizeof(int);     // get to position where int starts

नोट यह केवल कुछ कंपाइलरों पर और getArraySize के भीतर काम करता है क्योंकि आपने सरणी पॉइंटर को void* पर डाला है। तो यह भी कतई उचित नहीं है

लेकिन मैं वास्तव में सोचता हूं कि यह जाने का रास्ता नहीं है और मैं इसके बजाय struct का उपयोग करने की भी सलाह देता हूं जैसा कि @Lundin बताता है।

यदि आप अपने getArraySize फ़ंक्शन को किसी अन्य पॉइंटर के साथ या अपेक्षित सरणी के पॉइंटर के साथ कॉल करते हैं, लेकिन सही स्थिति में नहीं, तो यह संभवतः सेगमेंटेशन दोषों में समाप्त हो जाएगा

-2
Odysseus 19 फरवरी 2020, 10:59
यह बिल्कुल भी काम नहीं करता है क्योंकि sizeof(double) int* पॉइंटर को एक इंट के आकार के 8 गुना उदाहरण के लिए ले जाएगा, जो कभी भी सही नहीं हो सकता। आपका तरीका केवल कैरेक्टर टाइप पॉइंटर्स के साथ काम करेगा, जो यहां लागू नहीं होता है।
 – 
Lundin
19 फरवरी 2020, 10:43
मैं उनके getArraySize फ़ंक्शन का उल्लेख करता हूं जहां वह अपने सरणी सूचक को (void*) के रूप में पास करता है ताकि मुझे लगता है कि काम करना चाहिए। बाहर अगर यह अभी भी int* है तो आप बिल्कुल सही हैं, मैं इसे स्पष्ट कर दूंगा
 – 
Odysseus
19 फरवरी 2020, 10:49
नहीं, आप शून्य बिंदुओं पर सूचक अंकगणित नहीं कर सकते। यह एक गैर-मानक कंपाइलर एक्सटेंशन है जो केवल कुछ कंपाइलरों द्वारा समर्थित है, जब उनका गैर-अनुपालन मोड सक्षम होता है।
 – 
Lundin
19 फरवरी 2020, 10:51
अच्छा बिंदु - आप सही हैं लेकिन कम से कम जीएनयू सी इसकी अनुमति देता है। लेकिन इससे यह उचित नहीं है
 – 
Odysseus
19 फरवरी 2020, 10:58
जीएनयू सी मानक सी नहीं है और इसे शुरुआती लोगों को नहीं पढ़ाया जाना चाहिए। सख्त मानक अनुपालन और अधिकतम चेतावनियों के लिए जीसीसी का उपयोग करने वालों को हमेशा -std=c11 -pedantic-errors -Wall -Wextra के साथ संकलन करना चाहिए।
 – 
Lundin
19 फरवरी 2020, 11:00