एक सरणी का आयाम इसके प्रकार का हिस्सा क्यों है?


14

सी ++ प्राइमर किताब को पढ़ते हुए, मैं इस कथन के साथ आया: "किसी सरणी में तत्वों की संख्या सरणी के प्रकार का हिस्सा है।" इसलिए मैं निम्नलिखित कोड का उपयोग करके पता लगाना चाहता था:

#include<iostream>

int main()
{
    char Array1[]{'H', 'e', 'l', 'p'};
    char Array2[]{'P', 'l', 'e', 'a', 's', 'e'};

    std::cout<<typeid(Array1).name()<<std::endl;        //prints  A4_c
    std::cout<<typeid(Array2).name()<<std::endl;        //prints  A6_c

    return 0;
}

और दिलचस्प रूप से दो सरणियों पर टाइपिड के परिणाम से पता चला कि वे किसी तरह अलग हैं।

  • पर्दे के पीछे क्या चल रहा है?
  • सरणी के लिए ऐसा क्यों आवश्यक है कि उसका आकार शामिल हो? क्या सिर्फ इसलिए कि इसका आकार नहीं बदलना चाहिए?
  • यह तुलनात्मक सरणियों को कैसे प्रभावित करेगा?

बस अवधारणा को गहराई से समझने में सक्षम होना चाहते हैं।


3
आकार की जानकारी को प्रकार में शामिल करना कड़ाई से आवश्यक नहीं है , लेकिन यह उपयोगी है
byxor

सरणियों पर कोई भी ट्यूटोरियल समझाएगा (1)। मुझे यकीन नहीं है कि आप (3) से क्या मतलब है, क्योंकि सरणियों की तुलना करने के लिए कोई अंतर्निहित तरीका नहीं है।
होलीब्लैककैट

जवाबों:


20

पर्दे के पीछे क्या चल रहा है?

एक गैर-गतिशील रूप से आवंटित, परिभाषा के अनुसार, सजातीय तत्वों के एक निश्चित आकार के कंटेनर है। प्रकार के Nतत्वों की एक सरणी को Tस्मृति में Nप्रकार की वस्तुओं के एक सन्निहित अनुक्रम के रूप में रखा जाता है T


सरणी के लिए एक प्रकार का होना क्यों आवश्यक है जिसमें इसका आकार शामिल है?

मुझे विश्वास नहीं है कि यह किसी सरणी के प्रकार के लिए "आवश्यक" है, इसमें आकार शामिल है - तथ्य की बात के रूप में, आप Tऑब्जेक्ट के एक सन्निहित अनुक्रम को संदर्भित करने के लिए एक सूचक का उपयोग कर सकते हैं । इस तरह के सूचक सरणी के बारे में जानकारी खो देंगे।

हालाँकि, यह एक उपयोगी चीज़ है। यह प्रकार की सुरक्षा में सुधार करता है, और संकलन-समय पर उपयोगी जानकारी को एन्कोड करता है जिसे कई तरीकों से उपयोग किया जा सकता है। एक उदाहरण के रूप में, आप विभिन्न आकारों के सरणियों पर अधिभार के लिए संदर्भ-से-सरणियों का उपयोग कर सकते हैं

void foo(int(&array)[4]) { /* ... */ }
void foo(int(&array)[8]) { /* ... */ }

या एक स्थिर अभिव्यक्ति के रूप में एक सरणी के आकार का पता लगाने के लिए

template <typename T, std::size_t N>
constexpr auto sizeOf(const T(&array)[N]) { return N; }

यह तुलनात्मक सरणियों को कैसे प्रभावित करेगा?

यह वास्तव में नहीं है।

आप सी-स्टाइल सरणियों की उसी तरह से तुलना नहीं कर सकते हैं जिस तरह से आप दो संख्याओं (उदाहरण intवस्तुओं) की तुलना करेंगे । आपको किसी प्रकार की लेक्सोग्राफिक तुलना लिखना होगा, और यह तय करना होगा कि विभिन्न आकारों के संग्रह के लिए इसका क्या अर्थ है। std::vector<T>यह प्रदान करता है , और उसी तर्क को सरणियों पर लागू किया जा सकता है।


