जब वे कभी लागू नहीं होते हैं, तो सी और सी ++ कंपाइलर फ़ंक्शन हस्ताक्षर में सरणी लंबाई की अनुमति क्यों देते हैं?


131

यह मैंने अपने सीखने की अवधि के दौरान पाया:

#include<iostream>
using namespace std;
int dis(char a[1])
{
    int length = strlen(a);
    char c = a[2];
    return length;
}
int main()
{
    char b[4] = "abc";
    int c = dis(b);
    cout << c;
    return 0;
}  

तो चर में int dis(char a[1]), [1]कुछ भी नहीं करने के लिए लगता है और बिल्कुल काम नहीं करता है
, क्योंकि मैं उपयोग कर सकता हूं a[2]। ऐसे ही int a[]या char *a। मुझे पता है कि सरणी नाम एक सूचक है और एक सरणी को कैसे व्यक्त किया जाए, इसलिए मेरी पहेली इस भाग के बारे में नहीं है।

मैं जानना चाहता हूं कि संकलक इस व्यवहार की अनुमति क्यों देते हैं ( int a[1])। या इसके अन्य अर्थ हैं जिनके बारे में मुझे जानकारी नहीं है?


6
ऐसा इसलिए है क्योंकि आप वास्तव में फ़ंक्शन के लिए सरणियाँ पास नहीं कर सकते हैं।
एड एस।

37
मुझे लगता है कि यहां सवाल यह था कि सी आपको एक पैरामीटर को सरणी प्रकार का घोषित करने की अनुमति देता है जब यह वैसे भी एक पॉइंटर की तरह बिल्कुल व्यवहार करने वाला है।
ब्रायन

8
@ ब्रायन: मुझे यकीन नहीं है कि यह एक तर्क है या व्यवहार के खिलाफ है, लेकिन यह भी लागू होता है यदि तर्क प्रकार typedefसरणी प्रकार के साथ है। तो तर्क प्रकारों में "क्षयकर्ता को संकेत" बस के []साथ प्रतिस्थापित होने वाली चीनी नहीं है *, यह वास्तव में प्रकार प्रणाली से गुजर रहा है। यह कुछ मानक प्रकारों के लिए वास्तविक दुनिया परिणाम है जैसे va_listकि सरणी या गैर-सरणी प्रकार के साथ परिभाषित किया जा सकता है।
R .. गिटहब स्टॉप हेल्पिंग ICE

4
@songyuanyao आप एक सूचक का उपयोग करके C (और C ++) में पूरी तरह से भिन्न नहीं हो सकते int dis(char (*a)[1])। उसके बाद, आप एक सरणी के लिए एक पॉइंटर पास करते हैं dis(&b):। आप सी विशेषताएं है कि सी में मौजूद नहीं है का उपयोग करने के लिए तैयार हैं ++, आप भी चीजों की तरह कह सकते हैं void foo(int data[static 256])और int bar(double matrix[*][*]), लेकिन यह कीड़े की एक पूरी अन्य सकता है।
स्टुअर्ट ऑलसेन

1
@StuartOlsen वह बिंदु जो मानक को परिभाषित नहीं करता है। मुद्दा यह है कि जिसने भी इसे परिभाषित किया है उसने इसे इस तरह परिभाषित किया है।
user253751

जवाबों:


156

यह फ़ंक्शन के लिए सरणियों को पारित करने के लिए सिंटैक्स का एक क्विक है।

वास्तव में C. में किसी सरणी को पास करना संभव नहीं है। यदि आप ऐसा वाक्यविन्यास लिखते हैं जो दिखता है कि यह सरणी को पास करना चाहिए, तो वास्तव में क्या होता है कि सरणी के पहले तत्व के लिए एक सूचक इसके बजाय पारित किया जाता है।

चूंकि सूचक में कोई लंबाई की जानकारी शामिल नहीं है, []इसलिए फ़ंक्शन औपचारिक पैरामीटर सूची में आपकी सामग्री को वास्तव में अनदेखा किया जाता है।

