सामग्री पर जाएँ
Topos Uranos

सारांश

जो प्रोग्राम केवल स्टेटमेंटों को एक के बाद एक रखता है, वह अपने डेटा चाहे जो हों, हमेशा एक ही काम करता है; डेटा के अनुसार प्रतिक्रिया देने के लिए उसे निर्णय लेना पड़ता है। यह पाठ C++ के निर्णयों का अध्ययन करता है: if और else, जो किसी शर्त के अनुसार दो रास्तों में से एक चुनते हैं; else if की शृंखलाएँ, जो कई रास्तों में से एक चुनती हैं, और जिनमें शर्तों का क्रम तय करता है कि हर शाखा किस स्थिति को सँभालती है; नेस्टेड निर्णय और लटकते else का जाल; और enum class के साथ switch, जो नाम वाले असतत मानों में से चुनते हैं, और जिनमें कंपाइलर चेतावनी देता है यदि कोई स्थिति छूट जाए या कोई स्थिति अपने बाद वाली स्थिति में गिर जाए। इन सबको जोड़ने वाली अवधारणा स्थितियों के अनुसार विश्लेषण है: सही निर्णय इनपुट के समुच्चय को ऐसी परस्पर अपवर्जी स्थितियों में बाँटता है जो उसे पूरी तरह ढक लेती हैं, और हर स्थिति की जाँच उसके भीतर के एक परीक्षण से और उसकी हर सीमा पर एक परीक्षण से होती है।

अधिगम उद्देश्य

  1. ऐसे सरल, शृंखलित और नेस्टेड निर्णय लिखना जो किसी विनिर्देश की सभी स्थितियों को सँभालें।
  2. यह जाँचना कि if और else if की शृंखला की स्थितियाँ परस्पर अपवर्जी और सर्वसमावेशी हैं, और हर स्थिति के लिए एक परीक्षण इनपुट तैयार करना।
  3. असतत मानों के लिए enum class के साथ switch का उपयोग करना, और समझाना कि कोई स्थिति छूट जाने पर कंपाइलर किस बात की चेतावनी देता है।
  4. लटकते else और switch की स्थितियों के बीच फ़ॉलथ्रू को पहचानना, और उन्हें ठीक करना।

if और else

निर्णय का रूप

पाठ समस्या से एल्गोरिदम तक ने वे तीन रूप प्रस्तुत किए जिनसे हर एल्गोरिदम बनता है: अनुक्रम, निर्णय और पुनरावृत्ति। अब तक पाठ्यक्रम के प्रोग्राम अनुक्रम रहे हैं, इकाई 1 में पहले से इस्तेमाल हुए इक्के-दुक्के if को छोड़कर; यह पाठ दूसरे रूप को C++ में लिखता है। निर्णय किसी शर्त की गणना करता है, यानी bool प्रकार के किसी व्यंजक की, जैसे पाठ संबंध और तर्क के व्यंजक, और शर्त सत्य हो तो एक ब्लॉक चलाता है और असत्य हो तो दूसरा:

