मैं 'लूप' के लिए C ++ 'में दो इंक्रीमेंट स्टेटमेंट कैसे डालूं?


93

मैं एक के forबजाय एक लूप स्थिति में दो चर बढ़ाना चाहूंगा ।

तो कुछ इस तरह:

for (int i = 0; i != 5; ++i and ++j) 
    do_something(i, j);

इसके लिए वाक्य रचना क्या है?

जवाबों:


154

कॉमन ऑपरेटर का उपयोग करने के लिए एक सामान्य मुहावरा है जो दोनों ऑपरेंड का मूल्यांकन करता है, और दूसरा ऑपरेंड लौटाता है। इस प्रकार:

for(int i = 0; i != 5; ++i,++j) 
    do_something(i,j);

लेकिन क्या यह वास्तव में एक अल्पविराम ऑपरेटर है?

अब लिखा है कि, एक टिप्पणीकार ने सुझाव दिया कि यह वास्तव में कथन के लिए कुछ विशेष वाक्यगत शर्करा है, और बिल्कुल भी अल्पविराम ऑपरेटर नहीं है। मैंने जाँच की कि निम्नानुसार जीसीसी में:

int i=0;
int a=5;
int x=0;

for(i; i<5; x=i++,a++){
    printf("i=%d a=%d x=%d\n",i,a,x);
}

मैं एक्स के मूल मूल्य को लेने के लिए x की उम्मीद कर रहा था, इसलिए इसे x के लिए 5,6,7 .. प्रदर्शित करना चाहिए था। मुझे जो मिला वह यही था

i=0 a=5 x=0
i=1 a=6 x=0
i=2 a=7 x=1
i=3 a=8 x=2
i=4 a=9 x=3

हालांकि, अगर मैंने पार्सर को वास्तव में अल्पविराम ऑपरेटर को देखने के लिए मजबूर करने के लिए अभिव्यक्ति को ब्रैकेट किया है, तो मुझे यह मिलता है

int main(){
    int i=0;
    int a=5;
    int x=0;

    for(i=0; i<5; x=(i++,a++)){
        printf("i=%d a=%d x=%d\n",i,a,x);
    }
}

i=0 a=5 x=0
i=1 a=6 x=5
i=2 a=7 x=6
i=3 a=8 x=7
i=4 a=9 x=8

प्रारंभ में मैंने सोचा था कि यह दिखाया गया था कि यह बिल्कुल भी अल्पविराम ऑपरेटर के रूप में व्यवहार नहीं कर रहा है, लेकिन जैसा कि यह पता चला है, यह केवल एक पूर्ववर्ती समस्या है - अल्पविराम ऑपरेटर की सबसे कम संभव पूर्ववर्तीता है , इसलिए अभिव्यक्ति x = i ++, ++ प्रभावी रूप से है। (x = i ++), a ++ के रूप में पार्स किया गया

सभी टिप्पणियों के लिए धन्यवाद, यह एक दिलचस्प सीखने का अनुभव था, और मैं कई वर्षों से सी का उपयोग कर रहा हूं!


1
मैं कई बार पढ़ा है कि पाश के लिए एक के पहले या तीसरे भाग में अल्पविराम है नहीं अल्पविराम ऑपरेटर, लेकिन सिर्फ एक अल्पविराम विभाजक। (हालांकि, मैं इसके लिए एक आधिकारिक स्रोत खोजने में विफल रहा, क्योंकि मैं सी ++ भाषा मानक को पार्स करने में विशेष रूप से बुरा हूं।)
डैनियल डारानास

मैंने पहले सोचा था कि आप गलत थे, लेकिन मैंने कुछ परीक्षण कोड लिखे और आप सही हैं - यह अल्पविराम ऑपरेटर की तरह व्यवहार नहीं करता है। मेरे उत्तर में संशोधन करेगा!
पॉल डिक्सन

