2009-03-19 4 views
5

मैं जल्द ही एक ऑपरेटिंग सिस्टम कोर्स के लिए सी का उपयोग शुरू कर दूंगा और मैं सी का उपयोग करने पर सर्वोत्तम प्रथाओं पर पढ़ रहा हूं ताकि सिरदर्द बाद में कम हो जाएं।क्या सी में संरचना में सरणी और उनकी लंबाई चर लपेटने का यह सबसे अच्छा अभ्यास है?

यह हमेशा ऐरे के बारे में मेरा पहला प्रश्न रहा है क्योंकि उन्हें पेंच करना आसान है।

क्या यह एक सरणी बंडल करने के लिए एक आम प्रथा है और इसके संबंधित चर को संरचना में इसकी लंबाई है?

मैंने इसे कभी भी पुस्तकों में नहीं देखा है और आमतौर पर वे हमेशा दो अलग रखते हैं या आकार (सरणी []/सरणी [1]) जैसे कुछ प्रकार का उपयोग करते हैं।

लेकिन दोनों को एक स्ट्रक्चर में लपेटने के साथ, आप दोनों मूल्यों और संदर्भ द्वारा संरचना को पारित करने में सक्षम होंगे, जो आप पॉइंटर्स का उपयोग करते समय वास्तव में सरणी के साथ नहीं कर सकते हैं, इस मामले में आपको फिर से ट्रैक रखना होगा सरणी लंबाई की।

मैं सी का उपयोग शुरू कर रहा हूं इसलिए उपर्युक्त गलत हो सकता है, मैं अभी भी एक छात्र हूं।

चीयर्स, काई।

+0

प्रतिक्रियाओं हर किसी के लिए धन्यवाद! नोट: मेरा आकार का उपयोग गलत था, इस बात को इंगित करने के लिए अनचाहे करने के लिए धन्यवाद कि ग्लैब में गैरे के असली दुनिया के उदाहरण के लिए भी। – Kai

उत्तर

3

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

कभी-कभी आपके पास उस मामले में दो आकार होते हैं: एक वर्तमान, और एक आवंटित। यह एक ट्रेडऑफ है जहां आप कुछ गति के लिए कम आवंटन का व्यापार करते हैं, थोड़ी मेमोरी ओवरहेड के साथ भुगतान करते हैं।

कई बार सरणी केवल स्थानीय रूप से उपयोग की जाती हैं, और स्थिर आकार के होते हैं, यही कारण है कि sizeof ऑपरेटर तत्वों की संख्या निर्धारित करने के लिए इतना आसान है। , कोष्ठक हमेशा आवश्यक नहीं हैं

int array[4711]; 
int i; 

for(i = 0; i < sizeof array/sizeof *array; i++) 
{ 
    /* Do stuff with each element. */ 
} 

याद रखें कि sizeof एक समारोह नहीं है: आपका वाक्य रचना थोड़ा उस के साथ बंद है, वैसे, यहाँ कैसे यह आम तौर पर नज़र रखता है।

संपादित: वास्तव में जो आप का वर्णन के रूप में एक रैपिंग में से एक वास्तविक दुनिया उदाहरण glib द्वारा प्रदान की GArray प्रकार है। घोषणा के उपयोगकर्ता दृश्य भाग वास्तव में आप क्या वर्णन:

typedef struct { 
    gchar *data; 
    guint len; 
} GArray; 

कार्यक्रम, जब भी संभव हो सरणी पहुँचने के लिए एपीआई का उपयोग करने के लिए सीधे इन क्षेत्रों प्रहार नहीं की संभावना है।

1

मुझे ऐसा करने में कुछ भी गलत नहीं दिख रहा है, लेकिन मुझे लगता है कि ऐसा आमतौर पर ऐसा नहीं किया जाता है क्योंकि इस तरह की संरचना द्वारा किए गए ओवरहेड की वजह से होता है। अधिकांश सी प्रदर्शन कारणों के लिए नंगे धातु कोड है और इस तरह, abstractions अक्सर टाला जाता है।

+0

हम्म ... क्या यह सामान्यीकरण का थोड़ा सा नहीं है? –

5

हां यह सी में होना एक अच्छा अभ्यास है। यह संबंधित मूल्यों को एक संरचना में लपेटने के लिए पूरी तरह तार्किक है।

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

0

