2013-06-03 4 views
5

ऐसा कहा जाता है कि शून्य लंबाई सरणी परिवर्तनीय लंबाई संरचना के लिए है, जिसे मैं समझ सकता हूं। लेकिन मुझे क्या पहेली है कि हम केवल एक सूचक का उपयोग नहीं करते हैं, हम उसी तरह एक अलग आकार की संरचना को कम कर सकते हैं और आवंटित कर सकते हैं।हम पॉइंटर्स के बजाय शून्य लंबाई सरणी का उपयोग क्यों करते हैं?

संपादित करें - टिप्पणी

मान लिया जाये से जोड़ा गया उदाहरण:

struct p 
{ 
    char ch; 
    int *arr; 
}; 

हम इसका उपयोग कर सकते हैं:

struct p *p = malloc(sizeof(*p) + (sizeof(int) * n)); 

p->arr = (struct p*)(p + 1); 

स्मृति का एक सन्निहित हिस्सा पाने के लिए। हालांकि, मुझे लगता है कि स्पेस p->arr पर कब्जा करना भूल गया है और यह शून्य आकार सरणी विधि से एक अलग चीज़ प्रतीत होता है।

+2

कृपया एक उदाहरण प्रदान करें। – Arafangion

+1

structs के बारे में स्पष्टीकरण। C90 में 'LastMemberOfArray [] ',' 99 में' अंतिम MemberOfArray [] 'और गैर-मानक जीएनयू गुओ में 'LastMemberOfArray [0]' तीन मामले हैं। सी 0 9 मामले में, यह एक गंदे हैक अपरिभाषित व्यवहार पर निर्भर है। यदि संरचना के अंत में संरचना पैडिंग बाइट्स हैं तो आपको समस्याएं मिल सकती हैं। सी 99 ने इसे ठीक किया और _flexible array member_ नामक एक प्रकार बनाया, जो एक ही तरीके से काम करता है लेकिन अच्छी तरह से परिभाषित व्यवहार के साथ। और अंत में, गैर मानक जीएनयू एक ही उद्देश्य के लिए शून्य आकार के सरणी की अनुमति देता है। '-std = c99 -pedantic-error' और '[0]' के साथ मानक के रूप में संकलित करें संकलित नहीं होगा। – Lundin

+1

@ लुंडिन का पहला उदाहरण "9 0 में अंतिम मेम्बरऑफएरे [1] 'होना चाहिए था। सरल टाइपो, इसे केवल उन लोगों के लाभ के लिए जोड़ना जो याद नहीं करते हैं। –

उत्तर

5

ये तथाकथित "संरचना हैक" के विभिन्न रूप हैं, comp.lang.c FAQ के प्रश्न 2.6 में चर्चा की गई।

आकार 0 की एक सरणी परिभाषित करना वास्तव में सी में अवैध है, और कम से कम 1 9 8 9 एएनएसआई मानक के बाद से किया गया है। कुछ कंपाइलर्स इसे एक एक्सटेंशन के रूप में अनुमति देते हैं, लेकिन उस पर भरोसा करने से गैर-पोर्टेबल कोड होता है।

इस लागू करने के लिए एक अधिक पोर्टेबल तरह से उदाहरण के लिए, लंबाई 1 की एक सरणी का उपयोग करने के लिए है:

struct foo { 
    size_t len; 
    char str[1]; 
}; 

आप एक से अधिक sizeof (struct foo) बाइट्स आवंटित कर सकता है, len का उपयोग कर आवंटित आकार का ट्रैक रखने के, और फिर सरणी के एनएच तत्व प्राप्त करने के लिए str[N] तक पहुंचें। चूंकि सी कंपाइलर्स आम तौर पर सरणी सीमाओं की जांच नहीं करते हैं, यह आम तौर पर "काम" करेगा। लेकिन, कड़ाई से बोलते हुए, व्यवहार अपरिभाषित है।

1999 आईएसओ मानक एक विशेषता "लचीला सरणी सदस्यों" कहा जाता है, इस प्रयोग को बदलने के लिए इरादा कहा:

struct foo { 
    size_t len; 
    char str[]; 
}; 

आप पुराने struct हैक के रूप में एक ही तरीके से इन के साथ सौदा कर सकते हैं, लेकिन व्यवहार है अच्छी तरह से परिभाषित। लेकिन आपको खुद को सभी बहीखाता करना है; sizeof (struct foo) में अभी भी सरणी का आकार शामिल नहीं है, उदाहरण के लिए।

आप, ज़ाहिर है, एक सूचक के बजाय का उपयोग कर सकते हैं:

