क्या 'फॉर' के लिए 'लूप के अंदर' के लिए लूप एक समान काउंटर वेरिएबल नाम का उपयोग कर सकता है?


107

क्या मैं एक forलूप के अंदर एक ही काउंटर वेरिएबल का उपयोग कर सकता हूं for?

या चर एक दूसरे को प्रभावित करेंगे? निम्नलिखित कोड को दूसरे लूप के लिए एक अलग चर का उपयोग करना चाहिए, जैसे कि j, या iठीक है?

for(int i = 0; i < 10; i++)
{
  for(int i = 0; i < 10; i++)
  {
  }
}

72
यह भ्रामक है - यह मुझे एक कोड समीक्षा में नहीं मिलेगा। लेकिन यह वैध है। दोनों अलग-अलग चर कहलाते हैं i, अलग-अलग स्कोप के साथ। -Wshadowऐसी समस्याओं को स्वचालित रूप से प्राप्त करने के लिए GCC के साथ प्रयोग करें ।
जोनाथन लेफलर

15
मुझे आश्चर्य है कि -Wshadowइसमें शामिल नहीं है -Wall
लेफ्टरनबाउट

5
@leftaroundabout -Wshadowवैश्विक चर के छायांकन के बारे में भी चेतावनी देता है, जिससे बड़ी परियोजनाओं में आसानी से गुस्सा आ सकता है।
घन

9
@leftaroundabout और भी आश्चर्यजनक रूप से, यहां तक -Wextraकि शामिल नहीं है -Wshadow। मुझे लगता है कि यह कुछ परियोजनाओं में काफी आम है, या कुछ gcc डेवलपर को कोडिंग शैली के रूप में छायांकन करना पसंद है, इस तरह से छोड़ दिया जाना।
हायड

5
@leftaroundabout ने क्यूबिक के बारे में जो कहा है, उसकी गूंज -Wshadowएक भयावह झूठी सकारात्मक दर है, जिसने इसे पूरी तरह से बेकार कर दिया है। स्कोप एक कारण के लिए मौजूद है, और शैडोइंग एक प्राथमिकता है समस्याग्रस्त नहीं है। अब -Wshadow-local(नोट: नहीं -Wshadow=local ) बहुत अलग है। लेकिन दुर्भाग्य से जीसीसी ने अब तक इसे ट्रंक में शामिल करने से इनकार कर दिया है (हालांकि जीसीसी के कांटे प्रतीत होते हैं जो इसे शामिल करते हैं)।
कोनराड रूडोल्फ

जवाबों:


140

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

यह आमतौर पर खराब शैली है, भ्रम की स्थिति है, और इससे बचा जाना चाहिए।

वस्तुएं केवल तभी भिन्न होती हैं, जब आंतरिक को अलग से परिभाषित किया गया हो, जैसा कि int iआपने दिखाया है। यदि किसी नई वस्तु को परिभाषित किए बिना एक ही नाम का उपयोग किया जाता है, तो लूप एक ही वस्तु का उपयोग करेंगे और एक दूसरे के साथ हस्तक्षेप करेंगे।


3
(i) और for (j) नेस्टेड, और i ++ के अंदर का उपयोग करने से बाहरी-लूप वेरिएबल में वृद्धि होगी। हालाँकि आप जो कहते हैं वह सही है यदि आप दोनों छोरों में समान पहचानकर्ता का उपयोग करते हैं, क्योंकि वे भिन्न रूप से भिन्न चर हैं।
KYL3R

3
@BloodGain: "ऑब्जेक्ट" C मानक में प्रयुक्त एक तकनीकी शब्द है। मैंने यहां जानबूझकर इसका इस्तेमाल किया।
एरिक पोस्टपिसिल

1
@EricPostpischil: आह, मैं देख रहा हूं, हां। मुझे मानक में उस परिभाषा के बारे में पता नहीं था, और डर था कि यह नए प्रोग्रामर को भ्रामक होगा (क्योंकि यह बहुत स्पष्ट रूप से एक शुरुआती सवाल है), क्योंकि सी में "ऑब्जेक्ट" नहीं है इस अर्थ में कि हम आम तौर पर शब्द का उपयोग करते हैं। मैं इसे C11 मानक में देखता हूं, और अब मैं उत्सुक हूं कि क्या इसे C11 से पहले परिभाषित किया गया था।
ब्लडगैन

