दिलचस्प पोस्ट
यूपीएफ -8 में php regex शब्द सीमा मिलान Wchar_t * को char * कैसे परिवर्तित करें? देश का पता लगाने का सबसे अच्छा तरीका / आगंतुक का स्थान? मोबाइल एप्लिकेशन में ऑथ रहस्य सी / सी ++ बनाम क्लास बनाम डबल घुंघराले ब्रेसिज़ के साथ AngularJS-Twig संघर्ष WPF / C # में विभिन्न लोकेल कीबोर्ड पर '#' कैरेक्टर कैप्चर कैसे करें? MySQL: रैंडम एंट्री चुनें, लेकिन कुछ प्रविष्टियों के लिए वजन स्विफ्ट 3.1 को इनिशियलाइज़ () से हटा दिया गया मैं एक ही चीज़ कैसे प्राप्त कर सकता हूं? Internet Explorer में Mozilla's toSource () विधि को लागू करना html5 समय इनपुट 12 घंटे दिखाता है रिलेशनल डेटाबेस में आईपीवी 6-संगत पते को कैसे स्टोर करना है क्या अजगर का समर्थन मल्टीप्रोसेसर / मल्टीकोर प्रोग्रामिंग है? प्रमाणीकरण त्रुटियों के बाद मैं PrimeFaces AJAX का उपयोग कर एक पाठ फ़ील्ड कैसे आबाद कर सकता हूं? स्ट्रिंग के संभव संयोजन प्रदर्शित करें

सी पॉइंटर्स: निश्चित आकार की एक सरणी की ओर इशारा करते हैं

यह सवाल सी गुरुओं को वहां से बाहर जाता है:

सी में, निम्नानुसार एक संकेतक घोषित करना संभव है:

char (* p)[10]; 

.. जो मूल रूप से कहता है कि यह सूचक 10 वर्णों की एक सरणी को दर्शाता है इस तरह एक संकेतक घोषित करने के बारे में साफ बात यह है कि यदि आप पी के आकार के विभिन्न सरणी के एक सूचक को निर्दिष्ट करने का प्रयास करते हैं, तो आपको एक संकलन समय त्रुटि मिलेगी। यदि आप पी के लिए एक साधारण वर्ण सूचक का मान असाइन करने का प्रयास करते हैं, तो यह आपको एक संकलन समय त्रुटि भी देगा। मैंने इसे जीसीसी के साथ करने की कोशिश की और यह एएनएसआई, सी 8 9 और सीएएम के साथ काम करने लगता है।

मुझे ऐसा लगता है जैसे एक संकेतक की घोषणा करना बहुत उपयोगी होगा – विशेष रूप से, जब किसी फ़ंक्शन पर कोई संकेतक गुजरता हो आमतौर पर, लोग इस तरह के एक समारोह के प्रोटोटाइप लिखेंगे:

 void foo(char * p, int plen); 

यदि आप किसी विशिष्ट आकार के बफ़र की अपेक्षा कर रहे थे, तो आप बस के मूल्य का परीक्षण करेंगे। हालांकि, आपको यह गारंटी नहीं दी जा सकती कि जिस व्यक्ति ने आप को पी पास किया है वह वास्तव में आपको उस बफर में मान्य स्मृति स्थानों को प्रदान करेगा। आपको इस बात पर भरोसा करना होगा कि जो व्यक्ति इस फ़ंक्शन को बुलाता है वह सही काम कर रहा है। दूसरी ओर:

 void foo(char (*p)[10]); 

..क्या आपको निर्दिष्ट आकार के बफर देने के लिए कॉलर को बल देना होगा।

यह बहुत उपयोगी लगता है, लेकिन मैंने कभी भी इस तरह की किसी भी संहिता की घोषणा नहीं की जो मैंने कभी भी पूरे किए है।