बोनस: सी ++ 11 और इसके बाद के संस्करण प्रदान करता है std::array, जो एक सी-स्टाइल सरणी के चारों ओर एक कंटेनर-जैसा इंटरफ़ेस है। इसे सी-स्टाइल सरणियों के लिए पसंद किया जाना चाहिए क्योंकि यह अन्य कंटेनरों (जैसे std::vector<T>) के साथ अधिक सुसंगत है , और बॉक्स से बाहर लेक्सोग्राफिक तुलना का भी समर्थन करता है ।


2
"आपको किसी प्रकार की अलौकिक तुलना लिखना होगा, और यह तय करना होगा कि विभिन्न आकारों के संग्रह के लिए इसका क्या अर्थ है।" आप बस उपयोग कर सकते हैं std::equal(के माध्यम से std::beginऔर std::endजो सरणियों के लिए परिभाषित हैं)। उस स्थिति में, विभिन्न आकार के सरणियाँ गैर-बराबर होती हैं।
स्टु

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

8

जब आप इसे बनाते हैं तो किसी वस्तु को कितनी जगह आवंटित की जाती है यह पूरी तरह से उसके प्रकार पर निर्भर करता है। मैं जिस एलोकेशन के बारे में बात कर रहा हूं, वह आवंटन से newया के पास नहीं है malloc, लेकिन जो स्थान आवंटित किया गया है, ताकि आप अपना कंस्ट्रक्टर चला सकें और अपनी वस्तु को इनिशियलाइज़ कर सकें।

यदि आपके पास एक संरचना है (उदाहरण के लिए)

struct A { char a, b; }; //sizeof(A) == 2, ie an A needs 2 bytes of space

तब जब आप वस्तु का निर्माण करते हैं:

A a{'a', 'b'};

आप एक प्रक्रिया के रूप में वस्तु के निर्माण की प्रक्रिया के बारे में सोच सकते हैं:

  • अंतरिक्ष के 2 बाइट्स आवंटित करें (स्टैक पर, लेकिन जहां इस उदाहरण के लिए कोई फर्क नहीं पड़ता)
  • ऑब्जेक्ट का निर्माता चलाएँ (इस मामले में कॉपी 'a'और 'b'ऑब्जेक्ट पर)

यह ध्यान रखना महत्वपूर्ण है कि आवश्यक अंतरिक्ष के 2 बाइट्स पूरी तरह से ऑब्जेक्ट के प्रकार से निर्धारित होते हैं, फ़ंक्शन के तर्क मायने नहीं रखते हैं। इसलिए, एक सरणी के लिए प्रक्रिया समान है, सिवाय इसके कि अंतरिक्ष की मात्रा की आवश्यकता सरणी में तत्वों की संख्या पर निर्भर करती है।

char a[] = {'a'}; //need space for 1 element
char b[] = {'a', 'b', 'c', 'd', 'e'}; //need space for 5 elements

के प्रकार तो aऔर bतथ्य यह है कि प्रतिबिंबित करना चाहिए a1 वर्ण के लिए पर्याप्त जगह की जरूरत है और b5 वर्ण के लिए पर्याप्त जगह की जरूरत है। इसका मतलब यह है कि इन सरणियों का आकार अचानक नहीं बदल सकता है, एक बार 5-तत्व सरणी बनाने के बाद यह हमेशा 5-तत्व सरणी होता है। "सरणी" जैसी वस्तुओं के लिए जहां आकार अलग-अलग हो सकते हैं, आपको गतिशील मेमोरी आवंटन की आवश्यकता होती है, जिसे आपकी पुस्तक को किसी बिंदु पर कवर किया जाना चाहिए।


0

यह रनटाइम लाइब्रेरी के लिए एक आंतरिक कारण है। यदि आप निम्न कथनों पर विचार करते हैं, उदाहरण के लिए:

unsigned int i;
unsigned int *iPtr;
unsigned int *iPtrArr[2];
unsigned int **iPtrHandle;

फिर यह स्पष्ट हो जाता है कि समस्या क्या है: उदाहरण के लिए, संबोधन को unsigned int *स्वयं के sizeof operatorसंबोधन के साथ ही चिंतित होना पड़ता है unsigned int

बाकी जो कुछ आप यहाँ देखते हैं, उसके लिए एक अधिक विस्तृत विवरण है, लेकिन यह मुख्य रूप से C प्रोग्रामिंग भाषा, कर्निघन और रिची द्वारा 2 संस्करण में कवर किया गया कार्यक्रम का विषय है जो घोषित प्रकार के सादे भाषा पाठ को प्रिंट करता है। स्ट्रिंग।

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