इस सिंटैक्स को अनुमति देने का निर्णय 1970 के दशक में किया गया था और तब से बहुत भ्रम हो गया है ...


21
एक गैर-सी प्रोग्रामर के रूप में, मुझे यह उत्तर बहुत सुलभ लगता है। +1
क्षुद्र

21
+1 के लिए "इस वाक्यविन्यास को अनुमति देने का निर्णय 1970 के दशक में किया गया था और तब से बहुत भ्रम हो गया है ..."
NoSenseEtAl

8
यह सच है, लेकिन सिंटैक्स का उपयोग करके केवल उस आकार की एक सरणी को पास करना भी संभव है void foo(int (*somearray)[20])। इस स्थिति में 20 को कॉलर साइटों पर लागू किया जाता है।
v.oddou

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

7
"आपके [] की सामग्री" द्वारा, मैं विशेष रूप से प्रश्न में कोड के बारे में बात कर रहा हूं। यह सिंटैक्स क्विक बिल्कुल भी आवश्यक नहीं था, पॉइंटर सिंटैक्स का उपयोग करके एक ही चीज़ प्राप्त की जा सकती है, अर्थात यदि कोई पॉइंटर पास किया जाता है, तो पॉइंटर घोषणाकर्ता होने के लिए पैरामीटर की आवश्यकता होती है। जैसे पैट के उदाहरण में, void foo(int (*args)[20]);इसके अलावा, कड़ाई से बोलने वाले सी में बहुआयामी सरणियाँ नहीं हैं; लेकिन इसमें ऐसे सरणियाँ हैं जिनके तत्व अन्य सरणियाँ हो सकते हैं। यह कुछ भी नहीं बदलता है।
MM

143

पहले आयाम की लंबाई को नजरअंदाज कर दिया जाता है, लेकिन अतिरिक्त आयामों की लंबाई आवश्यक है कि कंपाइलर को सही ढंग से ऑफसेट की गणना करने की अनुमति दी जाए। निम्न उदाहरण में, fooफ़ंक्शन को दो-आयामी सरणी के लिए एक संकेतक दिया जाता है।

#include <stdio.h>

void foo(int args[10][20])
{
    printf("%zd\n", sizeof(args[0]));
}

int main(int argc, char **argv)
{
    int a[2][20];
    foo(a);
    return 0;
}

पहले आयाम के आकार [10]को अनदेखा किया जाता है; संकलक आपको अंत से अनुक्रमण करने से नहीं रोकेंगे (ध्यान दें कि औपचारिक 10 तत्व चाहते हैं, लेकिन वास्तविक केवल 2 प्रदान करता है)। हालांकि, [20]प्रत्येक पंक्ति के स्ट्राइड को निर्धारित करने के लिए दूसरे आयाम के आकार का उपयोग किया जाता है, और यहां, औपचारिक को वास्तविक से मेल खाना चाहिए। फिर से, कंपाइलर आपको दूसरे आयाम के अंत तक इंडेक्सिंग करने से नहीं रोकेगा।

किसी तत्व को सरणी के आधार से बाइट ऑफसेट args[row][col]द्वारा निर्धारित किया जाता है:

sizeof(int)*(col + 20*row)

ध्यान दें कि यदि col >= 20, तो आप वास्तव में एक बाद की पंक्ति (या पूरे सरणी के अंत से दूर) में अनुक्रमित करेंगे।

sizeof(args[0])रिटर्न 80मेरी मशीन जहां पर sizeof(int) == 4। हालांकि, अगर मैं लेने का प्रयास करता हूं, तो मुझे sizeof(args)निम्नलिखित संकलक चेतावनी मिलती है:

foo.c:5:27: warning: sizeof on array function parameter will return size of 'int (*)[20]' instead of 'int [10][20]' [-Wsizeof-array-argument]
    printf("%zd\n", sizeof(args));
                          ^
foo.c:3:14: note: declared here
void foo(int args[10][20])
             ^
1 warning generated.

यहां, संकलक चेतावनी दे रहा है कि यह केवल सूचक के आकार को देने वाला है जिसमें सरणी के आकार के बजाय सरणी का क्षय हुआ है।