1
ये था। 3.15 के बजाय C99 मानक में यह 3.14 है। इसलिए मेरी ओर से कोई बहाना नहीं। वह मुझे आपसे प्रश्न करना सिखाएगा <: - |
ब्लडगैन

1
आम तौर पर: किसी भी नेस्टेड दायरे में एक चर नाम का फिर से उपयोग करने से आपको रोकने के लिए कुछ भी नहीं है। सिवाय, भ्रामक कोड लिखने के लिए भगवान की सजा का डर।
इसहाक रैबिनोविच

56

सबसे पहले, यह पूरी तरह से कानूनी है: कोड नेस्टेड लूप के शरीर को 10 × 10 = 100 बार दोहराएगा और चलाएगा। iनेस्टेड लूप के अंदर लूप काउंटर बाहरी लूप के काउंटर को छिपाएगा , इसलिए दो काउंटर एक दूसरे से स्वतंत्र रूप से बढ़े होंगे।

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

नोट: भले ही दोनों छोरों के काउंटर चर एक ही पहचानकर्ता हैं i, लेकिन वे दो स्वतंत्र चर रहे हैं, अर्थात आप दोनों छोरों में एक ही चर का उपयोग नहीं कर रहे हैं । दोनों छोरों में एक ही चर का उपयोग करना भी संभव है, लेकिन कोड को पढ़ना मुश्किल होगा। यहाँ एक उदाहरण है:

for (int i = 1 ; i < 100 ; i++) {
    for ( ; i % 10 != 0 ; i++) {
        printf("%02d ", i);
    }
    printf("%d\n", i);
}

अब दोनों लूप एक ही चर का उपयोग करते हैं। हालांकि, यह पता लगाने में कुछ समय लगता है कि यह कोड इसे ( डेमो ) संकलित किए बिना क्या करता है ;


4
चूँकि यह प्रश्न "एक ही काउंटर चर का उपयोग करते हुए" के रूप में दर्शाया गया है, इसलिए मैं यह भी बताना चाहूंगा कि छायांकन केवल तब होता है जब पुनर्वितरण होता है। intलूप के लिए आंतरिक पर ऑमिटिंग , यानी वास्तव में एक ही काउंटर वेरिएबल का उपयोग करके, बाहरी लूप केवल एक बार चलाने का कारण होगा, क्योंकि आंतरिक लूप निकल जाएगा i == 10। यह तुच्छ है, लेकिन सोचा गया कि यह स्पष्टीकरण प्रदान करता है कि प्रश्न कैसे कहा गया था
ईस्टन बोर्नमेयर

@EastonBornemeier आप सही हैं, मुझे लगा कि मुझे जवाब के शरीर में "उसी चर" के मुद्दे को संबोधित करना चाहिए। धन्यवाद!
dasblinkenlight

@EricPostpischil "वैरिएबल शैडोइंग" एक आधिकारिक शब्द है, जो विकिपीडिया पर अपने स्वयं के पृष्ठ के साथ पूरा होता है । मैंने उत्तर को मानक के शब्दों के अनुरूप होने के लिए अद्यतन किया है, हालाँकि। धन्यवाद!
dasblinkenlight

2
@dasblinkenlight: वास्तव में, मुझे दिशा के बारे में मस्तिष्क की ऐंठन थी, और आंतरिक नाम बाहरी नाम को छाया देता है। मेरी पिछली टिप्पणी उस संबंध में गलत थी। मैं क्षमाप्रार्थी हूं। (हालाँकि, यह एक अंग्रेजी अर्थ में है, आधिकारिक अर्थ में नहीं - विकिपीडिया सी या प्रोग्रामिंग के लिए सामान्य रूप से आधिकारिक प्रकाशन नहीं है, और मुझे इस शब्द को परिभाषित करने वाले किसी भी कार्यालय या आधिकारिक निकाय के बारे में पता नहीं है।) सी मानक का उपयोग करता है। "छिपाना", इसलिए यह बेहतर है।
एरिक पोस्टपिसिल

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

26

आप ऐसा कर सकते हैं। लेकिन आपको iएस के दायरे के बारे में पता होना चाहिए । अगर हम बाहरी फोन iके साथ i_1और आंतरिक iके साथ i_2, के दायरे iरों के रूप में इस प्रकार है:

for(int i = 0; i < 10; i++)
{
     // i means i_1
     for(int i = 0; i < 10; i++)
     {
        // i means i_2
     }
     // i means i_1
}

आपको ध्यान देना चाहिए कि वे एक दूसरे को प्रभावित नहीं करते हैं, और बस उनकी परिभाषा का दायरा अलग है।