19
यह है उस संदर्भ में एक अल्पविराम ऑपरेटर। कारण यह नहीं है कि आप क्या उम्मीद कर रहे हैं कि कमांड ऑपरेटर के पास असाइनमेंट ऑपरेटर की तुलना में कम पूर्वता है, इसलिए पैरेन्थेस के बिना यह (x = i ++), j ++ के रूप में पार्स करता है।
कैफे

6
यह एक अल्पविराम ऑपरेटर है। असाइनमेंट कॉमा ऑपरेटर की तुलना में अधिक मजबूती से जोड़ता है, इसलिए x = i ++, a ++ पार्स किया गया है (x = i ++), a ++ और not x = (i ++, a ++)। कुछ पुस्तकालयों द्वारा उस विशेषता का दुरुपयोग किया जाता है ताकि v = 1,2,3; सहज बातें करता है, लेकिन केवल इसलिए कि v = 1 एक प्रॉक्सी ऑब्जेक्ट देता है जिसके लिए ओवरलोड कॉमा ऑपरेटर एक परिशिष्ट करता है।
एपीग्रामग्राम

3
ठीक। Open-std.org/jtc1/sc22/wg21/docs/papersGo/n2857.pdf खंड 6.5.3 से अंतिम भाग एक "अभिव्यक्ति" है। (हालांकि 1.6 # 2 एक "अभिव्यक्ति-सूची" को "अल्पविराम द्वारा अलग किए गए अभिव्यक्तियों की सूची" के रूप में परिभाषित करता है, यह निर्माण 6.5.3 में प्रकट नहीं होता है।) इसका मतलब यह है कि जब हम "++ i, ++ j" लिखते हैं तो इसे अपने आप में एक अभिव्यक्ति होना चाहिए , और इस प्रकार "," कॉमा ऑपरेटर (5.18) होना चाहिए । (यह "इनिशियलाइज़र की सूची" या "कार्यों के लिए तर्कों की सूची" नहीं है, जो उदाहरण हैं जहां "अल्पविराम को एक विशेष अर्थ दिया जाता है", जैसा कि 5.18 # 2 कहता है।) मुझे यह थोड़ा भ्रमित करने वाला लगता है।
डैनियल डारनास

55

इसे इस्तेमाल करे

for(int i = 0; i != 5; ++i, ++j)
    do_something(i,j);

17
+1 आप पहले भाग में j भी घोषित कर सकते हैं। for (int i = 0, j = 0; i! = 5; ++ i, ++ j) {...}
डैनियल डारानास

1
+1 एक साइड-नोट के रूप में, यह वही सिंटैक्स C # में काम करता है (मैं लूप इन्क्रिमेंट 2 काउंटर्स के लिए "C # के लिए Google खोज से यहां आया था" इसलिए सोचा कि मैं इसका उल्लेख करूंगा)।
कोडिंगविथस्पीक

@CodingWithSpike: ठीक है, में सी # अल्पविराम है विशेष, है ना वास्तव में कानूनी एक अल्पविराम ऑपरेटर अभिव्यक्ति प्रकट करने के लिए के लिए है। उदाहरण है कि C ++ में अल्पविराम ऑपरेटर का कानूनी उपयोग, लेकिन C # द्वारा अस्वीकार कर दिया गया:for( ; ; ((++i), (++j)) )
बेन Voigt

@BenVoigt का अल्पविराम से कोई लेना देना नहीं है। यह कानूनी C # या तो नहीं है: for(int i = 0; i != 5; (++i)) {अतिरिक्त कोष्ठक यह सोचकर संकलक को चकमा देता है कि यह "वेतन वृद्धि" ऑपरेशन नहीं है।
कोडिंगविथस्पीक

@ कोडिंगविथस्पीक: यह सच है, लेकिन कोष्ठक यह भी बदलता है कि सी # कॉमा को कैसे देखता है और कार्रवाई के लिए विशेष अर्थ को रोकता है।
बेन वोइग्ट

6

इसे करने की कोशिश न करें!

से http://www.research.att.com/~bs/JSF-AV-rules.pdf :

AV नियम 199
लूप के लिए वृद्धि की अभिव्यक्ति लूप के लिए एक लूप पैरामीटर को अगले मान में बदलने के अलावा कोई कार्रवाई नहीं करेगी।

तर्क: पठनीयता।


4
यह सच है, लेकिन निष्पक्ष होने के लिए मुझे पूरा यकीन है कि नियमों का मानक एक लड़ाकू जेट में एम्बेडेड सॉफ़्टवेयर के लिए लिखा गया था, न कि बगीचे की विविधता सी (++) कार्यक्रम। यह कहा जा रहा है, यह शायद एक अच्छी पठनीयता की आदत है, और कौन जानता है, शायद आप F-35 सॉफ्टवेयर डिजाइन कर रहे हैं, और यह टूटने के लिए एक कम आदत होगी।
गलाइस


2

मैं खुद को यह याद दिलाने के लिए आया था कि एक फॉरेस्ट लूप के इंक्रीमेंट क्लॉज में दूसरे इंडेक्स को कैसे कोड किया जाए, जो मुझे पता था कि इसे मुख्य रूप से एक नमूने में देखने से किया जा सकता है जिसे मैंने दूसरे प्रोजेक्ट में शामिल किया था, जिसे C ++ में लिखा गया था।

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

अलौकिक के लिए, निम्नलिखित मेरी टिप्पणियों का सारांश है। मैंने आज जो कुछ भी देखा, वह स्थानीय लोगों की खिड़की में चर को ध्यान से देखते हुए, मेरी उम्मीद की पुष्टि की कि एक C # कथन के लिए कथन C या C ++ के समान व्यवहार करता है।

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

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


1

मैं स्क्वेलार्ट से सहमत हूं। दो चर बढ़ाना बग प्रवण है, खासकर यदि आप केवल उनमें से एक के लिए परीक्षण करते हैं।

यह ऐसा करने के लिए पठनीय तरीका है:

int j = 0;
for(int i = 0; i < 5; ++i) {
    do_something(i, j);
    ++j;
}

Forलूप उन मामलों के लिए होते हैं जहां आपका लूप एक बढ़ते / घटते हुए वैरिएबल पर चलता है। किसी अन्य चर के लिए, इसे लूप में बदलें।

यदि आपको jबंधे होने की आवश्यकता है i, तो मूल चर को क्यों नहीं छोड़ना है और जोड़ना है i?

for(int i = 0; i < 5; ++i) {
    do_something(i,a+i);
}

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


2
पहले उदाहरण में, j को एक से अधिक बार बढ़ा दिया गया है! क्या एक पुनरावृत्ति के बारे में जहां पहले एक्स चरणों के लिए कुछ कार्रवाई करने की आवश्यकता है? (और संग्रह हमेशा बहुत लंबा होता है) आप हर पुनरावृत्ति को पुनरावृत्ति की तुलना में कर सकते हैं, लेकिन बहुत क्लीनर इमो है।
पीटर स्मिट

0
int main(){
    int i=0;
    int a=0;
    for(i;i<5;i++,a++){
        printf("%d %d\n",a,i);
    } 
}

1
लूप नहीं बनाने iऔर aस्थानीय करने की क्या बात है ?
sbi

2
कोई नहीं, सिर्फ यह दिखाने के लिए कि दोनों वेतन वृद्धि कैसे करें, इसका सिर्फ एक उदाहरण सिंटैक्स
Arkaitz Jimenez

0

मैथ्स का इस्तेमाल करें। यदि दो ऑपरेशन गणितीय रूप से लूप पुनरावृत्ति पर निर्भर करते हैं, तो गणित क्यों नहीं करते हैं?

int i, j;//That have some meaningful values in them?
for( int counter = 0; counter < count_max; ++counter )
    do_something (counter+i, counter+j);

या, विशेष रूप से ओपी के उदाहरण का जिक्र करते हुए:

for(int i = 0; i != 5; ++i)
    do_something(i, j+i);

विशेष रूप से यदि आप किसी फ़ंक्शन को मान द्वारा पास कर रहे हैं, तो आपको कुछ ऐसा प्राप्त करना चाहिए जो वास्तव में आप चाहते हैं।

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