बहुत उपयोगी - इसके साथ संगति भी 1-डी मामले में क्विर्क के कारण के रूप में प्रशंसनीय है।
jwg

1
यह 1-डी केस जैसा ही विचार है। सी और सी ++ में 2-डी सरणी की तरह दिखने वाला वास्तव में 1-डी सरणी है, जिसमें से प्रत्येक तत्व 1-डी सरणी है। इस मामले में हमारे पास 10 तत्वों के साथ एक सरणी है, जिसका प्रत्येक तत्व "20 ints का सरणी" है। जैसा कि मेरी पोस्ट में बताया गया है, जो वास्तव में फ़ंक्शन में जाता है, वह पहले तत्व का सूचक है args। इस मामले में, आर्ग्स का पहला तत्व "20 ints का सरणी" है। संकेत प्रकार जानकारी शामिल हैं; जो पास हो जाता है, वह "20 इंच की एक सरणी के लिए पॉइंटर" है।
एमएम

9
हाँ, यह है कि int (*)[20]प्रकार क्या है; "20 इंच की एक सरणी के लिए पॉइंटर"।
पटना

33

समस्या और इसे C ++ में कैसे दूर किया जाए

समस्या को पैट और मैट द्वारा बड़े पैमाने पर समझाया गया है । संकलक मूल रूप से सरणी के आकार के पहले आयाम को प्रभावी रूप से पारित तर्क के आकार की अनदेखी कर रहा है।

सी ++ में, दूसरी ओर, आप इस सीमा को आसानी से दो तरीकों से दूर कर सकते हैं:

  • संदर्भों का उपयोग करना
  • उपयोग std::array(C ++ 11 से)

संदर्भ

यदि आपका फ़ंक्शन केवल मौजूदा सरणी को पढ़ने या संशोधित करने की कोशिश कर रहा है (इसे कॉपी नहीं कर रहा है) तो आप आसानी से संदर्भों का उपयोग कर सकते हैं।

उदाहरण के लिए, मान लें कि आप एक ऐसा कार्य करना चाहते हैं, जो intहर तत्व के लिए दस s सेटिंग की एक सरणी को रीसेट करता है 0। आप निम्न फ़ंक्शन हस्ताक्षर का उपयोग करके आसानी से कर सकते हैं:

void reset(int (&array)[10]) { ... }

न केवल यह ठीक काम करेगा , बल्कि यह सरणी के आयाम को भी लागू करेगा ।

आप उपरोक्त कोड को सामान्य बनाने के लिए टेम्प्लेट का उपयोग भी कर सकते हैं :

template<class Type, std::size_t N>
void reset(Type (&array)[N]) { ... }

और अंत में आप constशुद्धता का लाभ उठा सकते हैं । आइए एक फ़ंक्शन पर विचार करें जो 10 तत्वों की एक सरणी प्रिंट करता है:

void show(const int (&array)[10]) { ... }

constक्वालिफायर लागू करके हम संभावित संशोधनों को रोक रहे हैं ।


सरणियों के लिए मानक पुस्तकालय वर्ग

यदि आप उपरोक्त वाक्यविन्यास को बदसूरत और अनावश्यक दोनों मानते हैं, जैसा कि मैं करता हूं, हम इसे कैन में फेंक सकते हैं और std::arrayइसके बजाय उपयोग कर सकते हैं (चूंकि C 11 11)।

यहां बताया गया है:

void reset(std::array<int, 10>& array) { ... }
void show(std::array<int, 10> const& array) { ... }

क्या यह अद्भुत नहीं है? यह उल्लेख करने के लिए नहीं कि जेनेरिक कोड ट्रिक जो मैंने आपको पहले सिखाई है, अभी भी काम करती है:

template<class Type, std::size_t N>
void reset(std::array<Type, N>& array) { ... }

template<class Type, std::size_t N>
void show(const std::array<Type, N>& array) { ... }