मैंने इसे कभी नहीं देखा है, लेकिन मैंने एक दशक से अधिक समय में ओएस स्तर का काम नहीं किया है ... :-) पहली नज़र में उचित दृष्टिकोण की तरह लगता है। केवल चिंता यह सुनिश्चित करने के लिए होगी कि किसी भी तरह का आकार सटीक रहता है ... आवश्यकतानुसार गणना करने से वह चिंता नहीं होती है।

1

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

0

पर विचार करते हुए कि आप सरणी की लंबाई (बाइट्स में, यानी तत्वों में नहीं #) की गणना कर सकते हैं और संकलक वास्तविक मूल्य के साथ आकार() कॉल को प्रतिस्थापित करेगा (यह एक फ़ंक्शन नहीं है, इसे कॉल करने के लिए कॉल किया जाता है संकलक द्वारा मूल्य 'रिटर्न' के साथ), तो एकमात्र कारण जिसे आप इसे एक स्ट्रक्चर में लपेटना चाहते हैं वह पठनीयता के लिए है।

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

+0

आकार के आधार पर समस्या यह है कि यह गतिशील आवंटित सरणी के साथ मदद नहीं करेगा। –

+0

... या जब आप एक सूचक के साथ एक फ़ंक्शन में सरणी पास करते हैं। मूल्य से गुजरने पर सरणी को बदलने के बारे में अंतिम बिंदु पर –

3

तीन तरीके हैं।

  1. स्थिर सरणी के लिए (गतिशील आवंटित नहीं किया और सूचक के रूप में पारित नहीं) आकार है संकलन समय पर जानता है ताकि आप sizeof ऑपरेटर इस्तेमाल किया जा सकता है, इस तरह: sizeof(array)/sizeof(array[0])
  2. उपयोग टर्मिनेटर (पिछले सरणी तत्व के लिए विशेष मूल्य जो नहीं कर सकते नियमित सरणी मान के रूप में उपयोग किया जाना चाहिए), जैसे शून्य-समाप्त तारों
  3. संरचना मूल्य या स्वतंत्र चर के रूप में या तो अलग मान का उपयोग करें। यह वास्तव में कोई फर्क नहीं पड़ता क्योंकि सरणी के साथ काम करने वाले सभी मानक फ़ंक्शन अलग-अलग आकार चर लेते हैं, हालांकि सरणी सूचक और आकार में एक स्ट्रक्चर में शामिल होने से कोड पठनीयता में वृद्धि होगी। मैं आपके अपने कार्यों के लिए एक क्लीनर इंटरफ़ेस रखने के लिए उपयोग करने का सुझाव देता हूं। कृपया ध्यान दें कि यदि आप मूल्य से अपनी संरचना को पास करते हैं, तो फ़ंक्शन सरणी को बदलने में सक्षम होगा, लेकिन आकार परिवर्तनीय नहीं है, इसलिए संरचना पॉइंटर पास करना एक बेहतर विकल्प होगा।
+0

। क्या आपका मतलब है कि आप सरणी को बदल सकते हैं या वस्तुओं को इंगित कर सकते हैं? (यदि यह सूचक की एक सरणी है।) अन्यथा, मैं नहीं देखता कि आप कैसे बदल सकते हैं लेकिन दूसरे को नहीं। – mmccoo

+0

आईडी स्ट्रक्चर में सरणी और सरणी आकार (जैसा कि मैंने उल्लेख किया है) में पॉइंटर होता है, सरणी बदलना कोई समस्या नहीं होगी, क्योंकि सरणी सूचक मूल्य से पारित किया जाएगा, सरणी नहीं – qrdl

1

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

लेकिन यदि आप गतिशील सरणी का उपयोग करते हैं, तो आप संकलन समय पर सरणी के आकार को नहीं जानते हैं। तो अगर आप struct में यह मान स्टोर कर सकते हैं, लेकिन आप यह भी संरचना में सरणी के लिए केवल एक सूचक स्टोर करेगा:

struct Foo { 
    int *myarray; 
    int size; 
}; 

तो तुम मान द्वारा इस संरचना पारित कर सकते हैं, लेकिन क्या तुम सच में करना int करने के लिए सूचक गुजर रहा है (सूचक सरणी के लिए) और int (सरणी का आकार)।

मेरी राय में यह आपकी बहुत मदद नहीं करेगा। प्लस में एकमात्र चीज यह है कि आप आकार और सरणी को एक ही स्थान पर संग्रहीत करते हैं और सरणी का आकार प्राप्त करना आसान है। यदि आप बहुत गतिशील सरणी का उपयोग करेंगे तो आप इसे इस तरह से कर सकते हैं। लेकिन यदि आप कुछ सरणी का उपयोग करेंगे, तो संरचनाओं का उपयोग करना आसान नहीं होगा।

+0

एएनएसआई सी संदर्भ द्वारा गुजरने वाले चर का समर्थन नहीं करता है । शायद आप सी ++ के बारे में सोच रहे हैं? –

+0

मैं सी के बारे में सोच रहा था, लेकिन यह बहुत समय पहले था जब मैं सी में लिख रहा था, इसलिए यह मेरी गलती है। – klew

+0

+1 "प्लस में एकमात्र चीज है, यह है कि आप आकार और सरणी को एक ही स्थान पर संग्रहीत करते हैं ..."। यह आपको एक परिवर्तनीय नाम और फ़ंक्शन पैरामीटर बचाएगा, लेकिन कोई स्मृति या गति नहीं। – potrzebie

2

सार्वजनिक एपीआई के लिए मैं सरणी के साथ जाऊंगा और आकार मान अलग हो जाएगा। इस तरह यह सबसे अधिक (यदि नहीं सभी) सी लाइब्रेरी में मुझे संभाला जाता है। आप इसे आंतरिक रूप से कैसे संभालेंगे यह पूरी तरह से आपके ऊपर है। तो एक संरचना का उपयोग करके कुछ सहायक कार्यों/मैक्रोज़ जो आपके लिए मुश्किल भागों को करते हैं, एक अच्छा विचार है।यह हमेशा मुझे एक आइटम डालने या हटाने के लिए फिर से सोचने के लिए सिर-दर्द बना रहा है, इसलिए यह समस्याओं का एक अच्छा स्रोत है। एक बार और जेनेरिक हल करने से, आपको शुरुआत से कम बग प्राप्त करने में मदद मिलती है। गतिशील और जेनेरिक सरणी के लिए एक अच्छा कार्यान्वयन kvec है।

+0

मैं एक 'संरचना {शून्य * पीआरटी का उपयोग नहीं करता; size_t len;}; * किसी भी * फ़ंक्शन एपीआई के पैरामीटर के रूप में, क्योंकि आप उदा। पहले तत्व की तुलना में एक अलग पता पास करके और/या सरणी की पूरी लंबाई की तुलना में एक अलग लंबाई गुजरकर एक सूची का केवल भाग क्रमबद्ध करें। – potrzebie

+0

... इसलिए यदि आप अमूर्तता चाहते हैं लेकिन अभी भी सरणी के हिस्सों तक पहुंचने की आवश्यकता है, तो एक सरणी स्लाइस संरचना शायद बेहतर होगी। आपके पास एक सरणी स्लाइस वेरिएबल हो सकता है जो पूरे सरणी को इंगित करता है और स्पैन करता है, और अन्य सरणी स्लाइस चर/मान जो आपके द्वारा काम किए जा रहे हिस्सों को इंगित करता है और स्पैन करता है। – potrzebie

2

मैं कहूंगा कि यह एक अच्छा अभ्यास है। वास्तव में, यह काफी अच्छा है कि सी ++ में उन्होंने इसे मानक पुस्तकालय में रखा है और इसे vector कहा है। जब भी आप सी ++ फोरम में एरे के बारे में बात करते हैं, तो आप प्रतिक्रियाओं के साथ गंदे हो जाएंगे जो इसके बजाय vector का उपयोग करने के लिए कहते हैं।

0

मुझे लगता है कि आपके सवाल का के इस भाग पीछे की ओर है:

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

चारों ओर सरणी पास करते समय पॉइंटर्स का उपयोग डिफ़ॉल्ट व्यवहार है; जो मूल्य से पूरे सरणी को पारित करने के मामले में आपको कुछ भी नहीं खरीदता है। यदि आप एक पॉइंटर को क्षय होने की बजाय पूरे सरणी की प्रतिलिपि बनाना चाहते हैं तो आपको किसी स्ट्रक्चर में सरणी को लपेटने की आवश्यकता है।

Pass array by value to recursive function possible?

और यहाँ सरणियों के विशेष व्यवहार के बारे में अधिक है: अधिक जानकारी के लिए इस उत्तर देखें

http://denniskubes.com/2012/08/20/is-c-pass-by-value-or-reference/

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

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