मेरा सवाल है: क्या कोई कारण है कि लोग इस तरह के संकेतक नहीं घोषित करते हैं? क्या मुझे कुछ स्पष्ट गड़बड़ नहीं दिख रहा है?

वेब के समाधान से एकत्रित समाधान "सी पॉइंटर्स: निश्चित आकार की एक सरणी की ओर इशारा करते हैं"

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

जब आपके ऐप्लीकेशन क्षेत्र की विशेषताओं को निश्चित निश्चित आकार के सरणी के लिए कॉल करना (सरणी आकार एक संकलन-समय स्थिर होता है), फ़ंक्शन में ऐसी किसी सरणी को पास करने का एकमात्र उचित तरीका पॉइंटर-टू-ऑरेरे पैरामीटर का उपयोग कर रहा है

 void foo(char (*p)[10]); 

(सी ++ भाषा में यह संदर्भ के साथ भी किया जाता है

 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 आप एक सरणी से किसी भी समय struct और बैक में Vector3d की परिभाषा को बदल सकते हैं, और आपको फ़ंक्शन घोषणापत्र बदलना नहीं होगा। या तो मामले में कार्यों को "संदर्भ द्वारा" एक समग्र वस्तु प्राप्त होगी (इसमें अपवाद हैं, लेकिन इस चर्चा के संदर्भ में यह सच है)।

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

लेकिन सच्चाई में, सरणी को पार करने के लिए पहले तत्व को सूचक का उपयोग करना एक बहुत ही विशिष्ट तकनीक है, जो एक चाल है, जो एक विशिष्ट उद्देश्य प्रदान करती है: इसका एकमात्र उद्देश्य अलगअलग आकार (यानी रन-टाइम आकार) । यदि आपको वास्तव में रन-टाइम आकार के सरणियों पर कार्य करने की आवश्यकता है, तो इस तरह के एक सरणी को पारित करने का सही तरीका एक सूचक द्वारा अपने पहले तत्व के द्वारा होता है जिसमें एक अतिरिक्त पैरामीटर

 void foo(char p[], unsigned plen); 

दरअसल, कई मामलों में यह रन-टाइम आकार के सरणियों को प्रोसेस करने में सक्षम होता है, जो विधि की लोकप्रियता में भी योगदान देता है। कई सी डेवलपर्स को कभी भी एक निश्चित आकार के ऑरेक्शन को संसाधित करने की आवश्यकता नहीं (या कभी भी नहीं पहचानते), इस प्रकार उचित निश्चित आकार की तकनीक से बेखबर रहता है।

फिर भी, यदि सरणी का आकार तय हो गया है, तो उसे एक तत्व के रूप में एक सूचक के रूप में देना होगा

 void foo(char p[]) 

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

एक और कारण है कि तय-आकार की सरणी के पास तकनीक को अपनाने में बाधा उत्पन्न हो सकती है गतिशील रूप से आवंटित सरणियों के टाइपिंग के लिए सरल दृष्टिकोण का प्रभुत्व है। उदाहरण के लिए, यदि कार्यक्रम निश्चित प्रकार के प्रकार के char[10] लिए कॉल करता है 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); 

और कंपाइलर उचित प्रकार की जांच करेगा। लेकिन फिर, यह एक अपरिवर्तनीय सी डेवलपर के लिए अत्यधिक भ्रमित है, यही कारण है कि आप इसे अक्सर "ठेठ" औसत रोज़ कोड में नहीं देख पाएंगे।

मैं एंड्रीटी के उत्तर में जोड़ना चाहूंगा (यदि इस पृष्ठ पर कोई भी इस विषय पर अधिक जानकारी की तलाश में ठोकर खाएगा):