इतना ही नहीं, लेकिन आप कॉपी प्राप्त करते हैं और मुफ्त के लिए अर्थ स्थानांतरित करते हैं। :)

void copy(std::array<Type, N> array) {
    // a copy of the original passed array 
    // is made and can be dealt with indipendently
    // from the original
}

तो आप किसका इंतज़ार कर रहे हैं? उपयोग करें std::array


2
@kietz, मुझे खेद है कि आपका सुझाया गया संपादन अस्वीकृत हो गया, लेकिन हम स्वचालित रूप से मान लेते हैं कि C ++ 11 का उपयोग किया जा रहा है , जब तक कि अन्यथा निर्दिष्ट न किया जाए।
जूता

यह सच है, लेकिन हम यह भी निर्दिष्ट करने वाले हैं कि यदि कोई समाधान केवल C ++ 11 है, तो आपके द्वारा दिए गए लिंक के आधार पर।
त्रिकली

@trlkly, मैं सहमत हूं। मैंने उसी के अनुसार उत्तर संपादित किया है। इस पर ध्यान दिलाने के लिए धन्यवाद।
जूता

9

यह सी की एक मजेदार विशेषता है जो आपको अपने आप को पैर में प्रभावी ढंग से शूट करने की अनुमति देती है यदि आप इतने इच्छुक हैं।

मुझे लगता है कि इसका कारण यह है कि सी असेंबली भाषा से सिर्फ एक कदम ऊपर है। पीक प्रदर्शन के लिए अनुमति देने के लिए आकार की जाँच और समान सुरक्षा सुविधाओं को हटा दिया गया है, जो कि प्रोग्रामर के बहुत मेहनती होने पर बुरी बात नहीं है।

साथ ही, फ़ंक्शन तर्क के लिए एक आकार असाइन करने से यह फायदा होता है कि जब फ़ंक्शन किसी अन्य प्रोग्रामर द्वारा उपयोग किया जाता है, तो एक मौका है कि वे एक आकार प्रतिबंध को नोटिस करेंगे। बस एक पॉइंटर का उपयोग करने से अगले प्रोग्रामर को वह जानकारी नहीं मिलती है।


3
हाँ। सी को कंपाइलर पर प्रोग्रामर पर भरोसा करने के लिए डिज़ाइन किया गया है। यदि आप किसी सरणी के अंत में इतनी स्पष्ट रूप से अनुक्रमण कर रहे हैं, तो आपको कुछ विशेष और जानबूझकर करना चाहिए।
जॉन

7
मैंने 14 साल पहले सी पर प्रोग्रामिंग में अपने दांत काट दिए। मेरे सभी प्रोफेसर ने कहा, एक वाक्यांश जो मेरे साथ अन्य सभी की तुलना में अधिक अटक गया है, "प्रोग्रामर के लिए सी प्रोग्रामर द्वारा लिखा गया था।" भाषा अत्यंत शक्तिशाली है। (क्लिच के लिए तैयार) जैसा कि चाचा बेन ने हमें सिखाया, "महान शक्ति के साथ, बड़ी जिम्मेदारी आती है।"
एंड्रयू फेलंगा

6

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

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

typedef struct {
  int a[10];
} myarray_t;

myarray_t my_function(myarray_t foo) {

  myarray_t bar;

  ...

  return bar;

}

आपको इस तरह के तत्वों का उपयोग करना होगा: foo.a [1]। अतिरिक्त ".a" अजीब लग सकता है, लेकिन यह चाल सी भाषा में महान कार्यक्षमता जोड़ती है।


7
आप संकलन-समय प्रकार की जाँच के साथ रनटाइम सीमा की जाँच कर रहे हैं।
बेन वोइगट

@ बान वायगट: मैं केवल सीमा जाँच के बारे में बात कर रहा हूँ, जैसा कि मूल प्रश्न है।
user34814

2
@ user34814 संकलन-समय सीमा की जाँच प्रकार की जाँच के दायरे में है। कई उच्च-स्तरीय भाषाएं यह सुविधा प्रदान करती हैं।
लेउशेंको

5