C++ कोड
if (शर्त) {    // शर्त सत्य होने पर चलता है} else {    // शर्त असत्य होने पर चलता है}

शर्त हमेशा कोष्ठकों में लिखी जाती है। else वाला भाग वैकल्पिक है: उसके बिना, शर्त असत्य हो तो कुछ नहीं होता और प्रोग्राम निर्णय के बाद वाले स्टेटमेंट से आगे बढ़ता है। दोनों स्थितियों में दोनों रास्ते अंत में मिल जाते हैं, इसलिए निर्णय, बाहर से देखने पर, एक ही स्टेटमेंट है जिसका एक प्रवेश और एक निकास है, जैसा पाठ 1.1 ने माँगा था।

उदाहरणयूक्लिडीय शेषफल

पाठ अंकगणितीय संक्रियाएँ ने दिखाया कि a % b का चिह्न भाज्य का होता है, इसलिए a=−7a = -7 और b=2b = 2 होने पर उसका मान −1-1 होता है, जबकि यूक्लिडीय शेषफल, जो कभी ऋणात्मक नहीं होता, 1 होता है; और उसने बताया था कि इसे ठीक करने का सुरक्षित तरीका यह है कि केवल तब bb जोड़ा जाए जब शेषफल ऋणात्मक हो। प्रोग्राम मानता है कि b>0b > 0।

C++ प्रोग्राम
#include <iostream>#include <print>​int main(){    int a{};    int b{};    std::cin >> a >> b;    int r{a % b};    if (r < 0) {        r = r + b;    }    std::println("{} को {} से भाग देने पर यूक्लिडीय शेषफल: {}", a, b, r);}
प्रोग्राम का इनपुट
-7 2
आउटपुट
-7 को 2 से भाग देने पर यूक्लिडीय शेषफल: 1

चर r अब स्थिरांक नहीं है, क्योंकि निर्णय उसे बदल सकता है। चित्र दोनों संभव रास्तों का अनुसरण करता है।

प्रमाण

  1. निष्पादन निर्णय तक तब पहुँचता है जब r की गणना हो चुकी होती है, और सबसे पहले वह शर्त r < 0 की गणना करता है: समचतुर्भुज प्रोग्राम का वह एकमात्र बिंदु है जहाँ रास्ते अलग होते हैं।

  2. यदि शर्त सत्य है, जैसे −7-7 और 2 के साथ, तो if का ब्लॉक चलता है: r का मान −1-1 से 1 हो जाता है।

  3. यदि वह असत्य है, जैसे 7 और 2 के साथ, तो पूरा ब्लॉक छोड़ दिया जाता है, और r अपना मान बनाए रखता है।

  4. दोनों रास्ते एक ही बिंदु पर मिलते हैं, और वहाँ से प्रोग्राम दोनों स्थितियों में एक ही तरह आगे बढ़ता है: परिणाम लिखने वाला स्टेटमेंट हमेशा चलता है।

else के साथ निर्णय दो ऐसी क्रियाओं में से एक चुनता है जो एक-दूसरे को अपवर्जित करती हैं। पाठ संबंध और तर्क की अधिवर्ष वाली शर्त एक bool देती है; निर्णय उसे प्रोग्राम के व्यवहार में बदल देता है।

C++ प्रोग्राम
#include <iostream>#include <print>​int main(){    int year{};    std::cin >> year;    const bool isLeap{(year % 4 == 0 && year % 100 != 0) || year % 400 == 0};    if (isLeap) {        std::println("{} अधिवर्ष है: फ़रवरी में 29 दिन होते हैं।", year);    } else {        std::println("{} अधिवर्ष नहीं है: फ़रवरी में 28 दिन होते हैं।", year);    }}
प्रोग्राम का इनपुट
1900
आउटपुट
1900 अधिवर्ष नहीं है: फ़रवरी में 28 दिन होते हैं।

शर्त को नाम देना, जैसे isLeap, इस बात को कि क्या तय किया जाता है, इस बात से अलग करता है कि निर्णय के साथ क्या किया जाता है।

कोष्ठक-धनु हमेशा

C++ का व्याकरण ब्लॉक में एक ही स्टेटमेंट होने पर कोष्ठक-धनु छोड़ने की अनुमति देता है: if (r < 0) r = r + b; मान्य है। लेकिन कोष्ठक-धनु के बिना निर्णय केवल अपने ठीक बाद वाले स्टेटमेंट को नियंत्रित करता है, और पाठक जिसे नियंत्रित समझता है वह इंडेंटेशन पर निर्भर करता है, जिसे कंपाइलर अनदेखा करता है। यदि ऐसा है, तो बाद का कोई भी बदलाव (दूसरा स्टेटमेंट जोड़ना, पहले को टिप्पणी बना देना) अर्थ बदल सकता है, बिना इसके कि टेक्स्ट में यह दिखे। इससे पाठ्यक्रम का नियम निकलता है: if या else के ब्लॉक में हमेशा कोष्ठक-धनु होते हैं, चाहे उसमें एक ही स्टेटमेंट हो।

सबसे छोटी त्रुटि इस नियम की पुष्टि करती है। कोष्ठकों के बाद लगा अर्धविराम एक खाली स्टेटमेंट है, और निर्णय उसी खाली स्टेटमेंट को नियंत्रित करता है; उसके बाद आने वाला ब्लॉक अब if का नहीं रहता और हमेशा चलता है।

C++ प्रोग्राम
#include <print>​int main(){    const int stock{12};    if (stock == 0);    {        std::println("माल समाप्त");    }    std::println("उपलब्ध मात्रा: {}", stock);}
कंपाइलर की चेतावनियाँ
main.cpp: In function ‘int main()’:main.cpp:6:20: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body]    6 |     if (stock == 0);      |                    ^main.cpp:6:5: warning: this ‘if’ clause does not guard... [-Wmisleading-indentation]    6 |     if (stock == 0);      |     ^~main.cpp:7:5: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the ‘if’    7 |     {      |     ^
आउटपुट
माल समाप्तउपलब्ध मात्रा: 12

प्रोग्राम घोषित करता है कि माल समाप्त हो गया है, जबकि 12 नग बचे हैं। GCC दो चेतावनियाँ देता है: -Wempty-body खाली बॉडी के चारों ओर कोष्ठक-धनु लगाने का सुझाव देता है, और -Wmisleading-indentation बताता है कि ब्लॉक का इंडेंटेशन ऐसा है मानो if उसे नियंत्रित करता हो। दूसरी क्लासिक त्रुटि, if (x == 0) की जगह if (x = 0), पाठ कंपाइल करना, चलाना और कॉन्फ़िगर करना में देखी गई थी: असाइनमेंट का मान शून्य होता है, जो false में बदल जाता है, और -Wparentheses चेतावनी देता है। दोनों स्थितियों में प्रोग्राम कंपाइल हो जाता है; चेतावनियों के बिना त्रुटि पर किसी का ध्यान नहीं जाता।

कोष्ठक-धनु का एक और परिणाम है: if के ब्लॉक के भीतर घोषित चर केवल वहीं मौजूद रहता है। यदि किसी शाखा में गणना किया गया मान निर्णय के बाद इस्तेमाल होता है, तो चर पहले घोषित किया जाता है, जैसे शेषफल वाले उदाहरण में r; स्कोप का अध्ययन पाठ पैरामीटर और स्कोप में होगा।

सशर्त संक्रियक

जब किसी निर्णय की दोनों शाखाएँ केवल एक मान चुनती हैं, तो C++ एक छोटा रूप देती है: शर्त ? a : b का मान शर्त सत्य होने पर a और असत्य होने पर b होता है, और वह केवल चुने गए तत्व की गणना करता है। if के विपरीत, जो एक स्टेटमेंट है, सशर्त संक्रियक एक व्यंजक है: उसका एक मान और एक प्रकार होता है, और वह वहाँ आ सकता है जहाँ कोई भी व्यंजक आ सकता है, उदाहरण के लिए किसी स्थिरांक के इनिशियलाइज़ेशन में, जिसकी अनुमति if const छोड़े बिना नहीं देता।

C++ प्रोग्राम
#include <iostream>#include <print>​int main(){    int a{};    int b{};    std::cin >> a >> b;    const int larger{a > b ? a : b};    std::println("बड़ा: {}", larger);    std::println("{} {}", b, b == 1 ? "वस्तु" : "वस्तुएँ");    const auto mixed{a > b ? a : 0.5};    std::println("साझा प्रकार: {:.1f}", mixed);    std::println("कोष्ठक के बिना: {}", 10 + a > b ? 1 : 0);    std::println("कोष्ठक के साथ: {}", 10 + (a > b ? 1 : 0));}
प्रोग्राम का इनपुट
7 3
आउटपुट
बड़ा: 73 वस्तुएँसाझा प्रकार: 7.0कोष्ठक के बिना: 1कोष्ठक के साथ: 11

पहली दो पंक्तियाँ वह उपयोग दिखाती हैं जो कोड को स्पष्ट करता है: बड़े मान को चुनना और किसी शब्द को संख्या के अनुरूप करना, पूरे स्टेटमेंट को दो शाखाओं में दोहराए बिना। तीसरी दिखाती है कि व्यंजक का एक ही प्रकार होता है, चाहे कोई भी शाखा चुनी जाए: यदि दोनों परिणाम अलग-अलग प्रकार के हों, तो वे पाठ अंकगणितीय संक्रियाएँ के सामान्य अंकगणितीय रूपांतरणों से एक साझा प्रकार में बदल दिए जाते हैं; यहाँ int और double से double मिलता है, और चुना गया 7 7.0 के रूप में सहेजा जाता है। अंतिम दो प्राथमिकता दिखाती हैं: सशर्त संक्रियक सबसे कम प्राथमिकता वाले संक्रियकों में है, इसलिए कोष्ठक के बिना शर्त 10 + a > b बनती है और मान 11 के बजाय 1 होता है। जब सशर्त संक्रियक किसी बड़े व्यंजक का हिस्सा हो, तो उसे कोष्ठक में रखा जाता है।

जैसे ही इस संक्रियक से मान चुनने से अधिक कुछ माँगा जाता है, वह कोड को धुँधला कर देता है। नेस्ट करने पर, जैसे a > b ? (a > c ? a : c) : (b > c ? b : c) में, वह पाठक को मन ही मन एक नेस्टेड निर्णय फिर से गढ़ने पर मजबूर करता है, उन कोष्ठक-धनुओं के बिना जो उसे पठनीय बनाते हैं; और उसके साइड इफ़ेक्ट के लिए इस्तेमाल करने पर, जैसे ok ? std::println("हाँ") : std::println("नहीं") में, वह भेस बदले हुए if के सिवा कुछ नहीं। पाठ्यक्रम का नियम है कि उसे केवल दो छोटे मानों में से चुनने के लिए, बिना नेस्ट किए, इस्तेमाल किया जाए; बाकी सब if से लिखा जाता है।