17

यह पूरी तरह से संभव है लेकिन ध्यान रखें, आप पहले घोषित i को संबोधित करने में सक्षम नहीं होंगे

for(int i = 0; i < 10; i++)//I MEAN THE ONE HERE
{

  for(int i = 0; i < 10; i++)
    {

    }
}

दूसरे लूप के भीतर दूसरे लूप में

for(int i = 0; i < 10; i++)
{

  for(int i = 0; i < 10; i++)//the new i
    {
        // i cant see the i thats before this new i here
    }
}

यदि आपको पहले i का मूल्य समायोजित करने या प्राप्त करने की आवश्यकता है, तो दूसरे लूप में j का उपयोग करें

for(int i = 0; i < 10; i++)
{

  for(int j = 0; j < 10; j++)
    {

    }
}

और अगर आपका रचनात्मक पर्याप्त आप दोनों को एक ही लूप में कर सकते हैं

for(int i ,j= 0; i < 10; (j>9) ? (i++,j=0) : 0 ,j++)
{
    printf("%d %d\n",i,j);
}

6
यदि मैंने कोड समीक्षा के दौरान नेस्टेड लूप में छायांकित आई चर को पकड़ा है, तो मैं इसे कोचिंग अवसर के रूप में देखूंगा। अगर मैंने किसी को आपके पिछले उदाहरण (जैसे कि एक लूप नहीं है) की तरह आंतरिक लूप को पकड़ा, मैं उन्हें एक खिड़की से बाहर फेंक सकता हूं।
ब्लडगैन

यह एक लूप है, इसमें लूप के लिए केवल एक है , अगर यह 2 होता तो कीवर्ड्स के लिए दो या कीवर्ड्स के लिए दो या
Dodo

3
इसीलिए मैंने कहा कि आपने लूप को बाधित कर दिया है। आप अभी भी लूपिंग कर रहे हैं, आपने इसे कम स्पष्ट वाक्य रचना के साथ छिपाया है। और यह इसके लिए हर तरह से बदतर है।
ब्लडगैन

12

हां आप आंतरिक forलूप के लिए बाहरी forलूप के समान काउंटर चर नाम का उपयोग कर सकते हैं ।

से पाश के लिए :

for ( init_clause ; cond_expression ; iteration_expression ) loop_statement
अभिव्यक्ति के रूप में इस्तेमाल बयान loop_statement अपनी ही स्थापित करता ब्लॉक गुंजाइश, दायरे से अलग की init_clause

for (int i = 0; ; ) {
    long i = 1;   // valid C, invalid C++
    // ...
}  

के दायरे loop_statement है नेस्ट के दायरे के भीतर init_clause

C मानकों से # 6.8.5p5 कथन कथन [जोर मेरा]

एक पुनरावृति कथन एक ऐसा खंड है जिसका दायरा इसके घेरने वाले खंड के सख्त उपसमुच्चय है। लूप बॉडी भी एक ब्लॉक है जिसका दायरा पुनरावृति कथन के दायरे का एक सख्त उपसमूह है

C मानकों से # 6.2.1p4 पहचानकर्ताओं के स्कोप [जोर मेरा]

.... भीतर के दायरे में, पहचानकर्ता आंतरिक दायरे में घोषित इकाई को नामित करता है; इकाई बाहरी दायरे में घोषित छिपा हुआ है (और नहीं देख सकते) भीतरी दायरे के भीतर।


10

एक कोड / संकलक के नजरिए से यह पूरी तरह से वैध और कानूनी चीज होगी। int iभीतरी में घोषित for(int i = 0; i < 10; i++)पाश, एक नया और छोटे दायरे में है ताकि घोषणा छाया की घोषणा int iबाहरी पाश में (या दूसरे शब्दों के साथ,: चर करने के लिए आंतरिक दायरे में स्थित सभी पहुंच iके चलते int iआंतरिक दायरे में घोषणा की, int iबाहरी दायरे में छोड़े गए )।

एक कोड गुणवत्ता के दृष्टिकोण से, यह पूरी तरह से भयानक है। यह पढ़ना कठिन है, समझना कठिन है और गलत समझना आसान है। यह मत करो।


8

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

int a = 5;
// scope of a that has value 5
int func(){
    int a = 10;
   // scope of a that has value 10
}
// scope of a that has value 5