संकलक को यह बताने के लिए कि myArray कम से कम 10 ints की एक सरणी की ओर इशारा करता है:

void bar(int myArray[static 10])

यदि आप myArray का उपयोग करते हैं तो एक अच्छे कंपाइलर को आपको चेतावनी देनी चाहिए [10]। "स्थिर" कीवर्ड के बिना, 10 का मतलब कुछ भी नहीं होगा।


1
यदि आप 11 वें तत्व का उपयोग करते हैं और कम से कम 10 तत्वों को शामिल करते हैं तो संकलक को चेतावनी क्यों देनी चाहिए ?
nwellnhof

संभवतः ऐसा इसलिए है क्योंकि कंपाइलर केवल यह लागू कर सकता है कि आपके पास कम से कम 10 तत्व हैं। यदि आप 11 वें तत्व तक पहुँचने की कोशिश करते हैं, तो यह सुनिश्चित नहीं हो सकता है कि यह मौजूद है (भले ही यह हो सकता है)।
डायलन वॉटसन

2
मुझे नहीं लगता कि यह मानक का सही पठन है। [static]यदि आप कॉल bar करते हैं तो कंपाइलर को चेतावनी देता है int[5]। यह तय नहीं करता है कि आप किस चीज का उपयोग कर सकते हैं bar । ओनस पूरी तरह से कॉलर की तरफ होता है।
टैब

3
error: expected primary-expression before 'static'इस वाक्यविन्यास को कभी नहीं देखा। यह मानक C या C ++ होने की संभावना नहीं है।
v.oddou

3
@ v.oddou, यह C99 में निर्दिष्ट है, 6.7.5.2 और 6.7.5.3 में।
शमूएल एडविन वार्ड

5

यह C का एक जाना-माना "फीचर" है, जो C ++ से अधिक उत्तीर्ण है क्योंकि C ++ को C कोड को सही ढंग से संकलित करना है।

समस्या कई पहलुओं से उत्पन्न होती है:

  1. एक सरणी नाम पूरी तरह से एक सूचक के बराबर माना जाता है।
  2. सी को तेजी से माना जाता है, मूल रूप से डेवलपर एक प्रकार का "उच्च-स्तरीय असेंबलर" है (विशेष रूप से पहला "पोर्टेबल ऑपरेटिंग सिस्टम": यूनिक्स लिखने के लिए बनाया गया है), इसलिए इसे "छिपा हुआ" कोड डालने के लिए नहीं माना जाता है; रनटाइम रेंज की जाँच इस प्रकार "निषिद्ध" है।
  3. स्थिर कोड या डायनेमिक एक्सेस (या तो स्टैक या आबंटित) तक पहुंचने के लिए उत्पन्न मशीन कोड वास्तव में अलग है।
  4. चूंकि फ़ंक्शन को पता नहीं चल सकता है कि सरणी का "प्रकार" तर्क के रूप में पारित हो गया है, सब कुछ एक सूचक माना जाता है और इस तरह के रूप में माना जाता है।

आप कह सकते हैं कि सरणियां वास्तव में सी में समर्थित नहीं हैं (यह वास्तव में सच नहीं है, जैसा कि मैं पहले कह रहा था, लेकिन यह एक अच्छा अनुमान है); एक सरणी को वास्तव में डेटा के ब्लॉक के लिए एक पॉइंटर के रूप में माना जाता है और पॉइंटर अंकगणित का उपयोग करके एक्सेस किया जाता है। चूंकि C में RTTI का कोई भी रूप नहीं है इसलिए आपको फ़ंक्शन प्रोटोटाइप (सूचक अंकगणित का समर्थन करने के लिए) में सरणी तत्व का आकार घोषित करना होगा। यह बहुआयामी सरणियों के लिए और भी अधिक "सही" है।

वैसे भी उपरोक्त सभी अब वास्तव में सच नहीं है: पी

