मैं उन्हें देखा है दोनों सी # कोड के कई टुकड़ों में इस्तेमाल किया जा रहा है, और मैं जब उपयोग करने के लिए जानना चाहते हैं i++या ++i( iजैसे एक नंबर चर जा रहा है int, float, double, आदि)। जो कोई भी यह जानता है?
मैं उन्हें देखा है दोनों सी # कोड के कई टुकड़ों में इस्तेमाल किया जा रहा है, और मैं जब उपयोग करने के लिए जानना चाहते हैं i++या ++i( iजैसे एक नंबर चर जा रहा है int, float, double, आदि)। जो कोई भी यह जानता है?
जवाबों:
विचित्र रूप से यह ऐसा लगता है कि अन्य दो उत्तर इसे स्पष्ट नहीं करते हैं, और यह निश्चित रूप से कहने योग्य है:
i++इसका मतलब है 'मुझे मूल्य बताओ i, फिर वेतन वृद्धि'
++iमतलब 'वेतन वृद्धि i, फिर मुझे मूल्य बताओ'
वे प्री-इन्क्रीमेंट, पोस्ट-इन्क्रीमेंट ऑपरेटर हैं। दोनों ही मामलों में परिवर्तनशील है , लेकिन अगर आप दोनों अभिव्यक्तियों का मूल्य समान मामलों में लेना चाहते हैं, तो परिणाम अलग-अलग होंगे।
इस प्रश्न का विशिष्ट उत्तर, दुर्भाग्य से यहां पहले से ही पोस्ट किया गया है, एक यह है कि "शेष संचालन से पहले वेतन वृद्धि" करता है और दूसरा "शेष संचालन के बाद वेतन वृद्धि" करता है। हालाँकि यह सहज रूप से विचार को पार कर जाता है, लेकिन यह कथन पूरी तरह से गलत है । समय में घटनाओं का क्रम C # में बहुत अच्छी तरह से परिभाषित किया गया है, और यह मज़बूती से ऐसा मामला नहीं है कि ++ के उपसर्ग (++ संस्करण) और पोस्टफ़िक्स (var ++) संस्करण अन्य कार्यों के संबंध में एक अलग क्रम में चीजें करते हैं।
यह आश्चर्यजनक है कि आप इस प्रश्न के बहुत से गलत उत्तर देखेंगे। एक महान कई "अपने आप को सी # सिखाते हैं" किताबें भी गलत हो जाती हैं। साथ ही, C # करने का तरीका यह बताता है कि C कैसे करता है। बहुत से लोग कारण जैसे कि C # और C एक ही भाषा हैं; वो नहीं हैं। मेरी राय में C # में इंक्रीमेंट और डीक्रीमेंट ऑपरेटर्स का डिज़ाइन इन ऑपरेटर्स सी में डिज़ाइन की खामियों से बचा जाता है।
दो प्रश्न हैं, जिन्हें यह निर्धारित करने के लिए उत्तर दिया जाना चाहिए कि वास्तव में उपसर्ग और पोस्टफ़िक्स ++ का संचालन C # में क्या है। पहला सवाल यह है कि परिणाम क्या है? और दूसरा सवाल यह है कि वेतन वृद्धि का दुष्प्रभाव कब होता है?
यह स्पष्ट नहीं है कि किसी भी प्रश्न का उत्तर क्या है, लेकिन इसे देखने के बाद यह वास्तव में काफी सरल है। एक चर x के लिए x ++ और ++ x ठीक क्या करते हैं, इसके लिए मुझे मंत्र दें।
उपसर्ग फॉर्म (++ x) के लिए:
उपसर्ग फॉर्म के लिए (x ++):
ध्यान देने योग्य कुछ बातें:
सबसे पहले, समय में घटनाओं का क्रम दोनों मामलों में समान है । फिर, यह बिल्कुल नहीं है कि समय में घटनाओं का क्रम उपसर्ग और पश्चात के बीच बदल जाता है। यह कहना पूरी तरह से गलत है कि मूल्यांकन अन्य मूल्यांकन से पहले या अन्य मूल्यांकन के बाद होता है। मूल्यांकन दोनों मामलों में ठीक उसी क्रम में होता है जैसा कि आप चरण 1 के माध्यम से देख सकते हैं। केवल अंतर यह है अंतिम चरण - परिणाम अस्थायी, या नए, वृद्धि मूल्य के मूल्य है या नहीं।
आप इसे एक सरल सी # कंसोल ऐप के साथ आसानी से प्रदर्शित कर सकते हैं:
public class Application
{
public static int currentValue = 0;
public static void Main()
{
Console.WriteLine("Test 1: ++x");
(++currentValue).TestMethod();
Console.WriteLine("\nTest 2: x++");
(currentValue++).TestMethod();
Console.WriteLine("\nTest 3: ++x");
(++currentValue).TestMethod();
Console.ReadKey();
}
}
public static class ExtensionMethods
{
public static void TestMethod(this int passedInValue)
{
Console.WriteLine("Current:{0} Passed-in:{1}",
Application.currentValue,
passedInValue);
}
}
ये रहे नतीजे ...
Test 1: ++x
Current:1 Passed-in:1
Test 2: x++
Current:2 Passed-in:1
Test 3: ++x
Current:3 Passed-in:3
पहले परीक्षण में, आप देख सकते हैं कि दोनों currentValueऔर क्या पारित किया गया थाTestMethod() विस्तार , उसी मूल्य को दिखाते हैं, जैसा कि अपेक्षित था।
हालांकि, दूसरे मामले में, लोग आपको यह बताने की कोशिश करेंगे कि कॉल के बाद होने वाली वेतन वृद्धि होती currentValueहै , लेकिन जैसा कि आप परिणामों से देख सकते हैं, यह कॉल से पहले होता है जैसा कि 'वर्तमान: 2' परिणाम से संकेत मिलता है।TestMethod()
इस स्थिति में, पहले का मान currentValueअस्थायी में संग्रहीत किया जाता है। अगला, उस मूल्य का एक संवर्धित संस्करण वापस संग्रहीत किया जाता है, currentValueलेकिन अस्थायी को छूने के बिना जो अभी भी मूल मूल्य को संग्रहीत करता है। अंत में उस अस्थायी को पारित कर दिया जाता है TestMethod()। यदि वेतन वृद्धि कॉल के बाद हुई है TestMethod()तो यह समान, गैर-वेतन वृद्धि दो बार लिखेगा, लेकिन ऐसा नहीं होता है।
यह ध्यान रखना महत्वपूर्ण है कि दोनों
currentValue++और++currentValueसंचालन से लौटाया गया मान अस्थायी पर आधारित होता है, न कि उस समय जब चर प्रचालन से बाहर होता है, तब चर में संग्रहीत वास्तविक मूल्य।ऊपर दिए गए संचालन के क्रम में याद करें, पहले दो चरण अस्थायी में चर के तत्कालीन मूल्य को कॉपी करते हैं। यही वह है जो रिटर्न मान की गणना करने के लिए उपयोग किया जाता है; उपसर्ग संस्करण के मामले में, यह है कि प्रत्यय संस्करण के मामले में जबकि अस्थायी मूल्य में वृद्धि हुई है, यह उस मूल्य को सीधे / गैर-संवर्धित है। अस्थायी में प्रारंभिक भंडारण के बाद चर को फिर से नहीं पढ़ा जाता है।
और अधिक सरल रूप से कहें, तो उपसर्ग संस्करण उस मान को लौटाता है जो चर से पढ़ा गया था (यानी अस्थायी का मान) जबकि उपसर्ग संस्करण उस मान को लौटाता है जो चर पर वापस लिखा गया था (यानी अस्थायी का बढ़ा हुआ मूल्य)। न ही चर का मान लौटाएं।
यह समझना महत्वपूर्ण है क्योंकि चर स्वयं अस्थिर हो सकता है और किसी अन्य थ्रेड पर बदल गया है जिसका अर्थ है कि उन कार्यों का वापसी मूल्य चर में संग्रहीत वर्तमान मूल्य से भिन्न हो सकता है।
लोगों में पूर्ववर्तीता, सहानुभूति के बारे में बहुत भ्रमित होना आश्चर्यजनक है, और जिस क्रम में साइड इफेक्ट्स निष्पादित किए जाते हैं, मुझे ज्यादातर संदेह होता है क्योंकि यह सी # में इतना भ्रामक है ध्यान से इन सभी मामलों में कम भ्रमित होने के लिए डिज़ाइन किया गया है। इन मुद्दों के कुछ अतिरिक्त विश्लेषण के लिए, मेरे सहित इस विचार के मिथ्यात्व को प्रदर्शित करता है कि उपसर्ग और उपसर्ग संचालन "सामान को समय में चारों ओर ले जाते हैं" देखें:
https://ericlippert.com/2009/08/10/precedence-vs-order-redux/
जिसके कारण यह SO प्रश्न:
int [] गिरफ्तारी = {0}; int value = arrest [गिरफ्तारी [0] ++]; मान = 1?
आपको इस विषय पर मेरे पिछले लेखों में भी दिलचस्पी हो सकती है:
https://ericlippert.com/2008/05/23/precedence-vs-associativity-vs-order/
तथा
https://ericlippert.com/2007/08/14/c-and-the-pit-of-despair/
और एक दिलचस्प मामला जहां सी को शुद्धता के बारे में तर्क देना मुश्किल हो जाता है:
https://docs.microsoft.com/archive/blogs/ericlippert/bad-recursion-revisited
इसके अलावा, हम अन्य ऑपरेशनों पर विचार करते समय समान सूक्ष्म मुद्दों में भाग लेते हैं, जिनके साइड इफेक्ट होते हैं, जैसे कि जंजीर सरल कार्य:
https://docs.microsoft.com/archive/blogs/ericlippert/chaining-simple-assignments-is-not-so-simple
और यहाँ क्यों वेतन वृद्धि ऑपरेटरों में परिणाम पर कोई रोचक पोस्ट है मूल्यों बल्कि की तुलना में सी # में चर :
i++या ++iकोड में उपयोग किया जाता है, पृष्ठभूमि में चल रही चीजें बस यही हैं; पृष्ठभूमि में । मैं सी # लिखता हूं कि इस स्तर पर क्या हो रहा है, ऊपर के स्तर पर चढ़ने के लिए, इसलिए यदि यह वास्तव में आपके सी # कोड के लिए मायने रखता है, तो आप पहले से ही गलत भाषा में हो सकते हैं।
i++;) for (int i = 0; i < x; i++)... और मैं बहुत बहुत इस की खुशी! (और मैं कभी उपसर्ग ऑपरेटर का उपयोग नहीं करता)। अगर मुझे कुछ लिखना है, जिसे समझने के लिए एक वरिष्ठ प्रोग्रामर को 2 मिनट की आवश्यकता होगी ... खैर ... कोड की एक और पंक्ति लिखना या एक अस्थायी चर पेश करना बेहतर होगा :-) मुझे लगता है कि आपका "लेख" (मैं जीत गया 't call it "answer") vindicates मेरी पसंद :-)
यदि आपके पास है:
int i = 10;
int x = ++i;
तब xहोगा 11।
लेकिन अगर आपके पास:
int i = 10;
int x = i++;
तब xहोगा 10।
एरिक के रूप में ध्यान दें, दोनों मामलों में एक ही समय में वेतन वृद्धि होती है, लेकिन परिणाम के रूप में जो मूल्य दिया जाता है वह भिन्न होता है (धन्यवाद एरिक!)।
आम तौर पर, मैं उपयोग करना पसंद करता हूं ++i जब तक कि कोई अच्छा कारण न हो। उदाहरण के लिए, लूप लिखते समय, मैं उपयोग करना पसंद करता हूं:
for (int i = 0; i < 10; ++i) {
}
या, अगर मुझे केवल एक चर बढ़ाने की आवश्यकता है, तो मुझे उपयोग करना पसंद है:
++x;
आम तौर पर, एक तरह से या दूसरे का बहुत महत्व नहीं होता है और कोडिंग शैली के लिए नीचे आता है, लेकिन अगर आप अन्य असाइनमेंट (जैसे मेरे मूल उदाहरणों) के अंदर ऑपरेटरों का उपयोग कर रहे हैं, तो संभावित दुष्प्रभावों के बारे में पता होना महत्वपूर्ण है।
iचर नाम के बजाय varइसका C # कीवर्ड के रूप में उपयोग करने के लिए संपादित किया है ।
int i = 0;
Console.WriteLine(i++); // Prints 0. Then value of "i" becomes 1.
Console.WriteLine(--i); // Value of "i" becomes 0. Then prints 0.
क्या इससे आपके सवाल का जवाब मिलता है ?
ऑपरेटर के काम करने का तरीका यह है कि यह एक ही समय में बढ़ जाता है, लेकिन अगर यह एक चर से पहले है, तो अभिव्यक्ति बढ़े / घटाए गए चर के साथ मूल्यांकन करेगी:
int x = 0; //x is 0
int y = ++x; //x is 1 and y is 1
यदि यह चर के बाद है, तो वर्तमान कथन मूल चर के साथ निष्पादित हो जाएगा, जैसे कि यह अभी तक बढ़ाया / बढ़ाया नहीं गया है:
int x = 0; //x is 0
int y = x++; //'y = x' is evaluated with x=0, but x is still incremented. So, x is 1, but y is 0
जब तक आवश्यक न हो मैं प्री-इंक्रीमेंट / डिक्रीमेंट (++ x) का उपयोग करके dcp से सहमत हूं। वास्तव में एकमात्र समय जब मैं पोस्ट-इन्क्रीमेंट / डिक्रीमेंट का उपयोग करता हूं, उस समय के लूप या लूप में होता है। ये छोरियां समान हैं:
while (x < 5) //evaluates conditional statement
{
//some code
++x; //increments x
}
या
while (x++ < 5) //evaluates conditional statement with x value before increment, and x is incremented
{
//some code
}
आप एरेज़ को इंडेक्स करते समय भी ऐसा कर सकते हैं और ऐसे:
int i = 0;
int[] MyArray = new int[2];
MyArray[i++] = 1234; //sets array at index 0 to '1234' and i is incremented
MyArray[i] = 5678; //sets array at index 1 to '5678'
int temp = MyArray[--i]; //temp is 1234 (becasue of pre-decrement);
आदि आदि...
सिर्फ C ++ में रिकॉर्ड के लिए, यदि आप या तो (यानी) का उपयोग कर सकते हैं, तो आप परिचालन के आदेश की परवाह नहीं करते हैं (आप बस वेतन वृद्धि या गिरावट चाहते हैं और बाद में इसका उपयोग करना चाहते हैं) उपसर्ग ऑपरेटर अधिक कुशल है क्योंकि यह नहीं करता है ऑब्जेक्ट की एक अस्थायी प्रतिलिपि बनाना होगा। दुर्भाग्य से, ज्यादातर लोग उपसर्ग (++ संस्करण) के बजाय पॉज़िफ़िक्स (var ++) का उपयोग करते हैं, सिर्फ इसलिए कि हमने शुरू में जो सीखा है। (मुझे एक साक्षात्कार में इस बारे में पूछा गया था)। सुनिश्चित नहीं है कि यह सी # में सच है, लेकिन मुझे लगता है कि यह होगा।