आप अपनी पोस्ट में जो कह रहे हैं वह बिल्कुल सही है। मैं कहूँगा कि हर C डेवलपर बिल्कुल एक ही खोज पर आता है और ठीक उसी निष्कर्ष पर पहुँचता है जब (यदि) वे C भाषा के लिए किसी विशेष स्तर तक पहुँचते हैं।
जब आपके एप्लिकेशन क्षेत्र की बारीकियों को विशिष्ट निश्चित आकार (सरणी आकार एक संकलन-समय स्थिर है) की एक सरणी के लिए कॉल किया जाता है, तो इस तरह के एक सरणी को किसी फ़ंक्शन में पास करने का एकमात्र उचित तरीका सूचक-टू-सरणी पैरामीटर का उपयोग करके होता है
void foo(char (*p)[10]);
(C ++ भाषा में यह संदर्भ के साथ भी किया गया है
void foo(char (&p)[10]);
)।
यह भाषा-स्तरीय प्रकार की जांच को सक्षम करेगा, जो सुनिश्चित करेगा कि तर्क के रूप में बिल्कुल सही आकार के सरणी की आपूर्ति की जाती है। वास्तव में, कई मामलों में लोग इस तकनीक का उपयोग करते हैं, बिना इसे साकार किए भी, टाइप टाइप नाम के पीछे सरणी प्रकार छिपाते हुए।
typedef int Vector3d[3];
void transform(Vector3d *vector);
/* equivalent to `void transform(int (*vector)[3])` */
...
Vector3d vec;
...
transform(&vec);
इसके अलावा ध्यान दें कि उपरोक्त कोड Vector3dएक सरणी या एक प्रकार के संबंध में अपरिवर्तनीय है struct। आप Vector3dकिसी भी समय की परिभाषा को ऐरे से structपीछे और पीछे से स्विच कर सकते हैं , और आपको फ़ंक्शन की घोषणा को बदलना नहीं पड़ेगा। या तो मामले में कार्यों को "संदर्भ द्वारा" एक समग्र वस्तु प्राप्त होगी (इसके अपवाद हैं, लेकिन इस चर्चा के संदर्भ में यह सच है)।
हालाँकि, आप सरणी के इस तरीके को स्पष्ट रूप से बहुत बार उपयोग करते हुए नहीं देखेंगे, केवल इसलिए कि बहुत से लोग बल्कि एक जटिल वाक्यविन्यास से भ्रमित हो जाते हैं और बस सी भाषा की ऐसी विशेषताओं के साथ पर्याप्त रूप से सहज नहीं होते हैं ताकि उनका सही उपयोग कर सकें। इस कारण से, औसत वास्तविक जीवन में, एक सरणी को इसके पहले तत्व के लिए एक संकेतक के रूप में पारित करना एक अधिक लोकप्रिय दृष्टिकोण है। यह सिर्फ "सरल" दिखता है।
लेकिन वास्तव में, सरणी पासिंग के लिए पहले तत्व के लिए पॉइंटर का उपयोग करना एक बहुत ही आला तकनीक है, एक ट्रिक, जो एक बहुत ही विशिष्ट उद्देश्य को पूरा करती है: इसका एक और एकमात्र उद्देश्य पासिंग सरणियों को सुविधाजनक बनाना है। विभिन्न आकार (यानी रन-टाइम आकार) के । यदि आपको वास्तव में रन-टाइम आकार के सरणियों को संसाधित करने में सक्षम होने की आवश्यकता है, तो इस तरह के एक सरणी को पास करने का उचित तरीका एक सूचक द्वारा अपने पहले तत्व के लिए एक अतिरिक्त पैरामीटर द्वारा आपूर्ति की गई ठोस आकार है।
void foo(char p[], unsigned plen);
दरअसल, कई मामलों में रन-टाइम आकार के सरणियों को संसाधित करने में सक्षम होना बहुत उपयोगी है, जो विधि की लोकप्रियता में भी योगदान देता है। कई सी डेवलपर्स बस एक निश्चित आकार के सरणी को संसाधित करने के लिए कभी भी मुठभेड़ नहीं करते (या कभी नहीं पहचानते हैं), इस प्रकार उचित निश्चित आकार की तकनीक से बेखबर रहते हैं।
फिर भी, यदि सरणी का आकार तय हो गया है, तो यह एक तत्व के लिए एक संकेतक के रूप में गुजर रहा है
void foo(char p[])
एक प्रमुख तकनीक-स्तरीय त्रुटि है, जो इन दिनों दुर्भाग्य से व्यापक है। इस तरह के मामलों में एक पॉइंटर-टू-एरे तकनीक एक बेहतर तरीका है।
एक और कारण जो निश्चित आकार की सरणी पासिंग तकनीक को अपनाने में बाधा उत्पन्न कर सकता है, वह है डायनामिक रूप से आवंटित किरणों के टाइप करने के लिए भोले दृष्टिकोण का प्रभुत्व। उदाहरण के लिए, यदि प्रोग्राम प्रकार के निश्चित सरणियों के लिए कहता है char[10](जैसा कि आपके उदाहरण में), एक औसत डेवलपर इस mallocतरह के सरणियों के रूप में करेगा
char *p = malloc(10 * sizeof *p);
इस ऐरे को घोषित फंक्शन में पास नहीं किया जा सकता है
void foo(char (*p)[10]);
जो औसत डेवलपर को भ्रमित करता है और उन्हें एक निश्चित विचार दिए बिना निश्चित आकार के पैरामीटर घोषणा को छोड़ देता है। हालांकि वास्तविकता में, समस्या की जड़ भोले mallocदृष्टिकोण में निहित है । mallocऊपर दिखाए गए प्रारूप रन-टाइम आकार की सरणियों के लिए आरक्षित किया जाना चाहिए। यदि सरणी प्रकार का संकलन-समय आकार है, तो इसका एक बेहतर तरीका mallocनिम्नानुसार होगा
char (*p)[10] = malloc(sizeof *p);
यह, निश्चित रूप से, उपरोक्त घोषित करने के लिए आसानी से पारित किया जा सकता है foo
foo(p);
और संकलक उचित प्रकार की जाँच करेगा। लेकिन फिर, यह एक अप्रस्तुत सी डेवलपर के लिए अति भ्रमित है, यही कारण है कि आप इसे "सामान्य" औसत रोजमर्रा के कोड में बहुत बार नहीं देखेंगे।
10इसे किसी भी चर के दायरे में बदला जा सकता है