अधिकांश आधुनिक C / C ++ कंपाइलर बाउंड चेकिंग का समर्थन करते हैं , लेकिन मानकों को इसे डिफ़ॉल्ट रूप से (बैकवर्ड संगतता के लिए) बंद करने की आवश्यकता होती है। उदाहरण के लिए, हाल ही में जीसीसी के संस्करण, "-O3 -वेल-पाठ" के साथ संकलन-समय सीमा की जाँच करते हैं और "-फाइबाउंड्स-चेकिंग" के साथ पूर्ण रन-टाइम सीमा की जाँच करते हैं।


हो सकता है कि सी ++ गया था 20 साल पहले सी कोड संकलन करने की अपेक्षा की, लेकिन यह निश्चित है नहीं, और एक लंबे समय (सी ++ 98? C99 कम से कम, जो किसी भी नए सी ++ मानक द्वारा नहीं किया गया "निर्धारित" है) के लिए नहीं है।
हाईड

@ मुझे लगता है कि थोड़ा बहुत कठोर है। स्ट्रॉस्ट्रुप को उद्धृत करने के लिए "मामूली अपवादों के साथ, C, C ++ का सबसेट है।" (सी ++ पीएल 4 डी एड।, सेक। 1.2.1)। जबकि C ++ और C दोनों आगे विकसित होते हैं, और नवीनतम C संस्करण से सुविधाएँ मौजूद हैं जो नवीनतम C ++ संस्करण में नहीं हैं, कुल मिलाकर मुझे लगता है कि स्ट्रॉस्ट्रुप उद्धरण अभी भी मान्य है।
mvw

इस मिलीनियम में लिखा गया @mvw मोस्ट सी कोड, जिसे असंगत सुविधाओं से बचाकर जानबूझकर C ++ संगत नहीं रखा गया है, स्ट्रक्चर्स को इनिशियलाइज़ करने के लिए C99 नामित इनिशियलाइज़र्स सिंटैक्स ( struct MyStruct s = { .field1 = 1, .field2 = 2 };) का उपयोग करेगा , क्योंकि यह किसी स्ट्रक्चर को इनिशियलाइज़ करने का सिर्फ इतना क्लियर तरीका है। नतीजतन, अधिकांश सी कोड को मानक सी ++ कंपाइलर द्वारा खारिज कर दिया जाएगा, क्योंकि अधिकांश सी कोड संरचना को इनिशियलाइज़ करेंगे।
हाइड

@mvw यह शायद कहा जा सकता है, कि C ++ को C के साथ संगत माना जाता है, ताकि कोड लिखना संभव हो, जो C और C ++ कंपाइलर दोनों के साथ संकलित करेगा, यदि कुछ समझौते किए जाते हैं। लेकिन इसके लिए C और C ++ दोनों के सबसेट का उपयोग करना आवश्यक है, न कि केवल C ++ का सबसेट।
हाइड

@ आपको आश्चर्य होगा कि C कोड C ++ का कितना भाग है। कुछ साल पहले पूरे लिनक्स कर्नेल C ++ संकलन योग्य थे (मुझे नहीं पता कि क्या यह अभी भी सच है)। मैं नियमित रूप से C ++ कंपाइलर में C कोड को एक बेहतर चेतावनी जाँच प्राप्त करने के लिए संकलित करता हूं, केवल "उत्पादन" को C मोड में संकलित किया जाता है ताकि सबसे अधिक ऑप्टिमाइज़ेशन निचोड़ा जा सके।
ZioByte

3

सी ही प्रकार का एक पैरामीटर को बदलने नहीं होंगे int[5]में *int; घोषणा को देखते हुए typedef int intArray5[5];, यह प्रकार का एक पैरामीटर बदल सकते हैं intArray5करने के लिए *intके रूप में अच्छी तरह से। कुछ परिस्थितियाँ ऐसी होती हैं जहाँ यह व्यवहार, हालांकि विषम होता है, उपयोगी होता है (विशेष रूप से va_listपरिभाषित चीजों की तरह stdargs.h, जिसमें कुछ कार्यान्वयन एक सरणी के रूप में परिभाषित होते हैं)। यह एक पैरामीटर के रूप में परिभाषित करने के लिए एक प्रकार के रूप में परिभाषित करने के लिए अतार्किक होगा int[5](आयाम की अनदेखी) लेकिन int[5]सीधे निर्दिष्ट करने की अनुमति नहीं है ।