जैसा कि मैं इन घोषणाओं के साथ अधिक खेलना शुरू करता हूं, मुझे एहसास है कि सी में उनके साथ जुड़ी बड़ी बाधा है (जाहिरा तौर पर सी ++ में नहीं) ऐसी परिस्थिति में काफी आम है, जहां आप कॉलर को एक बफर में एक कन्स्ट्रक्टर पॉइंटर दे सकते हैं, जिसमें आपने लिखा है। दुर्भाग्य से, यह संभव नहीं है जब सी में इस तरह एक संकेतक घोषित करते हैं, दूसरे शब्दों में, सी मानक (6.7.3 – पैरा 8) इस तरह से कुछ के साथ अंतर है:

 int array[9]; const int (* p2)[9] = &array; /* Not legal unless array is const as well */ 

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

यह मेरी राय में एक गंभीर बाधा है और यह मुख्य कारणों में से एक हो सकता है कि क्यों लोग आमतौर पर सी। में इस तरह के संकेतक नहीं घोषित करते हैं। अन्य तथ्य यह है कि अधिकांश लोगों को यह भी नहीं पता है कि आप इस तरह एक संकेतक घोषित कर सकते हैं एंड्रीटी ने बताया है

स्पष्ट कारण यह है कि यह कोड संकलित नहीं करता है:

 extern void foo(char (*p)[10]); void bar() { char p[10]; foo(p); } 

सरणी का डिफ़ॉल्ट प्रचार एक अयोग्य अंकन के लिए है।

इस प्रश्न को भी देखें, foo(&p) का उपयोग करके काम करना चाहिए

खैर, बस रखिए, सी चीजों को इस तरह से नहीं करता है प्रकार T की एक सरणी सरणी में पहली T को सूचक के रूप में चारों ओर पारित कर दी जाती है, और ये आपको मिलती है

यह कुछ शांत और सुरुचिपूर्ण एल्गोरिदम के लिए अनुमति देता है, जैसे अभिव्यक्तियों की तरह सरणी के माध्यम से पाशन करना

 *dst++ = *src++ 

नकारात्मक पक्ष यह है कि आकार का प्रबंधन आपके ऊपर है। दुर्भाग्य से, इस धर्मनिरपेक्ष रूप से करने में विफलता ने सी कोडन में लाखों कीड़े भी पैदा कर दी हैं, और / या दुर्भावनापूर्ण शोषण के लिए अवसरों का कारण बनता है।

क्या आप सी में पूछना के करीब आता है एक struct (मूल्य के आधार पर) या एक सूचक (एक संदर्भ के अनुसार) के पास पारित करने के लिए है जब तक वही संरचना प्रकार इस ऑपरेशन के दोनों किनारों पर उपयोग किया जाता है, दोनों कोड जो संदर्भ और कोड का उपयोग करता है, को संभालने में डेटा के आकार के बारे में सहमति है।

आपके स्ट्रेट में जो भी डेटा होता है, वह हो सकता है; यह एक अच्छी तरह से परिभाषित आकार के अपने सरणी को शामिल कर सकता है

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

आप वर्णों की एक सरणी को कई तरीकों से घोषित कर सकते हैं:

 char p[10]; char* p = (char*)malloc(10 * sizeof(char)); 

एक फ़ंक्शन के लिए प्रोटोटाइप जो मान से एक सरणी लेता है:

 void foo(char* p); //cannot modify p 

या संदर्भ से:

 void foo(char** p); //can modify p, derefernce by *p[0] = 'f'; 

या सरणी सिंटैक्स द्वारा:

 void foo(char p[]); //same as char* 

मैं इस समाधान की सिफारिश नहीं करेगा

 typedef int Vector3d[3]; 

क्योंकि यह इस तथ्य को अस्पष्ट करता है कि वेक्टर 3 डी में एक प्रकार है जिसे आपको इसके बारे में पता होना चाहिए। प्रोग्रामर आमतौर पर एक ही प्रकार के भिन्न आकारों की अपेक्षा नहीं करते हैं। विचार करें :

 void foo(Vector3d a) { Vector3D b; } 

जहां sizeof एक! = sizeof बी