struct bar { 
    size_t len; 
    char *ptr; 
}; 

और यह एक पूरी तरह से अच्छा दृष्टिकोण है, लेकिन यह अलग अर्थ विज्ञान है। "स्ट्रक्चर हैक" या लचीली सरणी सदस्यों का मुख्य लाभ यह है कि सरणी को बाकी संरचना के साथ आवंटित किया जाता है, और आप memcpy का उपयोग करके संरचना के साथ सरणी की प्रतिलिपि बना सकते हैं (जब तक लक्ष्य लक्ष्य रहा है ठीक से आवंटित)। एक सूचक के साथ, सरणी को अलग से आवंटित किया जाता है - जो आप चाहते हैं कि हो सकता है या नहीं भी हो सकता है।

8

सूचक की वास्तव में आवश्यकता नहीं है, इसलिए यह किसी भी लाभ के लिए जगह खर्च करता है। इसके अलावा, यह संकेत का एक और स्तर इंगित कर सकता है, जिसकी वास्तव में आवश्यकता नहीं है।

एक गतिशील पूर्णांक सरणी के लिए इन उदाहरण घोषणाओं की तुलना करें,:

typedef struct { 
    size_t length; 
    int data[0]; 
} IntArray1; 

और:

typedef struct { 
    size_t length; 
    int *data; 
} IntArray2; 

असल में, सूचक को व्यक्त करता है "सरणी के पहले तत्व, इस पते पर है जो कर सकते हैं कुछ भी हो "जो आम तौर पर आवश्यक सामान्य से अधिक सामान्य है। वांछित मॉडल "सरणी का पहला तत्व यहां है, लेकिन मुझे नहीं पता कि सरणी कितनी बड़ी है"।

बेशक, दूसरा फॉर्म "आधार" पता (IntArray2 संरचना का पता) के जोखिम के बिना सरणी को बढ़ाना संभव बनाता है, जो वास्तव में साफ हो सकता है। आप IntArray1 के साथ ऐसा नहीं कर सकते हैं, क्योंकि आपको आधार संरचना और पूर्णांक डेटा तत्वों को एक साथ आवंटित करने की आवश्यकता है। व्यापार-बंद, व्यापार-बंद ...

+0

एक सरणी में शून्य आकार नहीं हो सकता है। C11 6.7.6.2 – Lundin

12

यदि आप एक सूचक का उपयोग करते हैं, तो संरचना अब परिवर्तनीय लंबाई नहीं होगी: इसकी लंबाई तय होगी, लेकिन इसका डेटा एक अलग स्थान पर संग्रहीत किया जाएगा।

शून्य-लंबाई वाले सरणी * के पीछे विचार संरचना में शेष डेटा के साथ "लाइन में" सरणी के डेटा को संग्रहीत करना है, ताकि सरणी का डेटा स्मृति में संरचना के डेटा का पालन कर सके। स्मृति के एक अलग आवंटित क्षेत्र के सूचक आपको ऐसा करने नहीं देते हैं।


* इस तरह की सरणियों भी लचीला सरणियों के रूप में जाना जाता है; सी 99 में आप उन्हें element_type flexArray[0] के बजाय element_type flexArray[] घोषित करते हैं, यानी आप शून्य छोड़ देते हैं।

1

ऐसा इसलिए है क्योंकि एक सूचक के साथ आपको एक अलग आवंटन और असाइनमेंट की आवश्यकता होती है।

struct WithPointer* withPointer = malloc(sizeof(struct WithPointer)); 
withPointer.array = malloc(ARRAY_SIZE * sizeof(int)); 

एक WithArray की 'वस्तु' प्राप्त करने के लिए:

struct WithArray* withArray = malloc(sizeof(struct WithArray) + 
              (ARRAY_SIZE - 1) * sizeof(int)); 

यह है कि

struct WithPointer 
{ 
    int someOtherField; 
    ... 
    int* array; 
}; 

struct WithArray 
{ 
    int someOtherField; 
    ... 
    int array[1]; 
}; 

एक 'वस्तु' WithPointer की आपको बस इतना करना प्राप्त करने के लिए।

कुछ मामलों में यह लगातार स्मृति में सरणी रखने के लिए बहुत आसान, या यहां तक ​​कि आवश्यक है; उदाहरण के लिए नेटवर्क प्रोटोकॉल पैकेट में।

+2

एक सरणी में शून्य आकार नहीं हो सकता है। C11 6.7.6.2 – Lundin

+0

@ लुंडिन आप सही हैं, और ऊपर दिए गए कोड को सही किया। धन्यवाद। –

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