मुझे लगता है कि बेहोशी के लिए सरणी प्रकार के मापदंडों के सी की हैंडलिंग, लेकिन यह एक तदर्थ भाषा लेने के प्रयासों का एक परिणाम है, जिनमें से बड़े हिस्से विशेष रूप से अच्छी तरह से परिभाषित या विचार-आउट नहीं थे, और व्यवहार के साथ आने की कोशिश करते हैं ऐसे विनिर्देश जो मौजूदा कार्यक्रमों के लिए मौजूदा कार्यान्वयनों के अनुरूप हैं। उस प्रकाश में देखे जाने पर C के कई प्रश्न समझ में आते हैं, खासकर अगर कोई मानता है कि जब उनमें से कई का आविष्कार किया गया था, तो आज हम जानते हैं कि भाषा के बड़े हिस्से अभी तक मौजूद नहीं थे। जो मैं समझता हूं, सी से पूर्ववर्ती में, बीसीपीएल कहा जाता है, संकलक वास्तव में चर प्रकारों का ट्रैक बहुत अच्छी तरह से नहीं रखते थे। एक घोषणा के int arr[5];बराबर था int anonymousAllocation[5],*arr = anonymousAllocation;; एक बार आवंटन अलग सेट कर दिया गया था। संकलक न तो जानता था और न ही परवाह थीarrएक सूचक या एक सरणी था। जब एक्सेस किया जाता है तोarr[x] या*arr, यह एक सूचक के रूप में माना जाएगा कि यह कैसे घोषित किया गया था।


1

एक बात जिसका उत्तर अभी तक नहीं दिया गया है वह है वास्तविक प्रश्न।

पहले से दिए गए उत्तर बताते हैं कि सरणियों को किसी फ़ंक्शन में C या C ++ के मान से पारित नहीं किया जा सकता है। वे यह भी समझाते हैं कि जैसा घोषित किया गया int[]है वैसा ही एक पैरामीटर माना जाता है जैसे कि यह टाइप किया गया हो int *, और यह कि इस प्रकार का एक वेरिएबल int[]ऐसे फंक्शन में पास हो सकता है।

लेकिन वे यह नहीं समझाते हैं कि इसे स्पष्ट रूप से एक सरणी लंबाई प्रदान करने के लिए त्रुटि क्यों नहीं की गई है।

void f(int *); // makes perfect sense
void f(int []); // sort of makes sense
void f(int [10]); // makes no sense

इनमें से अंतिम त्रुटि क्यों नहीं है?

इसका एक कारण यह है कि यह टाइप्डिफ के साथ समस्याओं का कारण बनता है।

typedef int myarray[10];
void f(myarray array);

यदि यह फ़ंक्शन मापदंडों में सरणी लंबाई निर्दिष्ट करने में त्रुटि थी, तो आप फ़ंक्शन पैरामीटर में myarrayनाम का उपयोग करने में सक्षम नहीं होंगे । और चूंकि कुछ कार्यान्वयन मानक पुस्तकालय प्रकारों के लिए सरणी प्रकारों का उपयोग करते हैं जैसे कि va_list, और सभी कार्यान्वयनों को jmp_bufएक सरणी प्रकार बनाने के लिए आवश्यक है , यह बहुत समस्याग्रस्त होगा यदि उन नामों का उपयोग करके फ़ंक्शन मापदंडों की घोषणा करने का कोई मानक तरीका नहीं था: उस क्षमता के बिना, वहाँ हो सकता है। इस तरह के कार्यों का एक पोर्टेबल कार्यान्वयन नहीं है vprintf


0

यह संकलक को यह जांचने में सक्षम बनाता है कि पास किए गए सरणी का आकार वही है जो अपेक्षित था। यदि यह मामला नहीं है तो संकलक एक मुद्दे को चेतावनी दे सकता है।

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