मैं और अधिक प्रकार की जांच को सक्षम करने के लिए इस सिंटैक्स का भी उपयोग करना चाहता हूं।

लेकिन मैं यह भी मानता हूं कि पॉइंटर्स का उपयोग करने का वाक्यविन्यास और मानसिक मॉडल सरल और याद रखना आसान है।

यहां आने वाले कुछ और बाधाएं हैं I

  • सरणी तक पहुंच (*p)[] :

     void foo(char (*p)[10]) { char c = (*p)[3]; (*p)[0] = 1; } 

    इसके बजाय स्थानीय पॉइंटर-से-चार का उपयोग करने के लिए आकर्षक है:

     void foo(char (*p)[10]) { char *cp = (char *)p; char c = cp[3]; cp[0] = 1; } 

    लेकिन यह सही प्रकार का उपयोग करने के उद्देश्य से आंशिक रूप से हार जाएगा।

  • किसी को एक सरणी के पते को पॉइंटर-टू-ऑरेरे को निर्दिष्ट करते समय ऑपरेटर के पते का उपयोग करना याद रखना चाहिए:

     char a[10]; char (*p)[10] = &a; 

    ऑपरेटर का पता सही एरे के पते को &a , सही प्रकार के साथ इसे p निर्दिष्ट करें। ऑपरेटर के बिना, a स्वचालित रूप से सरणी के पहले तत्व के पते में परिवर्तित हो जाता है, जैसा कि &a[0] , जिसका एक अलग प्रकार है।

    चूंकि यह स्वत: रूपांतरण पहले से ही हो रहा है, मैं हमेशा यह है कि आवश्यक & आवश्यक है यह अन्य प्रकार के वेरिएबल्स के उपयोग के अनुरूप है, लेकिन मुझे यह याद रखना होगा कि एक सरणी विशेष है और मुझे सही प्रकार का पता पाने की आवश्यकता है, भले ही पता मान समान है।

    मेरी समस्या का एक कारण यह हो सकता है कि मैंने कश्मीर और आर सी को वापस 80 के दशक में पढ़ा, जो कि अब तक पूरे सरणियों पर & ऑपरेटर के उपयोग की अनुमति नहीं देता (हालांकि कुछ कंपाइलर्स ने इसे अनदेखा किया था या सिंटैक्स को सहन किया था)। जो, वैसे, एक और कारण हो सकता है कि संकेतक-टू-ऑरेंजों को अपनाया जाने का कठिन समय हो सकता है: वे केवल एएनएसआई सी के ठीक से काम करते हैं, और ऑपरेटर की सीमा उनके लिए बहुत अजीब समझने के लिए एक और कारण हो सकता है।

  • जब typedef पॉइंटर-टू-अरै (एक सामान्य हेडर फाइल में) के लिए एक प्रकार बनाने के लिए उपयोग नहीं किया जाता है, तो एक वैश्विक पॉइंटर-टू- extern को फ़ाइलों में इसे साझा करने के लिए एक और अधिक जटिल extern घोषणा की आवश्यकता है:

     fileA: char (*p)[10]; fileB: extern char (*p)[10]; 

शायद मुझे कुछ याद आ रहा है, लेकिन … क्योंकि सरणियाँ लगातार संकेत हैं, मूल रूप से इसका मतलब है कि उन्हें पॉइंटर्स के पास से गुजारने का कोई मतलब नहीं है।

क्या आप बस void foo(char p[10], int plen); उपयोग नहीं कर सकते हैं void foo(char p[10], int plen); ?

मेरे कंपाइलर (बनाम 2008) पर यह char (*p)[10] को वर्ण संकेतों की एक सरणी के रूप में मानता है, जैसे कि कोई कोष्ठक नहीं था, भले ही मैं सी फ़ाइल के रूप में संकलित हो इस "चर" के लिए संकलक समर्थन है? यदि ऐसा है तो इसका उपयोग करने के लिए एक प्रमुख कारण नहीं है।