इसी तरह लूप्स के मामले में, इनर लूप के अंदर घोषित होने वाले वेरिएबल के अलग-अलग स्कोप होते हैं और वेरिएबल घोषित किए गए बाहरी लूप के अलग-अलग स्कोप होते हैं।

for(int i = 0; i < 10; i++){
    // In first iteration, value of i is 0

    for(int i = 1; i < 10; i++){
        // In first iteration, value of i is 1
    }
    // In first iteration, value of i is 0
}

बेहतर तरीका यह है कि आंतरिक और बाहरी छोरों के लिए विभिन्न चर का उपयोग करें।

for(int i = 0; i < 10; i++){

    for(int j = 1; j < 10; j++){

    }

}

8

हां निश्चित रूप से आप एक ही नाम चर का उपयोग कर सकते हैं।

C प्रोग्रामिंग वैरिएबल को तीन स्थानों पर घोषित किया जा सकता है:
स्थानीय वैरिएबल: -एक फ़ंक्शन या ब्लॉक के अंदर।
वैश्विक चर: -सभी कार्यों के।
औपचारिक पैरामीटर: फ़ंक्शन मापदंडों में।

लेकिन आपके मामले में i scopeबातों से नीचे दिमाग लगाना होगा

for(int i = 0; i < 10; i++)
{
     // i means 1st for loop variable
     for(int i = 0; i < 10; i++)
     {
        // but here i means 2nd for loop  variable
     }
     //interesting thing here i means 1st for loop variable
}

नोट: आंतरिक और बाहरी छोरों के लिए विभिन्न चर का उपयोग करना सबसे अच्छा अभ्यास होगा


6

हां - और इससे भी अधिक दिलचस्प बात यह है कि आप हर बार जब आप ब्रेसिज़ खोलते हैं तो एक चर नाम का पुन: उपयोग कर सकते हैं। डायग्नोस्टिक कोड डालने पर यह अक्सर काम आता है। एक खुला ब्रेस टाइप करें '{' जिसके बाद डिक्लेरेशन और वेरिएबल्स का उपयोग होता है, फिर ब्रेस बंद करें और वैरिएबल चले जाएं। यह गारंटी देता है कि ब्रेसिज़ के बाहर घोषित किए गए किसी भी चर, वर्गों और तरीकों का लाभ बरकरार रखते हुए आप मुख्य शरीर में किसी भी चीज़ में हस्तक्षेप नहीं करेंगे।


3

स्कोप नियम: एक स्टेटमेंट के लिए घोषित किया गया वैरिएबल केवल उस स्टेटमेंट और लूप के बॉडी में इस्तेमाल किया जा सकता है।

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

int main(void) {

    int i = 2; //defined with file global scope outside of a function and will remain 2
    if(1)
    {       //new scope, variables created here with same name are different
        int i = 5;//will remain == 5
        for(int i = 0; i < 10; i++)
        {   //new scope for "i"

            printf("i value in first loop: %d \n", i); // Will print 0 in first iteration
            for(int i = 8; i < 15; i++) 
            {   //new scope again for "i", variable with same name is not the same
                printf("i value in nested loop: %d \n", i); // Will print 8 in first iteration
            }
        }

    }

    return 0;
}

लेकिन उसी चर नाम का उपयोग करने की अनुशंसा नहीं की जाती है क्योंकि यह समझना मुश्किल है और यह बाद में गैर-अनुरक्षण कोड बन जाता है।


1

महत्वपूर्ण हिस्सा आंतरिक लूप पैरामीटर है int i। क्योंकि iइस तरह से नए सिरे से परिभाषित किया गया है, दो चर एक दूसरे को प्रभावित नहीं करते हैं; उनके स्कोप अलग हैं। इसे दिखाने के लिए यहां दो उदाहरण दिए गए हैं:

for(int i = 0; i < 10; i++) // This code will print "Test" 100 times
{
 for(int i = 0; i < 10; i++)
 {
  puts("Test");
 }
}

ध्यान दें कि ऊपर दिए गए कोड int iमें आंतरिक लूप पैरामीटर और केवल नीचे का कोड शामिल है i

for(int i = 0; i < 10; i++) // This code will print "Test" 10 times
{
 for(i = 0; i < 10; i++)
 {
  puts("Test");
 }
}

0

ठीक है, आप अपनी स्क्रिप्ट के बिना समस्या होने पर ऐसा कर सकते हैं, लेकिन आपको उस संरचना से बचना चाहिए। यह आमतौर पर भ्रम की ओर जाता है

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