programmers
चैप्टर १ की AI की HINDI प्रस्तुति

CS50 लेक्चर 1 — हिंदी अनुवाद (शब्दशः)
शुरुआत और पिछले हफ़्ते की याद
धन्यवाद।
ठीक है, यह CS50 है, और यह पहला हफ़्ता है, यानी हमारा साथ का दूसरा हफ़्ता।
आपको याद होगा कि पिछले हफ़्ते, यानी हफ़्ता शून्य में, हमने Scratch पर ध्यान दिया था। यह आख़िरकार एक ग्राफ़िकल प्रोग्रामिंग भाषा है, जिसमें आप पहेली के टुकड़ों को खींचकर छोड़ (ड्रैग-ड्रॉप) सकते हैं। ये टुकड़े आपस में तभी जुड़ते हैं जब ऐसा करना तर्क के हिसाब से सही हो।
आप में से कई लोगों ने शायद इससे कभी खेला भी होगा, जैसे मिडिल स्कूल में या उससे भी पहले।
लेकिन हमारे मक़सद के लिए, Scratch का लक्ष्य हमें कुछ बुनियादी निर्माण-खंडों का एक तरह का मानसिक ढाँचा देना था। इन्हें हम आज C में, कुछ हफ़्तों बाद Python में, और उसके बाद भी बार-बार देखेंगे।
इनमें फ़ंक्शन, रिटर्न वैल्यू, आर्ग्युमेंट, वेरिएबल, लूप, कंडीशनल और बहुत कुछ शामिल है।
आज की चुनौती: फ़ायर होज़ से पानी पीना
इसलिए अगर आज का दिन थोड़ा फ़ायर होज़ (आग बुझाने वाले मोटे पाइप) जैसा लगे, जैसा यहाँ चित्र में दिखाया गया है, तो मैं समझता हूँ। फिर भी आज के बहुत से विचार बिल्कुल वही हैं जो पिछले हफ़्ते के थे।
बस सिंटैक्स (लिखने का तरीक़ा) बदलेगा। वह थोड़ा अलग दिखेगा। थोड़ा ज़्यादा डरावना दिखेगा। उसे रटना भी थोड़ा कठिन होगा। लेकिन अभ्यास से वह "मांसपेशियों की याद" (muscle memory) आ जाएगी।
मगर विचार आख़िर में वही रहेंगे।
अगर आप नहीं जानते, तो बता दूँ कि यहाँ पास में ही MIT की एक परंपरा है, जिसे "हैक" कहते हैं। इसमें साल में एक बार छात्र कोई बहुत ही पागलपन भरा काम करते हैं।
इस बार उन्होंने एक असली चालू पानी पीने का फ़व्वारा एक असली फ़ायर हाइड्रेंट से जोड़ दिया। वहाँ लगे बोर्ड पर, जो बहुत धुँधला (पिक्सेल वाला) है, लिखा है: "MIT से शिक्षा लेना ऐसा है जैसे फ़ायर होज़ से पानी पीने की कोशिश करना।"
और कंप्यूटर साइंस, प्रोग्रामिंग और CS50 भी कभी-कभी ऐसा ही लगेगा। लेकिन यह समझ लीजिए कि आख़िर में सबसे ज़रूरी बात यह नहीं है कि आप रोज़-रोज़ अपने को कहाँ महसूस करते हैं।
सबसे ज़रूरी यह है कि तीन महीने बाद आप अपने को कहाँ पाते हैं, पिछले हफ़्ते यानी "हफ़्ता शून्य" की तुलना में।
हफ़्ता शून्य से आज तक: वही प्रोग्राम, नया रूप
तो आइए देखें कि हफ़्ता शून्य कैसा दिखता था।
वह कुछ ऐसा दिखता था: सबसे सरल प्रोग्राम, जिससे हमने उस बिल्ली से "hello, world" कहलवाया।
आज वही कोड कुछ ऐसा दिखने लगेगा। इसकी एक झलक हमने आपको पिछले हफ़्ते दी थी।
लेकिन इस बार मैंने इसे जान-बूझकर रंग-कोड किया है, ताकि एक बात समझाई जा सके।
Scratch में हमारे पास एक पीले-से रंग का पहेली-टुकड़ा था जो शुरुआत कराता था। वह ख़ुद कुछ ख़ास नहीं करता था, बस प्रोग्राम को चालू करता था। असली काम बैंगनी वाले हिस्से में होता था।
आज भी यही बात सच होगी। मैं स्क्रीन पर इस पीले-से कोड की तरफ़ थोड़ी देर हाथ हिलाकर निकल जाऊँगा। लेकिन असली असर इसी बैंगनी पंक्ति और उसके भीतर के सफ़ेद टेक्स्ट का होगा।
इन सभी पंक्तियों का मतलब हम अगले कुछ हफ़्तों में तोड़-तोड़कर समझाएँगे। लेकिन कभी-कभी हम कुछ बारीकियों को छोड़ देंगे, अगर हमें लगे कि कहानी के इस मोड़ पर वे ग़ैर-ज़रूरी हैं।
वैसे, फ़िलहाल मैं रंग-कोडिंग हटा देता हूँ। तब हम देखेंगे कि यह ऐसा कोड है जो "C" नाम की भाषा में है। हम इसी के साथ खेलना और इसी को इस्तेमाल करना आज और अगले कई हफ़्तों तक शुरू करेंगे।
सोर्स कोड और मशीन कोड
यह उस चीज़ का नमूना है जिसे हम आम तौर पर "सोर्स कोड" (source code) कहेंगे।
सोर्स कोड वह है जो प्रोग्रामर लिखते हैं। वह है जो आप लिखते हैं। वह है जो आपने लिखा था, भले ही वह पहेली के टुकड़े खींचकर-छोड़कर लिखा था।
इस हफ़्ते से आप अपने कीबोर्ड का इस्तेमाल और ज़्यादा करने लगेंगे, और आप सोर्स कोड लिखेंगे।
यह ऐसा कोड है जिसे हम इंसान थोड़े प्रशिक्षण और थोड़े अभ्यास के बाद समझ सकते हैं।
लेकिन ज़ाहिर है, पिछले हफ़्ते की बात के हिसाब से, कंप्यूटर आख़िरकार कौन-सी भाषा समझते हैं?
बस एक ही। यानी बाइनरी, शून्य और एक।
तो हाँ, आप और मैं आज से कोड ऐसे रूप में लिख सकते हैं जो कुछ ऐसा दिखता है। मानता हूँ कि यह थोड़ा रहस्यमय और पेचीदा लग सकता है, लेकिन यह ढेर सारे शून्यों और एकों से तो बेहतर ही है।
लेकिन हम सोर्स कोड में लिखेंगे। जबकि जिन मशीनों के लिए हम कोड लिखते हैं, वे आख़िर में सिर्फ़ ये शून्य और एक ही समझती हैं। हो सकता है ये भी "hello world" ही कहें, लेकिन आगे से इसे हम "मशीन कोड" (machine code) कहेंगे।
मशीन कोड वह है जो कंप्यूटर समझते हैं। सिर्फ़ शून्य और एक।
सोर्स कोड वह है जो आप और मैं समझते हैं और असल में लिखते हैं।
कंपाइलर: सोर्स कोड से मशीन कोड
इसलिए यह स्वाभाविक है कि हमें किसी न किसी तरह एक को दूसरे में अनुवाद करना पड़ेगा, यानी सोर्स कोड से मशीन कोड में।
मैंने पिछले हफ़्ते इसका बहुत हल्का-सा ज़िक्र किया था। लेकिन हम वही मानसिक ढाँचा इस्तेमाल करेंगे। इसमें हमारा लिखा सोर्स कोड किसी समस्या का इनपुट होगा।
उससे हमें जो आउटपुट चाहिए, वह मशीन कोड होगा।
तो आज हम आपको इस मुहावरे वाले "ब्लैक बॉक्स" के अंदर के लिए एक ख़ास सॉफ़्टवेयर देंगे। वह सोर्स कोड को इनपुट के रूप में लेता है और मशीन कोड को आउटपुट के रूप में बनाता है। ऐसे प्रोग्राम को "कंपाइलर" (compiler) कहते हैं।
दुनिया में कंपाइलरों के कई अलग-अलग प्रकार हैं। हम आपसे सबसे लोकप्रिय में से एक का इस्तेमाल करवाएँगे।
लेकिन यह बस एक सॉफ़्टवेयर है जिसे किसी और ने लिखा है, और जो एक भाषा को दूसरी में बदल देता है।
उदाहरण के लिए, "C" नाम की भाषा में लिखा सोर्स कोड, उन शून्यों और एकों वाले मशीन कोड में, जिन्हें Mac, PC, फ़ोन और दूसरे उपकरण असल में समझते हैं।
VS Code: हम कोड कहाँ और कैसे लिखेंगे
तो हम यह कहाँ करेंगे और कैसे करेंगे?
मैंने पिछले हफ़्ते वादा किया था कि हम आपको इस औज़ार से परिचित कराएँगे। मैंने कक्षा की बिल्कुल शुरुआत में इसे थोड़ी देर इस्तेमाल करके वह चैट बॉट बनाया था।
हम इसे इस हफ़्ते Python के लिए नहीं, बल्कि एक दूसरी भाषा, यानी C, के लिए इस्तेमाल करेंगे। और यह औज़ार, Visual Studio Code, जिसे छोटे में VS Code कहते हैं, उद्योग में बहुत लोकप्रिय है।
यही वह औज़ार है जिसे आजकल "असली" प्रोग्रामर हर समय इस्तेमाल करते हैं। विकल्प बिल्कुल हैं। अगर आप में से कुछ लोगों ने पहले प्रोग्रामिंग की है, तो हो सकता है आपने दूसरे औज़ार इस्तेमाल किए हों या देखे हों।
लेकिन यह एक बहुत आम औज़ार है जो आपको CS50 के बाद भी दिखाई देगा।
और असल में, आप इसे अपने Mac और PC पर मुफ़्त में इंस्टॉल कर सकते हैं। इस तरह कोर्स के अंत तक आप CS50 और CS50 से जुड़े किसी भी औज़ार से पूरी तरह स्वतंत्र हो जाएँगे।
लेकिन कक्षा की बिल्कुल शुरुआत के लिए हमने आपको इस औज़ार का एक क्लाउड-आधारित (इंटरनेट पर चलने वाला) रूप दिया है।
इसलिए आपको किसी भी Mac या PC या ऐसे ही किसी उपकरण पर बस एक वेब ब्राउज़र चाहिए। सब कुछ पहले से इंस्टॉल है, पहले से सेट किया हुआ है।
आपको सत्र की शुरुआत में बेकार की तकनीकी सहायता वाली सिरदर्दी से जूझना नहीं पड़ेगा, क्योंकि यह बस चलना चाहिए।
लेकिन सत्र के अंत तक, जब आप तकनीक और ख़ासकर कोड से थोड़े ज़्यादा सहज हो जाएँ, तो आप बिल्कुल इस औज़ार से ख़ुद को अलग कर सकते हैं। इसे अपने Mac या PC पर इंस्टॉल या डाउनलोड कर सकते हैं, और लगभग वही माहौल पूरी तरह अपने नियंत्रण में पा सकते हैं।
VS Code का इंटरफ़ेस
तो आज से आपको ऐसा ही दिखने वाला इंटरफ़ेस बहुत बार दिखेगा।
हमने यही इंटरफ़ेस पिछले हफ़्ते भी बहुत थोड़ी देर इस्तेमाल किया था।
आगे से हम यहीं कोड लिखेंगे।
ऊपर दाईं ओर वह जगह है जहाँ एक या अधिक कोड-टैब दिखेंगे, ठीक वैसे ही जैसे आपके इस्तेमाल किए किसी भी टैब वाले माहौल में।
उदाहरण के लिए, यह उस पहली फ़ाइल का स्क्रीनशॉट है जो हम आज बनाएँगे, जिसका नाम है hello.c।
इसका नाम hello.c इसलिए है क्योंकि यह "C" नाम की भाषा में है, जैसा हम जल्दी ही देखेंगे। (कोई श्लेष नहीं, यानी कोई शब्दों का खेल नहीं।)
इधर यहाँ का कोड रंग-कोडित है। वह ठीक उस तरह नहीं है जैसा आपने पहले देखा था, क्योंकि मैंने उसे हाथ से Scratch के ब्लॉकों जैसा दिखाया था।
लेकिन VS Code और दूसरे प्रोग्रामिंग माहौल एक सुविधा देते हैं जिसे "सिंटैक्स हाइलाइटिंग" (syntax highlighting) कहते हैं। इसमें आपको इन रंगों की चिंता करनी या सोचना भी नहीं पड़ता।
बस जब आप किसी पहचानी हुई भाषा में कोड लिखते हैं, तो VS Code जैसे औज़ार आपके कोड के अलग-अलग हिस्सों को आपके लिए अलग रंग देते हैं, ताकि अलग-अलग विशेषताएँ उभरकर दिखें।
वे विशेषताएँ क्या हैं, यह हम आज के दौरान देखेंगे।
लेकिन आप अपने स्क्रीन के नीचे दाईं ओर भी काफ़ी समय बिताएँगे, जैसा मैंने पिछले हफ़्ते थोड़ी देर किया था। इसे "टर्मिनल विंडो" (terminal window) कहते हैं। यहीं आप कोड को कंपाइल करने और कोड चलाने के लिए कमांड चलाएँगे।
और असल में, जैसा हम आज देखेंगे, आप माउस का इस्तेमाल और क्लिक करना थोड़ा कम कर देंगे। आप कीबोर्ड का इस्तेमाल और टाइप करना थोड़ा ज़्यादा करने लगेंगे।
शुरू में यह एक क़दम पीछे जाने जैसा लग सकता है, क्योंकि आप ऐसी चीज़ का इस्तेमाल बंद कर रहे हैं जो इतनी उपयोगकर्ता-अनुकूल है।
लेकिन सच्चाई यह है कि लगभग हर प्रोग्रामर को आख़िर में यही लगता है कि कीबोर्ड का ज़्यादा इस्तेमाल करने से वह कहीं ज़्यादा उत्पादक और ताक़तवर हो जाता है। वह पारंपरिक माउस या ट्रैकपैड की तुलना में चीज़ें कहीं तेज़ी से कर पाता है।
इस बीच, यहाँ बाईं ओर हमें कुछ कुछ जानी-पहचानी सुविधाएँ दिखेंगी।
जैसे यही वह जगह है जहाँ आपको वे फ़ाइलें और फ़ोल्डर दिखेंगे जो आप समय के साथ बनाएँगे।
सबसे बाईं ओर एक "एक्टिविटी बार" (activity bar) होगा। यह असल में मेन्यू का एक आधुनिक रूप है, जिससे आप चीज़ें खोल और बंद कर सकते हैं और दूसरी सुविधाओं तक पहुँच सकते हैं।
मेरे मक़सद के लिए, मैं आम तौर पर यह हिस्सा छिपा दूँगा। मैं आम तौर पर यह हिस्सा यहाँ छिपा दूँगा, ताकि जब हम साथ हों तो हमारा ध्यान लगभग पूरी तरह कोड और कमांड पर रहे।
लेकिन अभी मैं अपने ही यूज़र इंटरफ़ेस को इस तरह सरल करने के लिए कुछ छोटे कीबोर्ड शॉर्टकट टाइप कर रहा हूँ।
GUI और CLI क्या हैं
तो इस सबके साथ, कुछ शब्दावली।
यह पूरा सामूहिक माहौल जिसका मैं वर्णन कर रहा हूँ, आम तौर पर "ग्राफ़िकल यूज़र इंटरफ़ेस" (graphical user interface) कहलाता है।
क्यों? क्योंकि यह उपयोगकर्ताओं के लिए एक इंटरफ़ेस है जो स्वभाव से ग्राफ़िकल है, यानी आइकन और बटन वग़ैरह के साथ।
इसका संक्षिप्त रूप है GUI, छोटे में "गूई"।
लेकिन इस ग्राफ़िकल यूज़र इंटरफ़ेस के भीतर, जैसा वादा किया था, नीचे दाईं ओर वही टर्मिनल विंडो होगी जहाँ मैंने वादा किया था कि हम अपनी ज़्यादातर कमांड टाइप करेंगे।
और कंप्यूटिंग की शब्दावली का थोड़ा और ज्ञान देने के लिए: उसे आम तौर पर "कमांड लाइन इंटरफ़ेस" (command line interface) कहा जाता है, छोटे में CLI। इसमें आप उस इंटरफ़ेस में कमांड टाइप करते हैं।
और कंप्यूटिंग सॉफ़्टवेयर की दुनिया असल में GUI और CLI में बँटी हुई है।
कभी-कभी किसी सॉफ़्टवेयर में दोनों में से एक-एक भी हो सकता है।
पहला प्रोग्राम: hello.c बनाना
लेकिन बिना और देर किए, क्यों न हम सबसे पहले पूरी तरह इसी प्रोग्राम पर ध्यान दें। मैं कहूँगा कि यह C जैसी भाषा में लिखा जा सकने वाला सबसे सरल प्रोग्राम है। फिर देखें कि हम इसे साथ मिलकर असल में कैसे कंपाइल और रन कर सकते हैं।
तो मैं यहाँ VS Code पर जाता हूँ, जहाँ मैंने अपना फ़ाइल एक्सप्लोरर आइकनों समेत छिपा रखा है।
और मैंने अपना एक्टिविटी बार भी छिपा दिया है, ताकि मेरे पास सिर्फ़ कोड के टैबों और नीचे के कमांड प्रॉम्प्ट के लिए जगह बचे।
मैं इसे कमांड प्रॉम्प्ट इसलिए कह रहा हूँ क्योंकि इसी डॉलर चिह्न पर मैं अपनी कुछ कमांड चलाऊँगा।
और यह डॉलर चिह्न परंपरा से है। इसका मुद्रा (करेंसी) से कोई लेना-देना नहीं है। यह बस कंप्यूटिंग की एक परंपरा है।
कुछ सिस्टम कैरेट चिह्न (^) इस्तेमाल करेंगे। कुछ सिस्टम "बड़ा-से" का चिह्न (>) इस्तेमाल करेंगे, या कुछ और।
लेकिन इसका मतलब बस यही है कि अपनी कमांड यहाँ टाइप करें।
कमांड: code hello.c
पहली कमांड जो मैं टाइप करूँगा, वह यह है: code hello.c, बीच में एक स्पेस के साथ।
मैंने फ़ाइल के नाम में कोई स्पेस नहीं रखा है। मैंने फ़ाइल के किसी भी हिस्से को बड़े अक्षरों (कैपिटल) में नहीं लिखा है, क्योंकि यह एक परंपरा है।
यह आपके Mac या PC से अलग है, जहाँ हो सकता है आपको फ़ाइलों के नाम में स्पेस और बड़े अक्षर रखने की आदत हो।
आम तौर पर आप अपनी ज़िंदगी आसान बना लेंगे अगर आप छोटे अक्षर (लोअरकेस) इस्तेमाल करें और बिल्कुल कोई स्पेस न रखें।
जैसे ही मैं एंटर दबाता हूँ, आपको दिखेगा कि hello.c नाम का एक बिल्कुल नया टैब खुल जाता है, जिसकी लाइन 1 पर कर्सर झपक रहा है।
असल में यह VS Code मेरा इंतज़ार कर रहा है कि मैं अब अपने कोड की पहली पंक्ति टाइप करूँ।
लेकिन ध्यान दें कि कमांड पूरी हो चुकी है। इसलिए मेरे पास यहाँ एक और कर्सर है। अगर मैं टर्मिनल विंडो में क्लिक करके उसे आगे ले आऊँ, तो मेरा कर्सर वहाँ झपक सकता है।
इसका बस इतना मतलब है कि जब मैं तैयार हूँ, मैं एक और कमांड टाइप कर सकता हूँ।
कोड टाइप करना
तो चलिए, इस कोड को बना लेते हैं।
मैंने यह कई बार किया है, इसलिए मैं इसे काफ़ी तेज़ी से टाइप कर सकता हूँ।
लेकिन इस टैब में मैं टाइप करूँगा: include standard IO.h, मोटे तौर पर कहें तो। फिर int main void। फिर तथाकथित घुँघराले कोष्ठकों (curly braces) के अंदर, वहाँ चार स्पेस छोड़कर (इंडेंट करके) लिखूँगा: print f, उद्धरण चिह्नों में, hello, कॉमा, world, बैकस्लैश (n) और उद्धरण चिह्न बंद, सेमीकोलन।
और बस! मैंने C में अपना पहला प्रोग्राम लिख दिया।
इस तरह की कक्षा में आपको मेरे लिखे हर एक पंक्ति के कोड को नोट करने की ज़रूरत नहीं है।
असल में, कोर्स की वेबसाइट पर हमारे किए सब कुछ की प्रतियाँ होंगी, और कोर्स के नोट्स में उनके अंश भी।
लेकिन आपका स्वागत है कि मैं जो टाइप कर रहा हूँ, उसके साथ-साथ असल समय में अभ्यास करें, पर यह अपेक्षित नहीं है।
प्रोग्राम को कंपाइल करना: make hello
तो बस इतना ही।
मैंने C में अपना बिल्कुल पहला प्रोग्राम लिख दिया है।
अगर मैंने यह किसी असली Mac या PC पर, बिना कमांड लाइन इंटरफ़ेस के, किया होता, तो हो सकता है मेरे डेस्कटॉप पर hello नाम का एक नया आइकन बन जाता। और आदर्श रूप से मैं उस पर डबल-क्लिक या टैप करके प्रोग्राम चला पाता।
लेकिन क्योंकि मैं इस ख़ास प्रोग्रामिंग माहौल में हूँ, जिसमें GUI और CLI का मिश्रण है, इसलिए मुझे असल में नीचे अपनी टर्मिनल विंडो में क्लिक करना होगा।
और मुझे अब इस प्रोग्राम को पहले कंपाइल करना होगा। क्योंकि इस समय यह सिर्फ़ सोर्स कोड के रूप में मौजूद है।
तो ऐसा करने के लिए, मैं अपना कोड कंपाइल करूँगा, बिल्कुल उचित ढंग से कहकर: make space hello।
मैं "स्पेस" शब्द बोल रहा हूँ, लेकिन असल में मैंने स्पेस बार दबाया है।
Make hello, जैसा कि अर्थ से ही लगता है, hello नाम का एक प्रोग्राम बनाएगा।
ध्यान दीजिए कि मैंने फिर से hello.c नहीं कहा। क्योंकि कंपाइलर, जिसे अभी हम make कहेंगे, हालाँकि यह थोड़ा सफ़ेद झूठ है, यह अनुमान लगा लेगा कि अगर मैं hello नाम का प्रोग्राम बनाना चाहता हूँ, तो वह अपने आप इस मामले में hello.c नाम की फ़ाइल ढूँढेगा।
तो यह थोड़ा जादू है।
एंटर।
और हैरानी की बात यह है कि जब भी आपको ऐसी किसी कमांड पर कोई आउटपुट न दिखे, तो वह शायद अच्छी बात है।
आम तौर पर, जब आप अपना कोड कंपाइल करते समय कोई आउटपुट देखते हैं, तो आपने कुछ ग़लत किया है। या इस मामले में, शायद मैंने कुछ ग़लत किया हो।
लेकिन कोई आउटपुट न होना अच्छा है। क्योंकि अब मैं यह कर सकता हूँ, और यह थोड़ा पेचीदा है: मैं इस प्रोग्राम को डबल-क्लिक करके या कहीं टैप करके नहीं, बल्कि "डॉट स्लैश hello" टाइप करके चला सकता हूँ, बिना किसी स्पेस के।
प्रोग्राम को चलाना: ./hello
यह थोड़ा अजीब है। लेकिन डॉट स्लैश (./) का मतलब यह है कि अभी hello नाम का प्रोग्राम बनाने के बाद, वह प्रोग्राम मेरे मौजूदा फ़ोल्डर में पहुँच जाएगा।
वह कहीं क्लाउड में है, हाँ, उस पर थोड़ी देर में और बात करेंगे। लेकिन hello नाम का प्रोग्राम बस मेरे मौजूदा फ़ोल्डर में कहीं है।
जब मैं डॉट स्लैश कहता हूँ, तो वह ऐसा कहने जैसा है कि "मौजूदा फ़ोल्डर के अंदर जाओ और उसके अंदर hello नाम का प्रोग्राम ख़ास तौर पर चलाओ।"
अब, जैसा मैं अक्सर करता हूँ, मैं उँगलियाँ क्रॉस कर लूँगा। उम्मीद है कि मैंने इसे किसी तरह बिगाड़ा नहीं होगा। और एक सेकंड में मुझे स्क्रीन पर सचमुच "hello world" छपा हुआ दिखना चाहिए।
तीन कमांड का सार
तो इन कमांडों को बस दोहरा लेते हैं।
एक: मैंने चलाया code hello dot c। यह VS Code की अपनी ख़ास चीज़ है। "code", यानी VS Code का छोटा रूप, बस hello dot c नाम की एक नई फ़ाइल बना देता है। फिर मैं अपने कीबोर्ड से अपने रास्ते पर चल पड़ता हूँ।
दो: make hello उस सोर्स कोड को मशीन कोड में कंपाइल करता है, और इस तरह hello नाम की एक नई फ़ाइल बनाता है।
तीन: उस प्रोग्राम, hello, को चलाने के लिए मैं यह अजीब-सी कमांड टाइप करता हूँ: dot slash hello।
यह ढाँचा बार-बार दिखेगा
लेकिन यह एक ऐसा ढाँचा (पैराडाइम) है जिसे, आप अपने प्रोग्रामों को चाहे जो नाम दें, हम बार-बार-बार देखेंगे।
इसलिए अगर आपने कभी ऐसा कुछ नहीं किया है, तब भी यह बहुत जल्दी जाना-पहचाना लगने लगेगा।
सवाल-जवाब: प्रोग्राम का नाम
हाँ, कोई सवाल?
(छात्र का सवाल) जब आप कहते हैं "make hello", तो कंप्यूटर को कैसे पता चलता है कि कोड का कौन-सा हिस्सा hello के लिए है?
अच्छा सवाल है। जब मैं कहता हूँ "make hello", तो कंप्यूटर को कैसे पता चलता है कि कोड का कौन-सा हिस्सा इस प्रोग्राम hello के लिए है? वह सचमुच hello dot c की पूरी सामग्री उठाएगा और उसे किसी तरह एक प्रोग्राम में बदल देगा।
(छात्र) और क्या नाम ज़रूर hello ही होना चाहिए? क्या उसका नाम hello होना ज़रूरी है?
नहीं। मैं इसे goodbye कह सकता था, या "my first program dot c", या कुछ भी।
बस शर्त यह है कि मैं यहाँ के शब्दों को उसी हिसाब से बदल दूँ।
(छात्र) लेकिन उन्हें एक ही चीज़ से आना चाहिए, है न? अगर मेरे पास green dot c है, तो वह green बनाएगा, या जो भी हो।
बिल्कुल सही। अगर आप वहाँ नाम बदलें, तो आपको अपनी कमांड भी उसी हिसाब से बदलनी होंगी।
इन क़दमों के बारे में कोई और सवाल?
नहीं? ठीक है।
Scratch और C का एक-से-एक मिलान
तो आइए इसे सुलझाकर देखें कि हमने अभी असल में क्या किया और यह कोड उसी तरह क्यों काम करता है।
दोहराने के लिए, Scratch में हमारे पास ऐसा एक प्रोग्राम था। जब हरे झंडे पर क्लिक किया जाता, तो हम स्क्रीन पर "hello world" कहलवाना चाहते थे।
इसके अनुरूप कोड मोटे तौर पर यह है।
और ध्यान दीजिए कि पीला या नारंगी-सा कोड "when green flag clicked" से मेल खाता है।
यहाँ का बैंगनी कोड "say" ब्लॉक से मेल खाता है।
और इसके अंदर का सफ़ेद कोड मोटे तौर पर उससे मेल खाता है जो पिछले हफ़्ते उस सफ़ेद अंडाकार में था, जिसका हम बार-बार इस्तेमाल करते रहे।
तो आइए एक-से-एक मिलान को और साफ़ करें।
ये स्लाइड जान-बूझकर इसलिए बनाई गई हैं कि आपको फिर से वही मानसिक ढाँचा मिले: पिछले हफ़्ते के वही विचार लेना और इस हफ़्ते से बस सिंटैक्स बदल देना।
फ़ंक्शन और printf
तो जब हमारे पास इस तरह का कोई फ़ंक्शन हो, और याद कीजिए कि फ़ंक्शन बस एक क्रिया या काम है जो काम का एक छोटा-सा हिस्सा पूरा करता है, तो C में आप, ज़ाहिर है, बैंगनी पहेली-टुकड़ा नहीं, बल्कि "print" शब्द टाइप करेंगे।
ज़्यादा तकनीकी रूप से, "printf", जहाँ F का मतलब, जैसा हम जल्दी देखेंगे, "format" है, यानी छपे हुए आउटपुट का रूप तय करो। क्योंकि यह सिर्फ़ कच्चा टेक्स्ट छापने से कहीं ज़्यादा ताक़तवर है।
फिर आपके पास कोष्ठक (पैरेंथेसिस) हो सकते हैं, खुला और बंद, बायाँ और दायाँ।
और ध्यान दीजिए, यह कोई संयोग नहीं है कि MIT ने फ़ंक्शनों के इनपुट के लिए अंडाकार चुना। क्योंकि वह मोटे तौर पर बाईं और दाईं ओर के कोष्ठक की शुरुआत जैसा दिखता है।
कोष्ठक के अंदर क्या जाता है
इस बीच, संबंधित C कोड में कोष्ठकों के अंदर क्या जाता है?
आख़िर में, कम से कम, "hello, comma, world"। क्योंकि हम सचमुच यही स्क्रीन पर छापना चाहते हैं।
लेकिन C में, Scratch के उलट, थोड़ा अतिरिक्त बोझ है। थोड़ा ज़्यादा सिंटैक्स, जिससे आपको बस निपटना ही पड़ता है, ताकि कंप्यूटर को साफ़ हो जाए कि आप क्या छापना चाहते हैं।
ख़ासकर, आपको जो कुछ भी छापना है, उसे दोहरे उद्धरण चिह्नों (double quotes) से घेरना पड़ेगा। इससे साफ़ हो जाता है कि hello कोई ख़ास फ़ंक्शन या वेरिएबल या कुछ और नहीं है।
यह "hello world" अंग्रेज़ी का वह वाक्यांश है जिसे आप छापना चाहते हैं।
तो यहाँ दोहरा उद्धरण चिह्न और वहाँ दोहरा उद्धरण चिह्न का मतलब है: यहाँ से शुरू और यहाँ पर ख़त्म, जो मैं छापना चाहता हूँ।
बैकस्लैश n और सेमीकोलन
ज़्यादातर मामलों में आप उन शब्द या शब्दों के अंत में, जिन्हें आप छापना चाहते हैं, एक अजीब-सा "backslash n" भी लगाएँगे। हम इसे थोड़ी देर में हटाकर देखेंगे कि यह क्या करता है।
और आख़िर में, और शायद प्रोग्रामिंग की दुनिया में सबसे चिढ़ाने वाली बात: आपको अपनी बात सेमीकोलन (;) पर ख़त्म करनी पड़ती है।
ठीक वैसे ही जैसे अंग्रेज़ी में आप ज़्यादातर वाक्य पूर्णविराम से ख़त्म करते हैं।
और प्रोग्रामिंग की बात यह है, ख़ासकर C में, कि अगर आपने मेरे अभी-अभी गिनाए इन ब्योरों में से लगभग किसी में भी गड़बड़ की, तो कुछ न कुछ ग़लत हो जाएगा।
इसलिए आप अच्छी संगत में हैं। आपका सबसे पहला प्रोग्राम जिसे आप लिखने या कंपाइल करने की कोशिश करेंगे, बहुत संभावना है कि वह सही से न चले।
क्योंकि समय के साथ आप इन सब बारीकियों को पहचानने की "मांसपेशियों की याद" विकसित कर लेंगे। ये बारीकियाँ देखने में छोटी लगती हैं (और असल में छोटी हैं भी), लेकिन कंप्यूटर के लिए मायने रखती हैं।
गणित का फ़ंक्शन और कोड का फ़ंक्शन
ठीक है। अगर आप गणित में फ़ंक्शनों के संकेतन से परिचित हैं, तो कोड का फ़ंक्शन असल में वही विचार है जो गणित का फ़ंक्शन है।
फ़ंक्शन f कोई इनपुट लेता है, उदाहरण के लिए x, और आम तौर पर कोई आउटपुट देता है।
इसलिए अगर आप ज़्यादा इसी पृष्ठभूमि से आ रहे हैं, तो समझ लीजिए कि हम यहाँ जो कर रहे हैं, वह मोटे तौर पर वही है।
लेकिन कोड में, याद कीजिए कि हमारे पास अलग-अलग तरह के आउटपुट हो सकते हैं।
आर्ग्युमेंट और साइड इफ़ेक्ट
तो यह हमारा बड़ा मानसिक ढाँचा है। मान लीजिए हमारे पास इस ब्लैक बॉक्स के अंदर एक फ़ंक्शन है जो आर्ग्युमेंट लेता है, यानी अपने इनपुट के रूप में। तो उसके कभी-कभी "साइड इफ़ेक्ट" (side effects) हो सकते हैं।
और याद कीजिए कि साइड इफ़ेक्ट अक्सर वे दिखने वाली चीज़ें होती हैं जो नतीजे के रूप में होती हैं। वे बस स्क्रीन पर चलती हैं।
हो सकता है आवाज़ स्पीकर से निकले। यह आम तौर पर कोई क्षणिक चीज़ होती है जो बस हो जाती है।
लेकिन यह उसी तरह उपयोगी नहीं है जैसा एक दूसरे प्रकार का फ़ंक्शन, जिस पर हम थोड़ी देर में लौटेंगे।
लेकिन पिछले हफ़्ते याद कीजिए: हमने उस बिल्ली को बोलने वाले बुलबुले के साथ स्क्रीन पर लाया था, जो उस बुलबुले में "hello, world" कहती थी।
तब इनपुट "hello, world" था। और संबंधित फ़ंक्शन "say" था।
आइए कोड को तोड़कर देखें
तो देखते हैं कि हम अब तक लिखे कोड को टुकड़े-टुकड़े करके समझ सकते हैं या नहीं कि वह असल में हमारे लिए क्या कर रहा है।
इसलिए मैं VS Code पर वापस जाता हूँ।
और मैं इसे थोड़ा-सा तोड़ने का प्रस्ताव रखता हूँ। मैं "backslash n" हटा देता हूँ, क्योंकि पहली नज़र में कौन जानता या परवाह करता है कि यह क्या कर रहा है?
अगर हम इसे नहीं समझते, तो इसे हटा ही देते हैं।
अब मैं नीचे अपनी टर्मिनल विंडो में जा सकता हूँ। और मैं फिर से "dot slash hello" एंटर कर सकता हूँ।
लेकिन देखने में कोई बदलाव नहीं दिखता, जो अच्छी बात है। ऐसा नहीं लगता कि मैंने कुछ बिगाड़ा।
दोबारा कंपाइल करना क्यों ज़रूरी है
लेकिन मैंने यहाँ आपको थोड़ा गुमराह कर दिया है।
क्यों? कुछ भी बदलता क्यों नहीं दिखा?
मैंने इसे दोबारा कंपाइल नहीं किया।
याद कीजिए कि कंपाइलर सोर्स कोड को मशीन कोड में बदलता है। लेकिन वह मैं कुछ मिनट पहले ही कर चुका था।
अगर मैंने सोर्स कोड बदला है, तो यह तर्कसंगत है कि उसके असर को सचमुच देखने के लिए मुझे कोड दोबारा कंपाइल करना पड़ेगा।
तो मैं वह फिर करता हूँ। make hello, एंटर।
लगता है कुछ ग़लत नहीं हुआ।
लेकिन अब मैं करता हूँ dot slash hello, एंटर।
और अब यह बारीक है। असल में, मैं ज़ूम इन कर देता हूँ।
यह सचमुच बस एक सौंदर्य (दिखावट) की गड़बड़ है। कार्यात्मक रूप से, प्रोग्राम तकनीकी तौर पर अब भी "hello world" ही छाप रहा है।
लेकिन ऐसा क्या है जो स्पष्ट रूप से ग़लत लग रहा है? या दूसरे शब्दों में, "backslash n" ने साफ़ तौर पर क्या किया था?
(छात्र) जी, यह किसी तरह मुझे नई पंक्ति (new line) दे रहा है।
बिल्कुल। असल में "backslash n" का मतलब यही है: वहाँ मुझे एक नई पंक्ति दो।
नई पंक्ति की ज़रूरत क्यों
और मैं वह क्यों कर रहा था?
असल में सिर्फ़ दिखावट के लिए। अगर यह डॉलर चिह्न मेरे उस प्रॉम्प्ट को दिखाता है जहाँ मैं कमांड टाइप करता हूँ, तो यह कुछ बेवक़ूफ़ाना-सा लगता है कि मैंने प्रोग्राम यहाँ ख़त्म किया और प्रॉम्प्ट उसी पंक्ति में आ गया।
यह बस ग़लत लगता है, भले ही आप एक तरह से कह सकें कि यही मेरा इरादा था, हालाँकि इस मामले में यह मेरा इरादा नहीं था।
एस्केप सीक्वेंस
तो विकल्प क्या होगा?
असल में आप यहाँ जो देख रहे हैं, उसे आम तौर पर "एस्केप सीक्वेंस" (escape sequence) कहते हैं। ये प्रतीकों के कुछ ख़ास क्रम होते हैं, जैसे इस मामले में backslash और n, जो कुछ असामान्य-सा काम करते हैं।
और यहाँ उनमें से कुछ की एक अधूरी सूची है जो आपको असली दुनिया में मिलेंगी।
CS50 में भी: backslash n आपको नई पंक्ति पर ले जाता है।
Backslash r को "कैरिज रिटर्न" (carriage return) कहते हैं। अगर आपने कभी पुराने ज़माने का टाइपराइटर देखा या चलाया है, तो यह टाइप करने वाले सिरे को वापस बाईं ओर लाने की प्रक्रिया को कहते हैं। यानी यह कर्सर को क्षैतिज (आड़ा) हिलाता है, ऊर्ध्वाधर (खड़ा) नहीं।
बैकस्लैश के साथ दोहरा उद्धरण चिह्न
यह वाला दिलचस्प है: backslash double quote।
यह पैटर्न क्यों मौजूद है? Backslash double quote।
(छात्र) अगर आप सिर्फ़ double quote लिखेंगे, तो वह उस चीज़ को बंद कर देगा जो आप कहने की कोशिश कर रहे हैं।
बिल्कुल सही।
तो याद कीजिए वह वाक्यांश जो हमने टाइप करके छापने की कोशिश की थी: "hello, comma, world"।
अगर किसी वजह से आप सीधे "hello, world" नहीं कहना चाहते, बल्कि कुछ तंज़ के साथ, जैसे "hello, world" को ही उद्धरण चिह्नों में कहना चाहते हैं, तो आप उद्धरण, उद्धरण, उद्धरण, उद्धरण नहीं रख सकते और उम्मीद नहीं कर सकते कि कंप्यूटर जान लेगा कि कौन-सा उद्धरण चिह्न किससे मेल खाता है। यह तो साफ़ तौर पर अस्पष्ट है।
इसलिए अगर आप दोहरे उद्धरण चिह्नों के अंदर असल में दोहरे उद्धरण चिह्न छापना चाहते हैं, तो यह एक एस्केप सीक्वेंस है जो कंप्यूटर को बताता है: "यह कोई ऐसा उद्धरण चिह्न नहीं है जो मेरी बात की शुरुआत और अंत तय करे। यह सचमुच एक दोहरा उद्धरण चिह्न है।"
और हम ऐसी दूसरी स्थितियाँ भी देखेंगे जिनमें इकहरा उद्धरण चिह्न, यानी एपॉस्ट्रोफ़ी, के साथ भी यही बात होती है।
हम कुछ पागलपन भरी स्थितियाँ भी देखेंगे जिनमें आप एक backslash ही छापना चाहेंगे। लेकिन backslash का पहले से ही कोई ख़ास मतलब है।
तो इन सभी समस्याओं के हल मौजूद हैं। लेकिन चलिए, यहाँ बहुत ज़्यादा बारीकियों में न उतरें।
अगर backslash n न जानते तो?
लेकिन मैं कोड पर वापस जाता हूँ और बताता हूँ कि विकल्प क्या हो सकता था।
अगर मुझे backslash n के बारे में पता नहीं होता, तो कर्सर को अगली पंक्ति में ले जाने की मेरी सहज प्रवृत्ति शायद यह होती कि मैं सीधे एंटर दबा दूँ। या कुछ ऐसा करूँ: दोहरे उद्धरण चिह्न को, कोष्ठक को और सेमीकोलन को अगली पंक्ति में खिसका दूँ।
लेकिन इससे आपको थोड़ा खटकना शुरू हो जाना चाहिए।
और असल में, यह ज़्यादातर प्रोग्रामिंग भाषाओं के एक सिद्धांत का उल्लंघन करता है: ज़्यादातर प्रोग्रामिंग भाषाएँ पंक्ति-आधारित (line-based) होती हैं। आदर्श रूप से आप अपनी बात उसी पंक्ति पर शुरू और ख़त्म करते हैं। और यह उसके ख़िलाफ़ जाता है।
और दूसरी बात, भले ही आप कोड पहली बार देख रहे हों, मान लीजिए कि यह भी बेवक़ूफ़ाना लगता है, कि अपनी बात का कुछ हिस्सा अगली पंक्ति में ले जाया जाए। यह थोड़ा फूहड़ दिखता है, और है भी।
इसलिए C और कई अन्य भाषाएँ, Python भी उनमें है, इसे इन्हीं तथाकथित एस्केप सीक्वेंस देकर सुलझाती हैं।
तो अगर आपको वहाँ नई पंक्ति चाहिए, तो आप backslash n लिखते हैं, और आपको वहाँ नई पंक्ति मिल जाती है।
अब, मैंने जो कहा वह थोड़ा बढ़ा-चढ़ाकर कहा। कभी-कभी कोड की पंक्तियाँ इतनी लंबी होंगी कि वे कई पंक्तियों में लिपट जाएँगी। लेकिन आम तौर पर यह एक परंपरा है जिससे हम बचने की कोशिश करेंगे।
ग़लती 1: सेमीकोलन भूल जाना
ठीक है, और क्या ग़लत हो सकता है?
तो चलिए यह करते हैं। मैं अपनी टर्मिनल विंडो साफ़ (क्लियर) कर देता हूँ। इसके लिए मैं Control L दबा सकता हूँ, या सचमुच "clear" टाइप कर सकता हूँ।
मैं अक्सर ऐसा करूँगा, बस स्क्रीन साफ़ रखने के लिए, हालाँकि इसका कोई कार्यात्मक असर नहीं है। यह सिर्फ़ दिखावट है।
मैं अनजाने में कुछ और करता हूँ। मान लीजिए मैं अपनी बात पूरी करना भूल गया, और मैंने सेमीकोलन छोड़ दिया। बाक़ी कोड बिल्कुल सही है।
मैं अब make hello करता हूँ। एंटर।
अब हमें कुछ ज़्यादा रहस्यमय आउटपुट दिखेगा।
मैं यहाँ ऊपर स्क्रॉल करके साफ़ कर देता हूँ कि अभी क्या हुआ। मैंने make hello चलाया, लेकिन मैं किसी दूसरे प्रॉम्प्ट पर वापस नहीं आया।
मुझे तुरंत डॉलर चिह्न नहीं दिखता, क्योंकि यहाँ एक त्रुटि संदेश (error message) है जो लगभग उतना ही लंबा है जितना मेरा लिखा कोड।
चिंता की बात नहीं, देखते हैं।
यहाँ उस फ़ाइल का नाम है जिसमें समस्या मौजूद है। यह तर्कसंगत है कि वह hello.c में है।
यहाँ वह पंक्ति संख्या है जहाँ समस्या दिखती है: पंक्ति 5। और यह उपयोगी है क्योंकि यह इससे मेल खाती है।
और फिर, अगर आप गिनना चाहें, तो यह 29वाँ अक्षर है। यानी अगर मैं बाएँ से दाएँ गिनूँ, तो लगभग अक्षर 29 पर कुछ गड़बड़ है। कुछ छूट गया है।
तो यह काफ़ी अच्छा त्रुटि संदेश है। असल में इसमें यह भी लिखा है: "expected semicolon after expression", यानी अभिव्यक्ति (एक्सप्रेशन) के बाद सेमीकोलन की उम्मीद थी।
एक छोटा हरा कैरेट चिह्न (^) मुझे ग़लती की ओर इशारा कर रहा है।
तो यह, फिर से, कंपाइलर का एक और फ़ायदा है। उसे न सिर्फ़ सोर्स कोड को मशीन कोड में बदलना आता है, वह आपके कोड में ग़लतियाँ ढूँढने और उन पर आपका ध्यान खींचने की कोशिश करने में भी काफ़ी अच्छा है।
तो मैं इसे कैसे ठीक करूँ?
अगर आपने इस मोड़ पर त्रुटि संदेश समझ लिया है, तो आप बस वापस अंदर जाएँ और सेमीकोलन जोड़ दें।
मैं वापस अपनी टर्मिनल विंडो में जाता हूँ। गंदगी साफ़ करने के लिए उसे क्लियर कर देता हूँ।
मैं make hello दोबारा चलाता हूँ, और अब हम फिर से काम पर हैं।
और असल में, अगर मैं dot slash hello करूँ, तो स्क्रीन पर "hello world" वापस आ जाता है।
ग़लती 2: ऊपर की पंक्ति (include) भूल जाना
ठीक है, चलिए एक और ग़लती करते हैं।
मान लीजिए मैं भूल गया, जैसा आप कभी-कभी भूलेंगे, कि सबसे ऊपर की इस पंक्ति को शामिल करना है। यह अगले हफ़्ते ज़्यादा समझ में आएगी। लेकिन अभी, इसे छोड़ देते हैं और सीधे कोड में उतर जाते हैं।
आप सोचेंगे कि "hello world" छापने के लिए इतना काफ़ी है।
चलिए, मैं वापस नीचे अपनी टर्मिनल विंडो में जाता हूँ। मैं अब फिर से make hello करता हूँ, और मुझे इस बार एक बिल्कुल अलग त्रुटि संदेश मिलेगा।
तो अब, समस्या अब भी hello dot c में है। यह तर्कसंगत है।
पंक्ति 3। ठीक है, तो वहीं कहीं printf अचानक समस्या बन गया है, भले ही सेमीकोलन वापस आ गया है और backslash n भी वापस आ गया है।
तो पढ़ते रहते हैं।
त्रुटि: "call to undeclared library function printf with type int", और फिर आगे पूरा एक लंबा वाक्य है।
तो यह एक त्रुटि संदेश का उदाहरण है जिसे, अगर आप यह जानने के अभ्यस्त नहीं हैं कि इसका क्या मतलब है और आपने पहले इसे देखा नहीं है, तो यह कहीं ज़्यादा रहस्यमय और अस्पष्ट है। यानी यह साफ़ नहीं होता कि समस्या का हल क्या है, ख़ासकर तब, जब आपका बाक़ी कोड सचमुच सही हो।
मैं बस कोई बेवक़ूफ़ाना-सी चीज़ भूल गया हूँ।
हेडर फ़ाइलें और लाइब्रेरी
लेकिन मैं इस समस्या के बारे में कैसे सोचूँ?
तो पता चलता है कि C की एक और ख़ूबी यह है कि उसके साथ कई "हेडर फ़ाइलें" (header files) आती हैं। ये ऐसी फ़ाइलें हैं जिनके नाम dot c पर ख़त्म नहीं होते, बल्कि dot h पर ख़त्म होते हैं।
और ये तथाकथित हेडर फ़ाइलें, जो dot h पर ख़त्म होती हैं, उनमें ऐसा कोड होता है जो दूसरे लोगों ने लिखा है और जिसे आप अपने प्रोग्रामों में इस्तेमाल कर सकते हैं।
तो उदाहरण के लिए, इस ख़ास मामले में, एक हेडर फ़ाइल हमें उस चीज़ तक पहुँच दे रही है जिसे कंप्यूटिंग में आम तौर पर "लाइब्रेरी" (library) कहते हैं।
लाइब्रेरी वह कोड है जो किसी और ने लिखा है और जिसे आप इस्तेमाल कर सकते हैं।
और मैंने पिछले हफ़्ते असल में एक लाइब्रेरी इस्तेमाल की थी।
जब मैंने वह import वाली पंक्ति लिखी और OpenAI, यानी उस कंपनी, का ज़िक्र किया, तो मैं असल में उस कंपनी की एक लाइब्रेरी इस्तेमाल कर रहा था। मैंने उसे कक्षा से पहले अपने प्रोग्रामिंग माहौल में अपने-आप डाउनलोड और इंस्टॉल करवा लिया था।
क्योंकि मुझे नहीं आता कि बिना उनके कंधों पर खड़े हुए और उनके ख़ुद के लिखे बहुत सारे कोड का इस्तेमाल किए, चैट बॉट कैसे बनाया जाए।
यहाँ भी यही विचार है।
printf के लिए stdio.h शामिल करना
भले ही printf C की एक ख़ूबी है, पर अगर आप उसे इस्तेमाल करना चाहते हैं, तो आपको वह लाइब्रेरी शामिल (include) करनी होगी। इसके लिए अपने प्रोग्राम से कहना होगा कि वह उस हेडर फ़ाइल को शामिल करे जो इस फ़ंक्शन को परिभाषित करती है।
और यह आप सिर्फ़ तभी जान पाते हैं जब आपको सिखाया जाए, या आप किसी किताब या संदर्भ में देख लें।
लेकिन इस मामले में, मैं जिस हेडर फ़ाइल का इस्तेमाल करना चाहता था, उसका नाम है: standard i o dot h, यानी stdio.h।
यह "studio dot h" नहीं है।
यह इंटरनेट पर बहुत आम गड़बड़ है। अगर आप ख़ुद को "studio dot h" टाइप करते पाएँ, तो वह टाइपो (टाइप करने की ग़लती) है। सही नाम "standard i o dot h" है।
और उसी फ़ाइल में printf फ़ंक्शन परिभाषित है।
तो अगर मैं यहाँ अपने कोड पर लौटूँ, तो इस समस्या का हल सचमुच बस यही है कि मैंने कुछ देर पहले जो पंक्ति हटाई थी, उसे वापस ले आऊँ।
क्योंकि पहली पंक्ति अब मेरे लिए यह कर रही है कि वह कंपाइलर को बता रही है: "अरे हाँ, जो कोड मैं इस्तेमाल करने जा रहा हूँ, वह सब मैंने नहीं लिखा है। कृपया printf की परिभाषा इस दूसरी फ़ाइल, standard i o dot h, से शामिल कर लो।"
और फिर, यह आप सिर्फ़ किसी संदर्भ में देखकर, किसी लेक्चर में आकर, या ऐसे ही किसी तरीक़े से जान सकते हैं।
वरना यह साफ़ नहीं है।
लेकिन ये ऐसी चीज़ें हैं जो आप बहुत जल्दी देख लेते हैं।
दस्तावेज़ कहाँ देखें: मैन पेज और manual.cs50.io
तो आप इन्हें कहाँ देखें?
पता चलता है कि C के इकोसिस्टम में सैकड़ों किताबें हैं जिन्हें आप ख़रीद या डाउनलोड कर सकते हैं। बहुत-बहुत-बहुत सारी वेबसाइटें हैं, और उनमें से एक CS50 की अपनी भी है।
और असल में, "C" नाम की प्रोग्रामिंग भाषा के लिए चीज़ें देखने का पारंपरिक तरीक़ा यह है कि आप C भाषा के आधिकारिक मैन्युअल पन्ने (manual pages) देखें, जिन्हें छोटे में "मैन पेज" (man pages) कहते हैं।
दुर्भाग्य से, उनमें से कई दशकों पहले लिखे गए थे। तब वे निश्चित रूप से काफ़ी उन्नत प्रोग्रामरों ने लिखे थे, आम पाठकों के लिए नहीं।
इसलिए हमने यह किया है कि उस सारे मुफ़्त उपलब्ध दस्तावेज़ीकरण (documentation) को लाकर अपने ही URL पर रख दिया है। वह है: manual.cs50.io।
और हमने उसे असल में उन लोगों के लिए सरल बना दिया है जो कम सहज हैं, यानी आप में से वे लोग जो तकनीक से कम परिचित या कम सहज हो सकते हैं।
और असल में उन ज़्यादातर लोगों के लिए जो मैन पेज पढ़ने के आदी नहीं हैं, उसे बल्कि शिक्षण-सहायक (टीचिंग असिस्टेंट) जैसी भाषा में लिखा हुआ पाना उपयोगी होता है।
manual.cs50.io पर क्या मिलता है
तो उदाहरण के लिए, अगर आप इस तरह के किसी URL पर जाएँ, तो आपको C के साथ ही आने वाली इस आधिकारिक लाइब्रेरी, stdio.h, के लिए CS50 का दस्तावेज़ीकरण दिखेगा।
अगर आप इस तरह के URL पर जाएँ, तो आप ख़ास तौर पर printf का दस्तावेज़ीकरण देख सकते हैं।
तो मैं उदाहरण के लिए इसकी एक झलक देता हूँ। अगर मैं अपने ही कंप्यूटर पर यही करूँ, तो मुझे यहाँ CS50 के मैन पेज दिख सकते हैं।
और आपको हेडर फ़ाइल दर हेडर फ़ाइल, CS50 में अक्सर इस्तेमाल होने वाले फ़ंक्शनों का एक समूह दिखेगा।
हमने सूची को एक विशाल सूची से छानकर बहुत छोटी सूची भी बना दी है, ताकि आप देख सकें कि आपके लिए सबसे ज़्यादा काम की क्या हो सकती है।
अगर आप stdio.h जैसे किसी ख़ास पन्ने पर जाएँ, तो आपको उदाहरण के लिए यहाँ आधे दर्जन से कुछ ज़्यादा फ़ंक्शन दिखेंगे। हम आज printf से आगे इन्हें नहीं छुएँगे, लेकिन कक्षा में समय के साथ देखेंगे कि वे काम की चीज़ें करते हैं।
उदाहरण के लिए, printf स्क्रीन पर छापता है। और हम फ़ाइलें खोलने, फ़ाइलें बंद करने और ऐसे ही दूसरे फ़ंक्शन भी देखेंगे, क्योंकि वह सब stdio, यानी इनपुट और आउटपुट, से जुड़ा है।
printf का मैन पेज कैसा दिखता है
अगर मैं इस हेडर फ़ाइल के किसी ख़ास मैन पेज पर जाऊँ, तो आपको इन पन्नों का मानक रूप दिखेगा।
तो यहाँ फ़ंक्शन का नाम है, printf, और यह स्क्रीन पर छापता है।
आपको एक सार (synopsis) दिखेगा, और यह असल में बताता है कि हम "कम पेचीदा" (less comfortable) मोड में हैं। अगर आप मूल, ज़्यादा रहस्यमय दस्तावेज़ीकरण देखना चाहें, तो बस उस विकल्प का निशान हटा दें, और आपको मूल आधिकारिक दस्तावेज़ीकरण दिखेगा।
लेकिन आपको इस बात का ज़िक्र दिखेगा कि यह फ़ंक्शन किस हेडर फ़ाइल में परिभाषित है, ताकि आपको पता रहे कि अपने कोड में किस फ़ाइल का इस्तेमाल करना है।
आपको एक तथाकथित "प्रोटोटाइप" (prototype) दिखेगा, जो उस फ़ंक्शन के कोड की बस पहली पंक्ति होती है। इस पर थोड़ी देर में और बात करेंगे।
आपको अंग्रेज़ी में विवरण दिखेगा।
आपको उदाहरण कोड दिखेगा। छोटी बात यह कि यह प्रामाणिक जवाब है।
आधिकारिक दस्तावेज़ और AI डक
और भले ही इस कक्षा में आपके पास वह आभासी रबर डक (virtual rubber duck) है, यानी cs50.ai, और उसके दूसरे रूप जो आप जल्दी देखेंगे, फिर भी आगे से आपकी आदत और सहज प्रवृत्ति होनी चाहिए कि आप आधिकारिक दस्तावेज़ीकरण भी जाँचें।
और आज के सभी AI इसी तरह की चीज़ों पर प्रशिक्षित हैं, जैसे आधिकारिक दस्तावेज़ीकरण।
तो वही मूल सामग्री है जिस पर इनमें से कोई भी AI, डक भी उनमें शामिल, असल में निर्भर है।
CS50 की अपनी लाइब्रेरी: cs50.h
लेकिन हम यह भी देखेंगे कि इन आधिकारिक फ़ंक्शनों के अलावा कुछ ऐसे भी हैं जिन्हें CS50 ने ख़ुद बनाया है।
हम इन्हें असल में कोर्स के बस पहले कुछ हफ़्तों के लिए "ट्रेनिंग व्हील" (साइकिल के सहारे वाले छोटे पहिये) की तरह इस्तेमाल करते हैं। फिर हम ये ट्रेनिंग व्हील हटा देते हैं।
लेकिन हक़ीक़त यह है कि C जैसी भाषा में कुछ चीज़ें करना सचमुच कठिन या झंझट भरा होता है।
ख़ासकर तब, जब आप पहली बार प्रोग्रामिंग सीख रहे हों, या कम से कम C में नए हों। हम अंत में आपको दिखाएँगे कि वह उस तरीक़े से कैसे किया जाता है।
लेकिन अगर आप बस उपयोगकर्ता से इनपुट लेना चाहें, जैसे टेक्स्ट की कोई स्ट्रिंग या कोई संख्या, तो C में यह आम तौर पर आसान नहीं है, कम से कम इन शुरुआती दिनों में।
तो उदाहरण के लिए, यहाँ इस URL पर आप CS50 की अपनी लाइब्रेरी और CS50 की अपनी हेडर फ़ाइल, cs50.h, का दस्तावेज़ीकरण देख सकते हैं।
और आपको दस्तावेज़ीकरण में ऐसे फ़ंक्शन दिखेंगे: get string, get int, get char, और कई दूसरे भी।
और इस हफ़्ते हम इन्हें छुएँगे।
लेकिन आख़िर में यह उपयोगी काम को जल्दी निपटाने का एक तरीक़ा होगा। हम अपने कंधों पर खड़े होकर, यानी हमारे अपने लिखे फ़ंक्शन इस्तेमाल करके, फिर आपकी रुचि की समस्याएँ सुलझाएँगे।
स्ट्रिंग क्या होती है
तो उदाहरण के लिए, इनमें से एक पर पहले ध्यान दें: get string।
प्रोग्रामिंग की भाषा में "स्ट्रिंग" (string) का मतलब टेक्स्ट है, यानी शून्य या अधिक अक्षरों का टेक्स्ट, जैसे H-E-L-L-O, कॉमा, स्पेस, W-O-R-L-D।
कंप्यूटर की भाषा में वह टेक्स्ट की एक स्ट्रिंग है।
और वह ज़ाहिर है कोई संख्या नहीं है, जैसे 50। वह असल टेक्स्ट है जो आप कीबोर्ड पर टाइप करेंगे।
हम बाद में देखेंगे कि हमें और क्या-क्या चीज़ें लेनी हैं।
Scratch का "ask" और C का get_string
लेकिन इस फ़ंक्शन से हम एक और प्रोग्राम की नक़ल करना शुरू कर सकते हैं जो हमने पिछले हफ़्ते Scratch में काफ़ी जल्दी बनाया था।
तो याद कीजिए कि Scratch में यह वाला थोड़ा ज़्यादा इंटरैक्टिव था। मैंने एक और नीला पहेली-टुकड़ा, "ask", इस्तेमाल किया था ताकि उपयोगकर्ता से सचमुच इनपुट लिया जा सके।
और याद कीजिए कि आज के print f फ़ंक्शन और पिछले हफ़्ते के "say" ब्लॉक के उलट, इस बार भी हमारे पास वही इनपुट-आउटपुट वाला मॉडल है।
लेकिन अगर हम एक फ़ंक्शन को आर्ग्युमेंट देते हैं, जिसे हम देखने वाले हैं, तो आपको कभी-कभी सिर्फ़ साइड इफ़ेक्ट नहीं, बल्कि एक "रिटर्न वैल्यू" (return value) वापस मिल सकती है। यानी कोई उपयोगी, दोबारा इस्तेमाल हो सकने वाली क़ीमत, जैसे व्यक्ति का नाम, जैसा हम जल्दी देखेंगे।
C में नाम पूछने वाला कोड बनाना
ठीक है, तो चलिए इसे सचमुच करते हैं।
अगर Scratch में इसका समकक्ष यह था कि उपयोगकर्ता से पूछा जाए "तुम्हारा नाम क्या है?", और फिर जवाब का इंतज़ार किया जाए जिसे हम एक वेरिएबल में रख सकें, तो मैं प्रस्ताव रखता हूँ कि C में, साथ-साथ रखकर देखें तो, यह कुछ ऐसा दिखेगा।
बाईं ओर हमारे पास Scratch का ब्लॉक है, "ask" फ़ंक्शन। यहाँ वहाँ का आर्ग्युमेंट भी है।
और "wait" का बस इतना मतलब है कि वह तब तक इंतज़ार करेगा जब तक उपयोगकर्ता टाइप करना पूरा न कर ले।
अगर मैं इसे अब C में अनुवाद करना चाहूँ, आज से आगे, तो यह कुछ ऐसा दिखता है।
C में सबसे नज़दीकी समकक्ष, CS50 की लाइब्रेरी की बदौलत, getString नाम का एक फ़ंक्शन होगा।
तो "ask" नाम का कोई C फ़ंक्शन नहीं है। और हमने इस फ़ंक्शन का नाम जान-बूझकर getString रखा है, बस यह बहुत साफ़ करने के लिए कि आप क्या पा रहे हैं। इस मामले में यह टेक्स्ट की एक स्ट्रिंग है।
और हमारे पास कोष्ठक तैयार हैं, जो उपयोगकर्ता-इनपुट वाले उस सफ़ेद अंडाकार के सूचक हैं।
अगर मैं उपयोगकर्ता को उसी वाक्यांश से टोकना चाहूँ, "तुम्हारा नाम क्या है?", तो मैं उसे बस उन्हीं कोष्ठकों के अंदर रख सकता हूँ।
लेकिन अपने उपयोगकर्ता-इनपुट के चारों ओर मुझे आगे और क्या जोड़ना पड़ेगा?
(छात्र) आपको उद्धरण चिह्न जोड़ने होंगे।
हाँ, मुझे उद्धरण चिह्न चाहिए, बस यह साफ़ करने के लिए कि ये अलग-अलग ख़ास शब्द नहीं हैं। यह पूरा एक वाक्यांश है जो मैं उपयोगकर्ता को दिखाना चाहता हूँ।
इसलिए मैं सचमुच सब कुछ के चारों ओर दोहरे उद्धरण चिह्न लगाऊँगा।
नाम के बाद एक स्पेस क्यों
और यह बस दिखावट की बात है। इस मामले में मैं कर्सर को अगली पंक्ति में ले जाने की ज़हमत नहीं उठाना चाहता।
यानी मैं चाहता हूँ कि उपयोगकर्ता सवाल देखे, और कर्सर वहीं झपकता रहे और उनके जवाब का इंतज़ार करे।
लेकिन मैं नहीं चाहता कि कर्सर सवालिया चिह्न के बिल्कुल बगल में हो। इसलिए मैं जान-बूझकर वहाँ एक अकेली ख़ाली जगह (स्पेस) छोड़ रहा हूँ, ताकि उसे थोड़ा सरका दूँ और वह कम से कम मेरी नज़र में थोड़ा सुंदर दिखे।
जवाब को वेरिएबल में रखना
अब, हम अभी पूरे नहीं हुए हैं, क्योंकि हमें इस क़ीमत के साथ कुछ करना है।
getString फ़ंक्शन, जैसा हम जल्दी देखेंगे, उपयोगकर्ता से कहेगा कि वह मेरे नाम जैसा कुछ टाइप करे।
लेकिन मैं उसे कहाँ रखना चाहता हूँ?
MIT का जवाब यह है कि उसे "answer" नाम के वेरिएबल में रखो। और आप Scratch में उसका नाम बदल नहीं सकते। वह बस "answer" के रूप में परिभाषित है।
लेकिन C में मुझे कुछ ऐसा करना पड़ेगा।
अगर आप किसी फ़ंक्शन की रिटर्न वैल्यू को सँभालकर रखना चाहते हैं, तो आप सचमुच बराबर का चिह्न (=) इस्तेमाल करते हैं।
और उसके बाईं ओर आप उस वेरिएबल का नाम रखते हैं जिसमें आप उस रिटर्न वैल्यू को रखना चाहते हैं।
वेरिएबल का नाम और टाइप
गणित में हम अपने वेरिएबल के रूप में x, y और z इस्तेमाल करते हैं। फिर से, कोड में, जैसे Scratch में, आप अपने वेरिएबलों को कोई भी नाम दे सकते हैं।
परंपरा के अनुसार, वे आम तौर पर छोटे अक्षरों (लोअरकेस) में होने चाहिए। उनमें स्पेस नहीं होने चाहिए। कुछ फ़ाइलों के नामों जैसे सतर्क रहें।
लेकिन अब यह यहाँ सामूहिक रूप से जो हो रहा है, उसका एक काफ़ी अच्छा समकक्ष है।
लेकिन C थोड़ा ज़्यादा सटीक है। आप वेरिएबल को बस नाम नहीं दे सकते।
आपको C को, या असल में कंपाइलर को, बताना पड़ता है कि इस वेरिएबल में आप किस प्रकार (टाइप) की क़ीमत रखना चाहते हैं।
तो अगर वह टेक्स्ट की स्ट्रिंग है, तो आप "string" लिखते हैं। अगर वह कोई संख्या है, तो आप कुछ और लिखेंगे।
लेकिन अभी के लिए, फ़ंक्शन के नाम के अनुसार, यह एक स्ट्रिंग है। वह मुझे एक स्ट्रिंग देगा।
अब भी एक चीज़ छूटी है
अब, हम इस तुलना को पूरा करने के बहुत क़रीब हैं। एक ब्योरा छूटा हुआ है।
यहाँ कोड में अब भी क्या छूटा है?
(छात्र) जी, हमें अंत में सेमीकोलन से अपनी बात पूरी करनी होगी।
हाँ। तो अगर आप अभी से यह समझने लगे हैं, तो यही एक कारण है कि हम Scratch से शुरुआत करते हैं। आपको अंतर्ज्ञान बहुत जल्दी मिल जाता है।
और भले ही दाईं ओर की कोई भी चीज़ ख़ासतौर पर कठिन नहीं है, फिर भी इन सब बेवक़ूफ़ाना छोटे-छोटे ब्योरों को आपको समय के साथ अपने भीतर बिठाना पड़ता है।
इस मामले में C के लिए, लेकिन कई प्रोग्रामिंग भाषाओं में हम ऐसा ही ढाँचा देखेंगे।
लेकिन कोर्स के लक्ष्यों में यह भी शामिल है कि आपको दिखाया जाए कि आख़िरकार भाषाएँ कैसे विकसित होती रही हैं।
इसलिए एक चीज़ जो हम कुछ हफ़्तों बाद Python में देखेंगे, वह यह है कि इस सिंटैक्स का कुछ हिस्सा असल में ग़ायब हो जाता है।
क्योंकि समय के साथ इंसान इस तरह की पुरानी भाषाओं से चिढ़ते गए: "आख़िर मुझे बार-बार सेमीकोलन क्यों लगाना पड़ता है, जब साफ़ है कि मैं पंक्ति के अंत पर हूँ?"
तो हम Python जैसी भाषाओं में देखेंगे कि हम इनमें से कुछ ऐसी ही बातों से छुटकारा पा सकते हैं।
लेकिन अभी के लिए, बस यह याद रखने की बात है कि क्या कहाँ जाता है।
Scratch से C में बदला कोड चलाना
ठीक है, तो अब चलिए Scratch को C में बदलने वाले उसी विचार को लें और इस कोड के साथ सचमुच कुछ करें।
मैं VS Code पर वापस जाता हूँ।
मैं अपनी फ़ाइल का नाम वही रखूँगा। लेकिन आपको CS50 की वेबसाइट पर दिखेगा कि हम मेरे टाइप किए हर उदाहरण में संस्करण संख्याएँ (version numbers) जोड़ देंगे। इसलिए आप इन प्रोग्रामों की प्रगति देख सकेंगे, भले ही हम नाम नहीं बदल रहे।
और मैं यहाँ, उदाहरण के लिए hello.c में, इस बार यह करने जा रहा हूँ।
मैं पहले अकेला "hello world" हटाता हूँ।
मैं यहाँ ऊपर जाता हूँ और इस बार cs50.h शामिल करता हूँ। तो एक नहीं, बल्कि दो हेडर फ़ाइलें।
और फिर अपने घुँघराले कोष्ठकों के अंदर, इस तथाकथित "main" फ़ंक्शन के अंदर, जैसा हम जल्दी कहने लगेंगे, मैं यह करूँगा।
बिल्कुल वही कोड की पंक्ति जो पहले स्क्रीन पर थी: मैं एक स्ट्रिंग लूँगा, उपयोगकर्ता से पूछते हुए "What's your name?" प्रश्नचिह्न, स्पेस, उद्धरण चिह्न बंद, सेमीकोलन।
getString और printf का रिश्ता
और एक बात बीच में: यह स्क्रीन पर छापेगा, जैसा हम जल्दी देखेंगे: "What's your name?"
तो इसका मतलब है कि getString फ़ंक्शन असल में ख़ुद printf का इस्तेमाल करके वह संदेश छाप रहा है।
मुझे वह संदेश स्क्रीन पर दिखाने के लिए printf का इस्तेमाल करने की ज़रूरत नहीं है। क्योंकि मैंने CS50 के getString फ़ंक्शन का दस्तावेज़ीकरण पढ़ा है, और मैं बस जानता हूँ कि वह मेरे लिए उसी ख़ास लक्ष्य को पाने के लिए printf का इस्तेमाल कर रहा है।
एक सहज पर ग़लत कोशिश
अब मैं कुछ सहज, लेकिन पूरी तरह सही नहीं, करता हूँ।
अगर मैं उस जवाब को छापना चाहता हूँ ताकि संदेश "hello world" नहीं, बल्कि "hello David" या "hello Kelly" बने, तो मैं कहता हूँ: hello, कॉमा, answer, backslash n (कर्सर को पहले की तरह नीचे ले जाने के लिए), सेमीकोलन।
तो यह पूरी तरह सही नहीं है। और भले ही आपने पहले कभी प्रोग्रामिंग न की हो, आप शायद देख सकते हैं कि यह ग़लत दिशा में कहाँ जा रहा है।
मैं प्रोग्राम को दोबारा बनाता हूँ, क्योंकि मैंने सोर्स कोड बदला है और मुझे नया मशीन कोड चाहिए।
कुछ भी ग़लत नहीं दिखता, सिंटैक्स की दृष्टि से नहीं, बल्कि तर्क की दृष्टि से।
लेकिन अगर मैं अब dot slash hello करता हूँ और एंटर दबाता हूँ, तो आप देखेंगे कि मुझसे पूछा जा रहा है: "What's your name?"
तो मैं "David" टाइप करता हूँ और फिर एंटर दबाता हूँ।
लेकिन जब मैं यह करूँगा, अगर आप जानते हैं कि यह कहाँ जा रहा है, तो मुझे उसके बजाय क्या दिखेगा? "hello answer"।
और कंप्यूटर बस वही कर रहा है जो मैंने उसे सचमुच करने को कहा था। मैंने उद्धरण चिह्नों में कहा था: "hello answer" छापो।
लेकिन ज़ाहिर है, वह वह लक्ष्य नहीं है जो मेरे मन में है।
तो मैं असल में इसका हल कैसे निकालूँ?
अच्छा, मुझे असल में इस चीज़ के बराबर कुछ पाना है, जो हमने Scratch में ब्लॉकों को एक के ऊपर एक रखकर, या कहें कि एक को दूसरे के भीतर रखकर (नेस्ट करके), किया था।
"hello" और नाम को जोड़ना: प्लेसहोल्डर %s
मुझे असल में "hello, कॉमा, स्पेस" और उस answer को आपस में जोड़ना है।
और पता चलता है कि C में आप यह बिल्कुल इस तरह नहीं कर सकते। यहाँ "join" फ़ंक्शन जैसा कोई समकक्ष नहीं है, कम से कम वह जो हम आज देखेंगे।
इसलिए हमें इसे थोड़े अलग ढंग से करना पड़ेगा।
लेकिन हम यह कर सकते हैं, शायद कंप्यूटर से यह कहकर कि: "ठीक है, पहले 'hello, कॉमा, स्पेस' छापो।"
और फिर शायद हम उसे एक "प्लेसहोल्डर" (जगह रोकने वाला निशान) दे सकते हैं, ताकि जब हमें नाम पता चल जाए तो उसे वहाँ बिठा दिया जाए।
क्योंकि जब मैं अपना कोड लिख रहा होता हूँ, तो मुझे बिल्कुल पता नहीं होता कि यह खेल कौन खेलेगा: मैं, या Kelly, या कोई और।
तो क्यों न हम एक ख़ास सिंटैक्स इस्तेमाल करें, यह बताने के लिए कि मैं उस व्यक्ति का नाम असल में कहाँ चाहता हूँ?
मैं प्रस्ताव रखता हूँ कि अब हम यह करें।
"hello, कॉमा, answer" को उद्धरण चिह्नों में छापने के बजाय, चलिए कुछ छापना शुरू करते हैं। मेरे कोष्ठक तैयार हैं, और इस बार मैंने सेमीकोलन भी पहले ही लगा दिया है।
मैं अब किसी तरह कहना चाहता हूँ: "hello, कॉमा, प्लेसहोल्डर"।
और यह आप सिर्फ़ तभी जान सकते हैं जब किसी ने आपको बताया हो या इंटरनेट पर कोई संदर्भ देखा हो।
Percent S (%s) उस स्ट्रिंग का प्लेसहोल्डर है जो आपको कोड लिखते समय पता नहीं होती। लेकिन जब कोई और उस कोड को चलाएगा, तो वह उनके इनपुट से भर दिया जाएगा और उसकी जगह बदल दिया जाएगा।
तो "hello, कॉमा, percent S" वह सबसे क़रीबी चीज़ है जो हम इसके लिए पा सकते हैं।
printf को दो इनपुट देना
फिर भी मुझे कुछ और सिंटैक्स चाहिए।
मुझे अब भी बाईं और दाईं ओर वे उद्धरण चिह्न चाहिए।
बस दिखावट अच्छी रखने के लिए, मैं अंत में वहाँ backslash n लगा दूँगा ताकि कर्सर नीचे चला जाए।
लेकिन अब मैंने अपने कोष्ठकों में एक और चीज़ के लिए जगह छोड़ दी है। और आप शायद अंदाज़ा लगा सकते हैं कि मैं किस ओर जा रहा हूँ।
फिर से, भले ही आपने पहले कभी प्रोग्रामिंग न की हो, यह printf से कह रहा है: "H-E-L-L-O, कॉमा, स्पेस, कुछ" छापो।
तो मुझे इन कोष्ठकों में दूसरे इनपुट के रूप में शायद क्या देना चाहिए, ताकि printf को पता चले कि वह "कुछ" क्या है?
(छात्र) वेरिएबल का नाम।
हाँ। यानी वह वेरिएबल जिसमें मेरे पास उपयोगकर्ता का नाम है। और असल में परंपरा यह है कि उद्धरण चिह्नों के बाद एक कॉमा लगाएँ। फिर उस वेरिएबल का नाम लिखें जिसमें वह क़ीमत है, जिसे उस प्लेसहोल्डर की जगह रखा जाना है।
दो तरह के कॉमा
अब ध्यान दीजिए कि यहाँ सिंटैक्स और व्याकरण का एक टकराव है।
उद्धरण चिह्नों के भीतर का कॉमा बस अंग्रेज़ी की बात है: "Hello, फलाँ-फलाँ।"
उद्धरण चिह्नों के बाहर का कॉमा C के लिए मायने रखता है। क्योंकि वह तय करता है कि बाईं ओर वाला पहला इनपुट, यानी आर्ग्युमेंट, कौन-सा है और अब दूसरा कौन-सा है।
और हमने C में यह पहले नहीं देखा है। अब तक हम सिर्फ़ एक इनपुट दे रहे थे। लेकिन आप दो, तीन या चार भी दे सकते हैं।
यह पूरी तरह इस पर निर्भर करता है कि फ़ंक्शन को किस चीज़ की उम्मीद करने के लिए बनाया गया है।
सब कुछ मिलाकर चलाना
तो अब मैं इन सब को जोड़ता हूँ।
मैं VS Code पर वापस जाता हूँ।
पहले हम सचमुच "answer" छाप रहे थे, लेकिन मैं "answer" को "percent s" में बदल सकता हूँ।
मैं अपना कर्सर उन उद्धरण चिह्नों के बाहर ले जा सकता हूँ, कॉमा लगाकर "answer" लिख सकता हूँ, क्योंकि यही वह नाम है जो मैंने उस वेरिएबल को दिया था।
मैं वापस अपनी टर्मिनल विंडो में जा सकता हूँ और अव्यवस्था कम करने के लिए उसे क्लियर कर सकता हूँ।
मैं एक बार फिर make hello करता हूँ।
लगता है काम कर रहा है। dot slash hello, एंटर। "david"।
और अब "hello, कॉमा, David" छप गया है।
सवाल-जवाब: हेडर फ़ाइलें कहाँ से आती हैं
ठीक है, इस सबके बारे में कोई भी सवाल?
(छात्र) मैं सोच रहा था कि हेडर फ़ाइल कहाँ से खिंचकर आती है?
अच्छा सवाल है। ये हेडर फ़ाइलें कहाँ से खिंचकर आती हैं?
जो आप यहाँ देख रहे हैं वह एक ग्राफ़िकल यूज़र इंटरफ़ेस है जो कहीं क्लाउड में cs50.dev पर रखा गया है। यह वही URL है जिसका मैंने पिछले हफ़्ते ज़िक्र किया था। और हम इसे थोड़ी देर में सुलझाएँगे।
वह सॉफ़्टवेयर किसी कंप्यूटर पर चल रहा है। और उस कंप्यूटर में एक हार्ड ड्राइव या सॉलिड स्टेट ड्राइव है, यानी स्टोरेज के फ़ोल्डरों जैसी चीज़।
वे फ़ाइलें, cs50.h और standard io.h और कई और, उस सर्वर पर पहले से इंस्टॉल हैं जिससे मैं जुड़ा हुआ हूँ।
और वे एक मानक जगह पर रखी जाती हैं, ताकि कंपाइलर को ख़ास तौर पर पता रहे कि उन्हें कहाँ ढूँढना है।
और वे सब चीज़ें हमने आपके लिए पहले से कर रखी हैं।
सवाल-जवाब: बैकस्लैश n नई पंक्ति क्यों नहीं बनाता
(छात्र) backslash n नई पंक्ति क्यों नहीं बनाता?
Backslash n नई पंक्ति क्यों नहीं बनाता?
असल में वह बनाता है। यहाँ backslash n सचमुच छप रहा है, और उसका असर यह है कि वह डॉलर चिह्न को अगली पंक्ति में धकेल देता है।
वरना डॉलर चिह्न उस आख़िरी से ठीक पहले वाली पंक्ति पर ही बना रहता।
सवाल-जवाब: इस स्ट्रिंग में backslash n क्यों नहीं
और कोई सवाल?
(छात्र) इस स्ट्रिंग पर backslash n क्यों नहीं है?
अच्छा। यहाँ backslash n क्यों नहीं है?
अच्छा सवाल है। यह प्रोग्रामर, यानी मेरी, पसंद है। मैं बस वह वाक्य देखना चाहता था: "What's your name?" प्रश्नचिह्न।
और मैं चाहता था कि उपयोगकर्ता, यानी मैं, अपना नाम उसके तुरंत बाद ऐसे टाइप करे।
लेकिन मुझे ऐसा करना ज़रूरी नहीं था। मैं बस आपको फ़र्क़ दिखाना चाहता था।
सवाल-जवाब: शुरू की चार पंक्तियाँ
(छात्र) समझ गया। और एक बात, जो हम कर रहे हैं उसे दोहराने पर, क्या हमें हमेशा पहली चार पंक्तियाँ लिखनी चाहिए?
क्या आपको हमेशा पहली चार लिखनी चाहिए? अरे, ये वाली?
हाँ। आज के लिए मुझ पर भरोसा कीजिए: यह कीजिए, यह कीजिए, यह कीजिए, यह कीजिए।
और अगले हफ़्ते हम और अच्छी तरह समझेंगे कि वे पंक्तियाँ क्या करती हैं।
हालाँकि एक छोटी-सी शर्त: cs50.h सिर्फ़ तब शामिल कीजिए जब आप हमारे फ़ंक्शनों में से किसी का इस्तेमाल कर रहे हों। ज़ाहिर है, अगर आप बस कुछ छाप रहे हैं, जैसे पहले उदाहरण में, तो आपको cs50.h की ज़रूरत नहीं है।
सवाल-जवाब: दो इनपुट, दो उद्गम
और कोई सवाल?
(छात्र) मेरा दूसरा कॉमा पहले इनपुट और दूसरे इनपुट को अलग कर रहा है। मैं समझता हूँ कि दूसरा इनपुट वह है जो मैं उपयोगकर्ता के रूप में टाइप करता हूँ। लेकिन पहला इनपुट मुझे असल में इनपुट जैसा नहीं लगता, क्योंकि वह तो वह सवाल है जो आप पूछते हैं। क्या आप थोड़ा समझा सकते हैं कि जब आप दोनों को इनपुट कहते हैं तो क्या मतलब होता है?
सही बात है। तो सवाल का सार यह है: यहाँ दाईं ओर यह इनपुट असल में उपयोगकर्ता से मिलता है। लेकिन यह पहला इनपुट मेरी ओर से दिया जाता है। बस ऐसा ही है।
तो ये दोनों इनपुट हैं, क्योंकि ये दोनों फ़ंक्शन को इनपुट के रूप में दिए जा रहे हैं।
लेकिन इन इनपुटों का उद्गम पूरी तरह इस पर निर्भर है कि मैं क्या पाने की कोशिश कर रहा हूँ।
पहला मैं पहले से जानता हूँ। यानी मैं प्रोग्रामर हूँ, मुझे पता है कि मैं "hello, कॉमा, कोई" कहना चाहता था।
दूसरा इनपुट मुझे पहले से पता नहीं है। इसलिए मैं एक वेरिएबल इस्तेमाल कर रहा हूँ, जिसमें वह क़ीमत रखी जाएगी जो मुझे तब मिलेगी जब getString फ़ंक्शन बाद में इस्तेमाल होगा।
लेकिन दोनों इनपुट हैं, भले ही उनका इस्तेमाल अलग-अलग तरीक़ों से होता है।
अच्छा सवाल है। कोई और?
ऑपरेटिंग सिस्टम और Linux
ठीक है, अब जब यह हो गया, तो चलिए एक क़दम पीछे हटकर पहले पूछे गए उस सवाल पर आते हैं कि ये फ़ाइलें कहाँ हैं।
आइए देखें कि असल में हम यहाँ इस्तेमाल क्या कर रहे हैं।
तो पता चलता है कि भले ही आप में से ज़्यादातर लोग Mac OS या Windows इस्तेमाल कर रहे हैं, दुनिया में दूसरे ऑपरेटिंग सिस्टम भी हैं।
फ़ोन में iOS है। iPad में iPad OS है। Android उपकरणों में Android है, जो अपने-आप में एक अलग ऑपरेटिंग सिस्टम है।
दुनिया के ऑपरेटिंग सिस्टम वे सॉफ़्टवेयर हैं जो किसी उपकरण पर सबसे बुनियादी काम करते हैं: जैसे उसे चालू करना, बंद करना, प्रिंटर को कुछ भेजना, स्क्रीन पर कुछ दिखाना, खिड़कियों और आइकनों को सँभालना, और वह सारा रोज़मर्रा का सामान जिसका इस्तेमाल दूसरे लोगों के सॉफ़्टवेयर भी करते हैं।
प्रोग्रामिंग की दुनिया में, और क्लाउड के सर्वरों की दुनिया में, और पूरे इंटरनेट पर, एक बहुत लोकप्रिय ऑपरेटिंग सिस्टम है जिसका नाम "Linux" है।
और यह "Unix" नाम की एक चीज़ का वंशज है, जो काफ़ी समय से मौजूद है।
यही वह है जो कई प्रोग्रामर, बल्कि ज़्यादातर प्रोग्रामर, अपने माहौल के हिसाब से इस्तेमाल करते हैं।
इस हद तक कि Linux का प्रदर्शन बहुत ऊँचा है। जैसे आप इस तरह के ऑपरेटिंग सिस्टम वाले सर्वरों पर हज़ारों-लाखों उपयोगकर्ताओं को सँभाल सकते हैं।
उसमें ग्राफ़िकल यूज़र इंटरफ़ेस नहीं होने की प्रवृत्ति होती है, हालाँकि हो सकता है। इसका बस यह मतलब है कि वह ज़्यादा तेज़ी से चल सकता है, क्योंकि उसे ये सब ग्राफ़िक नहीं चाहिए जो असल में सिर्फ़ इंसानों की सुविधा के लिए हैं, वेब ब्राउज़रों और दूसरे उपकरणों के लिए ज़रूरी नहीं।
और Linux, जहाँ तक वह आम तौर पर या अक्सर कमांड लाइन इंटरफ़ेस के रूप में इस्तेमाल होता है, कमांडों का एक पूरा समूह लेकर आता है जिन्हें आप समय के साथ इस्तेमाल करना और देखना शुरू करेंगे।
कुछ ज़रूरी Linux कमांड
अब, मैं पहले ही कई कमांड इस्तेमाल कर चुका हूँ।
मैंने "code" इस्तेमाल किया, जो VS Code की चीज़ है।
मैंने "make" इस्तेमाल किया, जो आज के मक़सद के लिए हमारा कंपाइलर है। लेकिन वह एक छोटा-सा सफ़ेद झूठ है जिसे हम अगले हफ़्ते साफ़ करेंगे।
और फिर मैंने "dot slash hello" इस्तेमाल किया, जो असल में एक ऐसी कमांड है जिसे मैंने गढ़ा, जैसे ही मैंने hello नाम का प्रोग्राम बनाया।
लेकिन और भी कई कमांड हैं।
उदाहरण के लिए, अगर मैं अपने मौजूदा फ़ोल्डर की फ़ाइलों की सूची देखना चाहूँ, तो मैं "ls" टाइप करके एंटर दबा सकता हूँ, छोटे में।
अगर मैं नया फ़ोल्डर बनाना चाहूँ, जिसे "डायरेक्टरी" भी कहते हैं, तो मैं डायरेक्टरी बनाने के लिए "mkdir" इस्तेमाल कर सकता हूँ।
अगर मैं कोई डायरेक्टरी हटाना चाहूँ, तो मैं "rm directory" इस्तेमाल कर सकता हूँ।
अगर मैं कोई फ़ाइल हटाना चाहूँ, तो मैं "rm" इस्तेमाल कर सकता हूँ।
अगर मैं किसी फ़ाइल का नाम बदलना चाहूँ, तो मैं "mv" इस्तेमाल कर सकता हूँ, यानी move (हटाना/सरकाना)।
अगर मैं किसी फ़ाइल की प्रति बनाना चाहूँ, तो "cp"। अगर मैं डायरेक्टरी बदलना चाहूँ, यानी किसी फ़ोल्डर में जाना चाहूँ, तो मैं "cd" इस्तेमाल कर सकता हूँ।
अब, इन्हें याद करने में अभ्यास में बस थोड़ा-सा समय लगता है।
और ये सब बहुत संक्षिप्त हैं, क्योंकि कमांड लाइन का पूरा मक़सद ही यह है कि लोग चीज़ों में जल्दी घूम-फिर सकें।
फ़ोल्डर बनाने और फ़ाइल हिलाने का अभ्यास
तो उदाहरण के लिए, भले ही यह थोड़ा बवंडर जैसा होगा, मैं वापस VS Code में जाता हूँ।
और मैं प्रस्ताव रखता हूँ कि हम इनमें से बस कुछ कमांडों के साथ खेलें, ताकि आपने मुझे यह करते देखा हो।
लेकिन आम तौर पर, CS50 के प्रॉब्लम सेट में हम आपको क़दम-दर-क़दम बताएँगे कि कौन-सी कमांड टाइप करनी है, ताकि आप वही नतीजे पा सकें।
और फिर सत्र में आगे चलकर हम आपको बार-बार पांडित्यपूर्ण ढंग से यह याद दिलाना बंद कर देंगे कि यह और वह कैसे करना है, क्योंकि आख़िरकार यह आपके लिए ज़्यादा स्वाभाविक हो जाना चाहिए।
लेकिन उदाहरण के लिए, मैं यह करता हूँ। मैं बाईं ओर अपना फ़ाइल एक्सप्लोरर दोबारा खोलता हूँ।
आपका थोड़ा अलग दिखेगा। आपके पास आपकी अपनी अनोखी पहचान संख्या (यूनिक ID) अलग होगी। लेकिन आम तौर पर आपको वे सभी फ़ाइलें और/या फ़ोल्डर दिखेंगे जो आपने अब तक बनाए हैं।
आज मैंने पहली चीज़ जो बनाई, उसका नाम hello.c था।
और फिर make का इस्तेमाल करके मैंने दूसरी फ़ाइल बनाई, जिसका मैंने दावा किया कि उसका नाम hello है।
तो "dot slash hello" इसलिए काम करता है क्योंकि सचमुच मेरे मौजूदा फ़ोल्डर में hello नाम का एक प्रोग्राम है। इसलिए ही डॉट (.) है। उसे तब बनाया गया था जब मैंने अपने सोर्स कोड को मशीन कोड में कंपाइल किया।
फ़ोल्डरों में व्यवस्थित करना
अब मान लीजिए, चर्चा की ख़ातिर, कि यह जल्दी ही गड़बड़ हो जाएगा। क्योंकि कक्षा और प्रॉब्लम सेटों के लिए हम जितने ज़्यादा प्रोग्राम बनाएँगे, इस एक मुख्य फ़ोल्डर के अंदर आपके पास फ़ाइलों की एक बेतरतीब खिचड़ी बन जाएगी।
तो चलिए उपफ़ोल्डर बनाते हैं, जैसा आप अपने Mac या PC या Google Drive वग़ैरह पर करने को प्रेरित हो सकते हैं।
हम यह कई तरीक़ों से कर सकते हैं। मैं अपने फ़ाइल एक्सप्लोरर पर राइट क्लिक या कंट्रोल क्लिक कर सकता हूँ। और मुझे कुछ जाना-पहचाना संदर्भ मेन्यू (contextual menu) दिखेगा।
और मैं सचमुच "new folder" चुन सकता हूँ, या चीज़ों के नाम बदल सकता हूँ, या उन्हें खींचकर-छोड़कर इधर-उधर कर सकता हूँ।
लेकिन आज के लिए, चलिए CLI, यानी कमांड लाइन इंटरफ़ेस, पर ज़्यादा ध्यान दें, और फिर से इस तरह की कमांडों पर।
rm: बनी हुई प्रोग्राम फ़ाइल हटाना
तो मैं वापस VS Code में जाता हूँ और प्रस्ताव रखता हूँ कि हम कुछ चीज़ें करें, बस एक दौरे की तरह।
पहले, मैं मशीन कोड को हटा देता हूँ। इस उदाहरण से मेरा काम हो चुका है। मैं इन टुकड़ों को बेवजह रखना नहीं चाहता।
मैं "hello" को हटाने जा रहा हूँ, "hello.c" को नहीं, बल्कि "hello" को, यानी कंपाइल किए गए प्रोग्राम को।
जब मैं यह टाइप करूँगा, तो मुझे चेतावनी मिलेगी: "hello नाम की सामान्य फ़ाइल (regular file) हटाएँ?", इसका जो भी मतलब हो।
यहाँ मुझसे हाँ-या-नहीं का जवाब माँगा जा रहा है। इसके लिए "y" काफ़ी है।
तो मैं "y" दबाता हूँ, एंटर दबाता हूँ, और देखिए ऊपर बाईं ओर क्या होता है, जैसे ही मैं अपनी टर्मिनल विंडो और इस कमांड का इस्तेमाल करके उस फ़ाइल को हटाता हूँ।
वह ग़ायब हो जाती है।
मैं उस पर राइट क्लिक या कंट्रोल क्लिक कर सकता था, लेकिन यह कमांड लाइन इंटरफ़ेस वही चीज़ हासिल कर लेता है।
mkdir: नया फ़ोल्डर बनाना
अब मान लीजिए कि प्रॉब्लम सेट एक और आगे के प्रॉब्लम सेटों के लिए, मैं अपना लिखा हर प्रोग्राम उसके अपने फ़ोल्डर में रखना चाहता हूँ। बस ख़ुद को व्यवस्थित रखने के लिए, ख़ासकर जैसे-जैसे सत्र आगे बढ़ता है।
तो मैं "hello" नाम का एक नया फ़ोल्डर बनाता हूँ।
यानी मैं hello नाम का प्रोग्राम नहीं बनाना चाहता। मैं hello नाम का एक फ़ोल्डर बनाना चाहता हूँ।
तो एक तरीक़ा, इस चीट शीट के अनुसार, यह है कि एक डायरेक्टरी बनाई जाए, जिसका बस मतलब फ़ोल्डर है।
तो "mkdir hello", एंटर। और आप ऊपर बाईं ओर देखेंगे कि अब मेरे पास सचमुच एक फ़ोल्डर है। और उसके बगल में एक साफ़-साफ़ फ़ोल्डर का आइकन भी है।
mv: फ़ाइल को फ़ोल्डर में सरकाना
अब, मैं शॉर्टकट ले सकता था। मैं hello.c पर क्लिक करके खींच सकता था और उसे hello में छोड़ सकता था।
लेकिन फिर से, चलिए कमांड लाइन इंटरफ़ेस पर ही टिके रहें।
मैं अब आगे बढ़कर hello.c को hello में "move", यानी छोटे में "mv", करता हूँ।
तो यह पहली कमांड है जिसमें मैं कमांड के बाद एक शब्द नहीं दे रहा, जैसे "code hello.c" या "make hello" में।
अब मैं कमांड के बाद दो शब्द टाइप कर रहा हूँ। क्योंकि move कमांड इस तरह बनी है कि वह पहले शब्द के रूप में उद्गम (origin, यानी कहाँ से) की और दूसरे शब्द के रूप में गंतव्य (destination, यानी कहाँ को) की उम्मीद करती है।
इसलिए, अगर मैं hello.c का नाम बदलना चाहूँ, माफ़ कीजिए, अगर मैं hello.c को hello फ़ोल्डर में सरकाना चाहूँ, तो मुझे ऐसे टाइप करना चाहिए।
अब, वैसे, आप गंतव्य के अंत में एक आख़िरी स्लैश (forward slash, यानी तिरछी रेखा) भी लगा सकते हैं। इससे साफ़ हो जाता है कि आप इसे एक फ़ोल्डर में रखना चाहते हैं, और hello.c का नाम सिर्फ़ "hello" नहीं करना चाहते।
लेकिन क्योंकि hello फ़ोल्डर पहले से मौजूद है, Linux जानता है कि वह क्या कर रहा है। वह बस यह मान लेगा कि जब आप ऐसा करते हैं... देखिए ऊपर बाईं ओर क्या होता है।
hello.c ग़ायब हो गई लगती है। लेकिन अगर मैं इस छोटे त्रिकोण पर क्लिक करूँ, तो अहा, वह रही। वह अब उस फ़ोल्डर के अंदर है।
ls: सूची देखना
लेकिन अब मैंने अपने लिए एक तरह की उलझन खड़ी कर ली है।
मैं अपनी टर्मिनल विंडो साफ़ करता हूँ, और अब "ls" टाइप करता हूँ।
और जब मैं सूची (list) के लिए "ls" टाइप करता हूँ, तो आपको सिर्फ़ "hello" नाम का एक फ़ोल्डर दिखेगा। उसे आपकी आँखों को दिखाने के लिए रंग-कोडित किया गया है, और अंत में एक स्लैश है ताकि साफ़ हो जाए कि वह फ़ोल्डर है।
वह सब आपके लिए अपने-आप Linux, यानी ऑपरेटिंग सिस्टम, कर देता है।
cd: किसी फ़ोल्डर के अंदर जाना
लेकिन एक मिनट रुकिए, मेरा hello प्रोग्राम कहाँ चला गया?
यानी hello.c कहाँ है?
वह उसी फ़ोल्डर में है। इसलिए मुझे उस फ़ोल्डर या डायरेक्टरी में जाना पड़ेगा।
और यहाँ, चीट शीट के अनुसार, डायरेक्टरी बदलने के लिए हमारे पास "cd" है।
तो मैं "cd space hello" कर सकता हूँ, स्लैश के साथ या उसके बिना, और एंटर दबा सकता हूँ।
और अब आपको यह दिखेगा। मानता हूँ कि यह थोड़ा रहस्यमय है। मेरा प्रॉम्प्ट अब बदल गया है। वह अब भी डॉलर चिह्न ही है, लेकिन उससे पहले एक स्थायी याद-दिहानी है कि मैं किस फ़ोल्डर में हूँ।
हमने इसे परंपरा के रूप में अपनाया है। कई सिस्टम यही करते हैं, हालाँकि उनका रूप थोड़ा अलग हो सकता है।
यह बस इसलिए है कि आपको याद रहे कि आप आख़िर कहाँ हैं, और आपको ऑपरेटिंग सिस्टम से यह पूछने के लिए कोई और कमांड टाइप न करनी पड़े कि आप किस फ़ोल्डर में हैं।
फ़ोल्डर के अंदर ls, make और rm
तो अब जब मैं यहाँ हूँ, अगर मैं "ls" टाइप करके एंटर दबाऊँ, तो मुझे क्या दिखना चाहिए?
बस hello.c, क्योंकि उस फ़ोल्डर में वही एक चीज़ है।
तो अब चलिए शायद एक और काम करते हैं। इस फ़ोल्डर के अंदर "make hello" करते हैं।
यह ठीक है। और देखिए ऊपर बाईं ओर अभी क्या हुआ। अब मेरे पास दोनों फ़ाइलें वापस आ गई हैं।
ठीक है, मान लीजिए मैं एक से छुटकारा पाना चाहता हूँ। तो मैं फिर से "rm hello" कर सकता हूँ। मैं हटाने की पुष्टि के लिए "y" यानी हाँ टाइप कर सकता हूँ। और अब मैं वहीं लौट आया हूँ जहाँ अभी था।
mv से नाम बदलना
अब मान लीजिए मैं और चीज़ें करना चाहता हूँ। मान लीजिए मुझे hello.c के इस संस्करण पर कोई ख़ास गर्व नहीं है। मैं इसे रखना चाहता हूँ, पर इसका नाम बदलना चाहता हूँ।
तो मैं कह सकता हूँ: "mv hello.c old.c" कैसा रहेगा?
मैं बस फ़ाइल का नाम बदलना चाहता हूँ।
तो "mv" का इस्तेमाल सिर्फ़ किसी फ़ाइल को एक जगह से दूसरी जगह भौतिक रूप से हिलाने के लिए नहीं होता। अगर आप इसे दो फ़ाइलों के नामों पर इस्तेमाल करें, तो यह बस आपके लिए फ़ाइल का नाम बदल देगा।
इसलिए ऐसी कोई अलग "rename" कमांड नहीं है जिसका आपको इस्तेमाल करना पड़े।
लेकिन पता है क्या? नहीं, मुझे इसका अफ़सोस है। यह प्रोग्राम ठीक था। चलिए इसका नाम वापस बदल देते हैं।
तो old.c को वापस hello.c में "move" करते हैं, और ऊपर बाईं ओर देखिए। वह बस फ़ाइल का नाम फिर से बदल देता है।
cp से बैकअप बनाना
फिर भी मैं एक बैकअप बना लेता हूँ।
तो मैं "cp hello.c" से उसकी प्रति backup.c नाम की फ़ाइल में बना लेता हूँ। बस अगर मैंने इसे बिगाड़ दिया, तो मैं चाहता हूँ कि एक फ़ालतू प्रति मेरे पास रहे।
अब आप ऊपर बाईं ओर देखते हैं कि मेरे पास दोनों फ़ाइलें हैं।
अगर मैं अब "ls" टाइप करूँ, तो आपको दोनों फ़ाइलें दिखेंगी।
तो GUI में जो हो रहा है, वही चीज़ बिल्कुल CLI में भी हो रही है।
लेकिन पता है क्या? यह बस प्रदर्शन के लिए था। मुझे इसमें से किसी की ज़रूरत नहीं है।
तो मैं बैकअप हटा देता हूँ। "y" यानी हाँ बोल देता हूँ।
.. का मतलब: ऊपर वाला फ़ोल्डर
मैं hello.c को इस फ़ोल्डर से बाहर ले जाता हूँ। मैं बस उसे खींचकर-छोड़ भी सकता था।
लेकिन मैं hello.c को, कहें तो, "पैरेंट फ़ोल्डर" (ऊपर वाले फ़ोल्डर) में कैसे ले जाऊँ? मैं इसे इस फ़ोल्डर से बाहर ले जाना चाहता हूँ।
तो यह आप सिर्फ़ तभी जान सकते हैं जब आपको बताया गया हो कि "dot dot" (..) एक ख़ास संकेतन है।
इसका मतलब है "पैरेंट फ़ोल्डर", यानी पदानुक्रम (हाइरार्की) में एक क़दम ऊपर वापस जाना।
और अब, अगर यह साफ़ न हो, तो एक अकेला डॉट (.), जो हम पहले देख चुके हैं, इसी फ़ोल्डर को दर्शाता है। दो डॉट का मतलब है एक क़दम ऊपर।
तीन डॉट या चार डॉट जैसा कुछ नहीं होता। उसके लिए आपको अलग सिंटैक्स इस्तेमाल करना पड़ता है। लेकिन उस पर फिर कभी।
तो देखिए क्या होता है। जब मैं hello.c को पैरेंट डायरेक्टरी में ऊपर "move" करता हूँ, तो ऊपर बाईं ओर देखिए, इंडेंटेशन (खिसकाव) बदल गया है, क्योंकि अब वह उसी फ़ोल्डर के अंदर नहीं है।
cd अकेला: सीधे घर लौटना
और अब मैं यह करता हूँ। मैं "cd dot dot" करके अपने मुख्य फ़ोल्डर में लौट सकता था, यानी इस फ़ोल्डर से बाहर निकलने के लिए।
लेकिन जब आप संदेह में हों, या अगर आप कभी किसी उलझे हुए झमेले में फँस जाएँ, तो बस अकेला "cd" टाइप करके एंटर दबा दीजिए। आपको जादू से आपके डिफ़ॉल्ट फ़ोल्डर, यानी एक "होम डायरेक्टरी" में पहुँचा दिया जाएगा। हालाँकि वह भी थोड़ा सफ़ेद झूठ ही है।
तो यह आपको हमेशा वहीं ले जाएगा जहाँ से आप cs50.dev, यानी VS Code, में लॉग इन करते समय शुरू करते हैं।
और अब मैं वह फ़ोल्डर देख सकता हूँ, जो ख़ाली है, और वह फ़ाइल।
तो मैं एक आख़िरी कमांड चलाता हूँ। या "rmdir hello", ताकि सारा किया हुआ काम पूरी तरह पलट जाए, और हम अब वहीं लौट आएँ जहाँ से कहानी शुरू हुई थी।
लेकिन यहाँ बात बस यह दिखाने की है कि इन बुनियादी कमांडों से आप वह सब कुछ कर सकते हैं जिसे आप सालों से Mac और PC पर माउस से करते आए हैं और जिसे आप सहज मान चुके हैं।
सवाल-जवाब: फ़ोल्डर में कई फ़ाइलें हों तो
इनमें से किसी के बारे में सवाल? Linux कमांडों के बारे में?
(छात्र) अगर आपके पास किसी फ़ोल्डर में पाँच अलग-अलग फ़ाइलें हों, तो आप कैसे चुन सकते हैं कि कौन-सी खोलनी है?
बहुत अच्छा सवाल है। अगर फ़ोल्डर में पाँच अलग-अलग फ़ाइलें हों, तो आप कैसे चुनें कि कौन-सी खोलनी है?
आप निश्चित रूप से "code", स्पेस, और जिस फ़ाइल को खोलना है उसका नाम लिख सकते हैं।
या हम दूसरी तरकीबें देखेंगे। जैसे आप तारांकन (asterisk) या स्टार का इस्तेमाल एक तथाकथित "वाइल्ड कार्ड" के रूप में कर सकते हैं, और कह सकते हैं कि इस फ़ोल्डर की हर चीज़ खोलो।
और आप इससे भी ज़्यादा सटीक पैटर्न इस्तेमाल कर सकते हैं।
तो समय के साथ, जब मेरे पास ज़्यादा फ़ाइलें होंगी, तब मैं इस तरह की तरकीबें भी कर पाऊँगा।
सवाल-जवाब: फ़ोल्डर के अंदर hello
(छात्र का सवाल ट्रांसक्रिप्ट में अस्पष्ट है; वह कुछ इस तरह है: "मुझे नहीं पता कि मैं यह बोल सकता हूँ या नहीं, लेकिन मैं सब कुछ-वाली चीज़ बना सकता हूँ और फिर लोडिंग से वापस आ सकता हूँ। जब आप कोई फ़ाइल पढ़ते हैं, तो मैं उसे वापस लो तक खींच लूँगा, क्योंकि वह वैसे ही लिखी है और यह सारा कोड भी वैसे ही लिखा है। तो आपने वह लो कैसे बनाया?")
ज़रूर।
तो एक काम जो मैंने कुछ देर पहले अपने VS Code में किया, वह यह था कि जब मैं hello फ़ोल्डर के अंदर था, जिसमें मैंने hello.c रखी थी, तो बस चर्चा की ख़ातिर मैंने "make hello" चलाकर उसे दोबारा कंपाइल किया।
और यह उदाहरण जान-बूझकर थोड़ा उलझाने वाला है, क्योंकि मेरे पास hello नाम के फ़ोल्डर के अंदर hello.c नाम की फ़ाइल है।
लेकिन क्योंकि मैंने hello.c को कंपाइल किया, इसलिए मैंने hello नाम का एक प्रोग्राम भी बना दिया।
लेकिन वह प्रोग्राम hello, hello नाम के फ़ोल्डर के अंदर था। इसका बस यही मतलब है कि आप यह पूरी तरह कर सकते हैं।
आप एक ही जगह पर एक फ़ाइल और एक फ़ोल्डर, एक ही नाम से, नहीं रख सकते, क्योंकि वे टकरा जाएँगे। आप Mac या PC पर भी ऐसा नहीं कर सकते। आपके पास अनोखे नाम होने चाहिए।
लेकिन आप निश्चित रूप से किसी चीज़ को दूसरे फ़ोल्डर के अंदर बिना किसी टकराव के रख सकते हैं।
अच्छा सवाल है।
कंडीशनल: दोराहे वाला फ़ैसला
ठीक है।
तो आइए कुछ और निर्माण-खंड और कुछ और चीज़ें जोड़ें जो हम कर सकते हैं।
इन Linux कमांडों के अलावा, जिन्हें हम अब सहज मानना शुरू कर देंगे, प्रोग्रामिंग भाषाओं की कई और ख़ूबियाँ हैं जो हमने Scratch में देखी थीं।
आइए अब उन्हें C में अनुवाद करें।
तो "कंडीशनल" (conditionals), जो मुहावरे वाले दोराहे जैसे हैं। ये आपको किसी सवाल के जवाब के आधार पर यह या वह या कुछ और करने देते हैं। ऐसे सवाल को "बूलियन एक्सप्रेशन" (Boolean expression) कहते हैं।
C में if
यहाँ, उदाहरण के लिए, Scratch में हम इसे इस तरह कह सकते हैं: अगर वेरिएबल x वेरिएबल y से छोटा है, तो हम कहेंगे "x, y से छोटा है"।
और संदर्भ से बाहर, मैंने इसे स्लाइड में शामिल नहीं किया, पर माना जा सकता है कि हमने x और y बनाए हैं और उन्हें किसी तरह क़ीमतें दी हैं, जो भी हों।
लेकिन यह बस अब प्रोग्राम का कंडीशनल हिस्सा है।
C में आप यही चीज़ ऐसे करेंगे: आप "if" कहेंगे, फिर एक स्पेस, फिर कोष्ठक। इन कोष्ठकों का फ़ंक्शनों से कोई लेना-देना नहीं है।
"if" कोई फ़ंक्शन नहीं है। यह C की एक ख़ूबी है जो कंडीशनल लागू करती है, ठीक वैसे ही जैसे यह नारंगी ब्लॉक Scratch की एक ख़ूबी है।
कोष्ठकों के अंदर आप वही बूलियन एक्सप्रेशन रखते हैं।
तो यहाँ भी, संदर्भ से बाहर, अगर मैंने ऊपर वेरिएबल x और y परिभाषित किए हैं, तो मैं निश्चित रूप से उन्हें इस कंडीशनल में इस्तेमाल कर सकता हूँ।
और मैं यह सवाल पूछने के लिए "छोटा है" का ऑपरेटर (<) इस्तेमाल कर सकता हूँ, ठीक वैसे ही जैसे गणित की कक्षा में।
और जवाब, भले ही वह "छोटा है" का चिह्न है, सोचें तो असल में सही (true) या ग़लत (false) होगा। हाँ या नहीं। यह एक बूलियन एक्सप्रेशन है। या तो वह छोटा है, या नहीं है।
घुँघराले कोष्ठकों का मतलब
ठीक है, घुँघराले कोष्ठकों के अंदर, जो यहाँ ज़रूरी हैं, मैं सचमुच अपने पुराने दोस्त printf को रखूँगा। और यहाँ कुछ दिलचस्प नहीं है, सिवाय नए वाक्यांश "x is less than y" के, backslash n, सेमीकोलन और कोष्ठकों के साथ।
लेकिन यह जान-बूझकर है।
ठीक जैसे Scratch में "say" थोड़ा खिसका हुआ है और "if" वाले नारंगी पहेली-टुकड़े से गले लगा हुआ है, वैसे ही क्या ये घुँघराले कोष्ठक भी वही मतलब रखने के लिए हैं? ये कोड की इन पंक्तियों को एक तरह से गले लगा रहे हैं।
एक बात बीच में: C में ये हमेशा ज़रूरी नहीं होते। अगर आपके पास कोड की सिर्फ़ एक पंक्ति है, तो आप तकनीकी रूप से इन्हें छोड़ सकते हैं।
लेकिन C में, और ख़ासकर CS50 में, हम आम तौर पर एक ख़ास शैली का प्रचार करेंगे, जैसे असली दुनिया की कोई भी कंपनी करती है। इसका मक़सद यह है कि जो प्रोग्रामर कोड पर मिलकर काम करें, वे सब ऐसा कोड लिखें जो एक जैसा दिखे। ताकि वह अव्यवस्था में न बदल जाए, जो तब होती है जब हर किसी की अपनी परंपरा हो।
तो यह एक ऐसी परंपरा है जिसका आपको सचमुच पालन करना चाहिए।
और फिर मैंने चार स्पेस का इंडेंट इसलिए लगाया है कि तार्किक रूप से साफ़ हो जाए कि कोड की यह पंक्ति तभी चलती है जब इस सवाल का जवाब सही हो। या "हाँ" हो।
if-else: दो तरफ़ा दोराहा
इस बीच, Scratch में अगर हमारे पास "if-else" कंडीशन होती, यानी दोराहे का एक दो-तरफ़ा रूप: अगर x, y से छोटा है तो यही कहो, वरना कहो "x, y से छोटा नहीं है"।
मैं इसे C में कैसे कर सकता हूँ?
तो: "if x less than y", और फिर "else" कुछ और।
और उन घुँघराले कोष्ठकों के बीच क्या जाता है? बस दो अलग-अलग printf: "x is less than y" या "x is not less than y"।
यहाँ एकमात्र नई चीज़ यह है कि हमने "else" और घुँघराले कोष्ठकों की एक और जोड़ी जोड़ दी है। ठीक वैसे ही जैसे वहाँ दो नारंगी आकृतियाँ उन दो बैंगनी पहेली-टुकड़ों को गले लगा रही हैं।
तीन-तरफ़ा फ़ैसला: else if
थोड़ा और जटिल कुछ कैसा रहेगा?
और यह लगता है कि तेज़ी से बढ़ रहा है, लेकिन यह बस इसलिए है कि Scratch के पहेली-टुकड़े बहुत बड़े हैं।
अगर x, y से छोटा है, तो कहो "x, y से छोटा है"। वरना अगर x, y से बड़ा है, तो कहो "x, y से बड़ा है"। वरना अगर x, y के बराबर है, तो कहो "x, y के बराबर है"।
हम इसे C में कैसे कर सकते हैं?
लगभग वही विचार। "if x less than y", "else if x greater than y", "else if x equals y"।
= और == का फ़र्क़
तो इससे पहले कि हम बताएँ कि घुँघराले कोष्ठकों में क्या है, यह टाइपो नहीं है।
मैंने शायद यह क्यों किया है, भले ही आपने पहले कभी C इस्तेमाल न किया हो?
(छात्र) क्योंकि बराबर का चिह्न वेरिएबल का चिह्न है।
बिल्कुल सही। वह अकेला बराबर का चिह्न (=), जिसे हम पहले ही इस्तेमाल कर चुके हैं, जब getString से मिली क़ीमत को "answer" जैसे वेरिएबल में रखा था, तकनीकी रूप से "असाइनमेंट ऑपरेटर" (assignment operator) है।
तो इंसानों ने दशकों पहले तय किया कि जब उनके सामने ऐसी स्थिति आए जहाँ वे किसी रिटर्न वैल्यू को दाईं ओर से बाईं ओर वेरिएबल में कॉपी करना चाहते हों, तो बराबर का चिह्न इस्तेमाल करना दृश्य रूप से समझदारी भरा लगा। क्योंकि आख़िरकार आप चाहते हैं कि वे दोनों चीज़ें बराबर हों, भले ही उस मामले में आप कोड को दाएँ से बाएँ पढ़ते हों।
मैं बस कल्पना कर सकता हूँ कि किसी मोड़ पर वही लोग कमरे में थे, और वे कंडीशनलों का सिंटैक्स बना रहे थे, और उन्होंने कहा होगा: "हमने तो बराबर का चिह्न असाइनमेंट के लिए पहले ही इस्तेमाल कर लिया है। अब बराबरी (equality) के लिए क्या इस्तेमाल करें?"
और C में, और कई दूसरी भाषाओं में भी, इसका हल सचमुच यही है: वे दो बराबर के चिह्न (==) इस्तेमाल करते हैं।
तो यह "बराबरी का ऑपरेटर" (equality operator) है, जबकि अकेला चिह्न असाइनमेंट ऑपरेटर है। और यह बस ऐसे ही है।
अब Scratch बच्चों के लिए बनाया गया है। छोटे बच्चों को दो बराबर के चिह्नों से उलझाने का कोई फ़ायदा नहीं। इसलिए Scratch एक अकेला बराबर का चिह्न इस्तेमाल करता है, जबकि C और ज़्यादातर भाषाएँ दोहरा बराबर का चिह्न इस्तेमाल करती हैं।
तो वहाँ एक छोटा-सा अंतर है।
एक ख़राब डिज़ाइन: तीसरा सवाल ग़ैर-ज़रूरी
घुँघराले कोष्ठकों में क्या जाता है? कुछ ख़ास दिलचस्प नहीं, बस कुछ और printf।
लेकिन यहाँ एक मौक़ा है कि हम न सिर्फ़ इस Scratch कोड और C कोड की समतुल्यता को अलग करके देखें, बल्कि एक ख़राब-डिज़ाइन के मौक़े को भी, जिस पर हम पिछले हफ़्ते थोड़ी देर के लिए ठोकर खा चुके थे।
यह तर्कसंगत रूप से अच्छी तरह डिज़ाइन नहीं किया गया है, भले ही यह सही है।
क्यों?
(छात्र) आपको यह तीसरा बूलियन एक्सप्रेशन पूछने की ज़रूरत नहीं है।
हाँ। हमें यह तीसरा बूलियन एक्सप्रेशन पूछने की ज़रूरत नहीं है। "क्या x, y के बराबर है?", कहें तो।
तो तार्किक रूप से, अगर हम सामान्य इंसानी संख्याओं की बात कर रहे हैं, तो वह या तो छोटी है, या बड़ी है, या डिफ़ॉल्ट रूप से बराबर है।
इसलिए आप यह तीसरा सवाल पूछकर कंप्यूटर का समय, और बदले में उपयोगकर्ता का समय, बर्बाद कर रहे हैं।
तो यहाँ थोड़ा बेहतर यह होगा कि "else if" हटा दें और एक डिफ़ॉल्ट स्थिति रखें, यानी कहें तो एक "else" ब्लॉक, जो इस तरह दिखे।
अगर यह तर्कसंगत है कि सिर्फ़ तीन संभावनाएँ हैं, तो आपको असल में तीन में से सिर्फ़ दो की जाँच करने की ज़रूरत है।
तो यह एक छोटा-सा सुधार (ऑप्टिमाइज़ेशन) है। लेकिन आप कल्पना कर सकते हैं कि आप अपने कोड में यह बार-बार करते हैं। आप कंप्यूटर या उपयोगकर्ता का समय बर्बाद नहीं करना चाहते, अगर आप चीज़ों को इस तरह बेहतर बना सकते हैं।
C के ऑपरेटरों की सूची
ठीक है। अब जब हमारे पास इन कंडीशनलों के लिए Scratch कोड और C कोड के बीच ये समतुल्यताएँ हैं, तो हम इस मिश्रण में और क्या-क्या डाल सकते हैं?
तो C में ऑपरेटरों का एक पूरा समूह है।
और बस इसलिए कि आपने एक जगह सूची देख ली हो: आपके पास न सिर्फ़ असाइनमेंट, "छोटा है", "बड़ा है" और बराबरी है, बल्कि यहाँ कुछ और भी हैं।
अब, भले ही Microsoft Word और Google Docs में आप "बड़ा या बराबर" का चिह्न बना सकते हों, जिसमें एक रेखा दूसरी के नीचे होती है, या "छोटा या बराबर" का।
C में, ज़्यादातर भाषाओं में, आप असल में कीबोर्ड दो बार दबाते हैं। आप "छोटा है" और बराबर का चिह्न (<=) लगाते हैं, या "बड़ा है" और बराबर का चिह्न (>=) लगाते हैं।
और इसी तरह आप "बड़ा या बराबर" या "छोटा या बराबर" की धारणा हासिल करते हैं।
!= का मतलब
यह वाला हमने देखा है। और क्या आप अंदाज़ा लगाना चाहेंगे कि विस्मयादिबोधक चिह्न और बराबर (!=) का क्या मतलब है, जिसे दूसरे तरीक़े से "बैंग इक्वल्स" (bang equals) भी बोलते हैं?
(छात्र) जी, "बराबर नहीं"।
हाँ। तो आम तौर पर, प्रोग्रामिंग में आपको विस्मयादिबोधक चिह्न किसी और चीज़ की नकार (negation), यानी उसके उलट, को दर्शाता मिलेगा।
इसलिए आप नहीं चाहते कि वह बराबर हो, आप चाहते हैं कि वह बराबर न हो।
अब आप सोच सकते हैं कि क्या यह "नहीं बराबर बराबर" नहीं होना चाहिए? हाँ, लेकिन वे कुंजी-दबाव (keystrokes) बचाने की कोशिश कर रहे हैं।
तो यह उसकी नकार है, भले ही यह बिल्कुल वैसा दिखता नहीं जैसा दिखना चाहिए। तीन के बजाय बस दो अक्षर।
और डॉट, डॉट, डॉट: और भी कई ऑपरेटर हैं जो आपको समय के साथ असली दुनिया में मिलेंगे।
लेकिन यह भी ध्यान देने लायक है कि C में सिर्फ़ स्ट्रिंग ही नहीं होतीं।
डेटा के प्रकार (टाइप)
याद कीजिए कि स्ट्रिंग टेक्स्ट की स्ट्रिंग थीं। और डेटा के दूसरे प्रकार भी हैं जो आप किसी उपयोगकर्ता से ले सकते हैं या सँभालकर रख सकते हैं।
हमने स्ट्रिंग देखी है, लेकिन हम असल में कई और भी देखेंगे।
तो C में हम "bool" देखेंगे। यह एक ऐसा वेरिएबल है जो सही (true) या ग़लत (false) हो सकता है, बस इतना ही। यानी बूलियन एक्सप्रेशनों से इसका गहरा रिश्ता है: एक वेरिएबल ख़ुद भी सही या ग़लत हो सकता है।
हम "char" यानी कैरेक्टर (अक्षर) देखेंगे। यह टेक्स्ट की स्ट्रिंग नहीं, जिसमें कई अक्षर और शब्द वग़ैरह होते हैं, बल्कि बस एक अकेला अक्षर होता है। कुछ भाषाओं के उलट, C अकेले अक्षरों और कई अक्षरों के बीच फ़र्क़ करती है।
float और double: दशमलव वाली संख्याएँ
"double", या बल्कि चलिए "float" पर कूदते हैं।
float को "फ़्लोटिंग पॉइंट वैल्यू" (floating point value) भी कहा जाता है। यह बस वह संख्या है जिसमें दशमलव बिंदु हो, यानी एक वास्तविक संख्या (real number), कहें तो।
लेकिन आजकल float आम तौर पर उन संख्याओं को दर्शाने के लिए कुल 32 बिट इस्तेमाल करता है।
इसमें पेच यह है: 32 बिट से आप कुल कितने मान दर्शा सकते हैं, मोटे तौर पर पिछले हफ़्ते के हिसाब से? यह उन गिनी-चुनी संख्याओं में से एक थी जिन्हें मैंने आपको याद रखने को कहा था। यह मोटे तौर पर 4 अरब है।
लेकिन गणित की कक्षा के अनुसार दुनिया में कितनी वास्तविक संख्याएँ हैं? अनगिनत (अनंत)।
तो ऐसा लगता है कि हम कोड में जितना दर्शा सकते हैं और दुनिया में असल में जितनी संख्याएँ हैं, उनके बीच एक बेमेल है।
double: ज़्यादा सटीकता, पर फिर भी सीमित
ठीक है, चिंता की बात नहीं। अगर आपको ज़्यादा सटीकता चाहिए, यानी ज़्यादा सार्थक अंक, तो आप अपने वेरिएबल को float से "double" में उन्नत कर सकते हैं। यह 64 बिट इस्तेमाल करता है, जो कहीं ज़्यादा सटीक है, दोगुने बिट।
लेकिन यह समस्या को बुनियादी रूप से हल नहीं करता, क्योंकि यह अब भी सीमित है, अनंत नहीं।
और आज के अंत में हम देखेंगे कि इसके असली दुनिया में क्या नतीजे हैं।
int और long: पूर्ण संख्याएँ
लेकिन फ़्लोटिंग पॉइंट मानों के अलावा, सादे "इंटीजर" (integers, पूर्ण संख्याएँ) भी हैं: 0, 1, 2 और उनके ऋणात्मक (नेगेटिव) रूप।
लेकिन ये परंपरागत रूप से 32 बिट इस्तेमाल करते हैं। इसका मतलब है कि "int" का इस्तेमाल करके कंप्यूटर जितनी ऊँची संख्या तक गिन सकता है, वह 4 अरब होगी।
लेकिन अगर आप ऋणात्मक संख्याएँ चाहते हैं, तो यह मोटे तौर पर 2 अरब होगी, ताकि आप ऋणात्मक 2 अरब तक भी जा सकें।
तो आजकल यह इतना बड़ा नहीं है।
"long" 64 बिट इस्तेमाल करता है, जो मानों की बहुत बड़ी रेंज है। लेकिन वहाँ भी यह अब भी सीमित है।
और कई और भी हैं।
cs50.h के फ़ंक्शन और छपाई के प्लेसहोल्डर
तो ये डेटा के वे प्रकार हैं जिन्हें हम अपने प्रोग्रामों में सँभालकर रख सकते हैं और उनके साथ काम कर सकते हैं।
लेकिन इनमें से कुछ, ख़ासकर एक, सीधे cs50.h से आते हैं।
तो अपने कोड में cs50.h शामिल करने से आपको जो चीज़ें मिलती हैं, उनमें सिर्फ़ get string ही नहीं, बल्कि ये दूसरे फ़ंक्शन भी हैं।
हम इनका थोड़ी देर में इस्तेमाल शुरू करेंगे, जिनसे आप इंटीजर, char, double या float ले सकते हैं।
हमारे पास "getBool" नहीं है, क्योंकि आम तौर पर सिर्फ़ सही या ग़लत की क़ीमत लेना बहुत उपयोगी नहीं है। लेकिन हम उसे बना सकते थे। हमने बस नहीं बनाने का फ़ैसला किया।
लेकिन हम अक्सर इन फ़ंक्शनों का इस्तेमाल करेंगे जिन्हें आप उस हेडर फ़ाइल के इस्तेमाल से पा सकते हैं।
लेकिन इन क़ीमतों को हम कहाँ रखेंगे? और उन्हें कैसे दिखाएँगे?
तो पता चलता है कि सिर्फ़ "percent s" ही नहीं है।
"percent s" स्ट्रिंग के लिए प्लेसहोल्डर था। लेकिन अगर आप कोई char, यानी एक अकेला अक्षर, छापना चाहते हैं, तो आप असल में "percent c" इस्तेमाल करेंगे।
अगर आप फ़्लोटिंग पॉइंट वैल्यू छापना चाहते हैं, तो आप "percent f" इस्तेमाल करेंगे। इंटीजर के लिए "percent i"। और लॉन्ग इंटीजर, यानी "long", के लिए आप इसके बजाय "percent li" इस्तेमाल करेंगे।
तो संक्षेप में, इन सभी समस्याओं के हल मौजूद हैं।
ये बौद्धिक रूप से दिलचस्प ब्योरे नहीं हैं, लेकिन ये उपयोगी, व्यावहारिक चीज़ें हैं जिन्हें आप अंत में समय के साथ आत्मसात कर लेंगे।
वेरिएबल: counter
तो चलिए, कुछ और उदाहरण साथ में करते हैं।
और थोड़ी देर में हम एक छोटे ब्रेक के लिए रुकेंगे, जिसमें हर हफ़्ते बाहर ट्रांसेप्ट (गिरजाघर जैसे बड़े हॉल का आड़ा हिस्सा) में नाश्ता परोसा जाएगा।
लेकिन उससे पहले, इन वेरिएबलों पर ध्यान देते हैं।
तो Scratch में हमारे पास ऐसे वेरिएबलों में कई मान सँभालकर रखने की क्षमता थी, जिन्हें हम नए पहेली-टुकड़े बनाकर ख़ुद बना सकते थे। C में आप असल में वही चीज़ पा सकते हैं।
तो उदाहरण के लिए, मान लीजिए कि Scratch में हम किसी के स्कोर का हिसाब एक काउंटर से रखना चाहते थे।
तो हम "counter" नाम का एक वेरिएबल बना सकते हैं और उसे शुरू में 0 पर सेट कर सकते हैं। फिर आख़िर में उसमें 1 जोड़ सकते हैं, 2 जोड़ सकते हैं, और इसी तरह, जैसे-जैसे वे कचरा कूड़ेदान में डालते हैं।
C में counter बनाना
तो C में आप लगभग वही करेंगे।
आप अपने वेरिएबल का नाम चुन सकते हैं, जैसे मैंने पहले "answer" के साथ किया था। आप उसे शुरू में 0 जैसी क़ीमत दे सकते हैं।
लेकिन पहले की बात के हिसाब से, मुझे यहाँ दाईं ओर C में शायद और क्या करना पड़ेगा?
(छात्र) आपको उसे एक टाइप देना पड़ेगा।
हाँ। मुझे टाइप देना पड़ेगा। और काउंटर, क्योंकि वह संख्यात्मक है, टेक्स्ट की स्ट्रिंग नहीं होगा। और मुझे नहीं लगता कि मुझे दशमलव बिंदुओं की चिंता करनी है, अगर मैं बस अपनी उँगलियों पर गिनने जैसा कुछ गिन रहा हूँ।
तो "int" काफ़ी होगा। और "int" सामान्य रूप से काम आने वाली संख्या है, कम से कम तब, जब 2 अरब से ज़्यादा मान आपके मामले के लिए ज़रूरत से ज़्यादा हों, जो यह मामला होगा।
अब भी एक छोटी चीज़ छूटी है?
(छात्र) जी, बात पूरी करने के लिए सेमीकोलन।
तो दाईं ओर वह वही है जो यहाँ बाईं ओर करने के बराबर है।
counter में 1 जोड़ना: तीन तरीक़े
मान लीजिए कि Scratch में आप काउंटर को बढ़ाना (increment) चाहते थे, यानी स्कोर में 1 जोड़ना, 2 जोड़ना, और इसी तरह।
वह कुछ ऐसा दिख सकता है: "counter को 1 से बदलो"। इसका अर्थ है ऊपर जाना, जब तक आप ऋणात्मक संख्या न दें, जिससे वह नीचे जाएगा।
C में आप यह असल में कई तरीक़ों से कर सकते हैं।
पहला तरीक़ा: "counter = counter + 1"। और यह फ़िलहाल थोड़ा ग़लत लगता है।
counter, counter धन 1 के बराबर कैसे हो सकता है?
इसका मतलब बराबरी नहीं है। अकेला बराबर का चिह्न असाइनमेंट के रूप में याद है। और इसका मतलब है: दाईं ओर की क़ीमत लो और उसे बाईं ओर की क़ीमत में, या इस मामले में बाईं ओर के वेरिएबल में, कॉपी कर दो।
तो यह काउंटर की मौजूदा क़ीमत, यानी 0, लेता है, उसमें 1 जोड़ता है, और फिर उस 1 को काउंटर वेरिएबल में सँभालकर रख देता है।
तो अब क़ीमत 1 है। और अगर आप फिर से करें, तो वह 2 हो जाती है, फिर 3, फिर 4, और इसी तरह।
छोटे रास्ते: += और ++
लेकिन ईमानदारी से, यह बढ़ाने की तकनीक इतनी आम है कि इसके लिए और भी संक्षिप्त संकेतन है। आप बस यह भी कर सकते हैं।
पहली नज़र में थोड़ा अजीब लगता है। लेकिन "counter plus equals 1" सेमीकोलन बिल्कुल वही काम करता है। आप बस कम कुंजियाँ दबाते हैं।
और ईमानदारी से, C में यह करना इतना ही आम है कि आप यह भी कर सकते हैं: "counter plus plus" (counter++)।
यह वही चीज़ है, यानी वेरिएबल में 1 जोड़ना।
"plus plus plus" या उससे ज़्यादा प्लस जैसा कुछ नहीं होता। यह सिर्फ़ अकेली क़ीमतों को 1 से बढ़ाने के लिए है।
तो यह कहा जा सकता है कि यह संस्करण और वह संस्करण, भले ही ज़्यादा लंबे हैं, थोड़े ज़्यादा लचीले हैं, क्योंकि आप एक बार में 2, या 3, या उससे ज़्यादा जोड़ सकते हैं।
और घटाने (decrementation) के लिए भी इनके समतुल्य हैं: "minus minus", या आम तौर पर माइनस का चिह्न वहाँ।
एक छोटा प्रोग्राम: compare.c
ठीक है, तो चलिए इस तकनीक को सचमुच कोड में इस्तेमाल करते हैं।
मैं वापस VS Code में जाता हूँ। मैं अपना फ़ाइल एक्सप्लोरर बंद कर देता हूँ।
और चलिए इस बार शायद एक तरह का छोटा कैलकुलेटर बनाते हैं।
मैं प्रस्ताव रखता हूँ कि हम एक बहुत ही बच्चा-सा कैलकुलेटर बनाएँ। या बल्कि, अभी कैलकुलेटर भी नहीं। बस कुछ मानों की तुलना करते हैं।
तो मैं यह करता हूँ। "code compare.c", ताकि compare नाम का एक बिल्कुल नया प्रोग्राम बने।
और फिर इसमें मैं थोड़ा-सा बॉयलरप्लेट (हर बार दोहराया जाने वाला ढाँचा) लिखूँगा।
मैं cs50.h शामिल करूँगा। मैं stdio.h शामिल करूँगा। और मैं "int main void" करूँगा, जिस पर अगले हफ़्ते और बात होगी।
और फिर घुँघराले कोष्ठकों के अंदर, इन नई तकनीकों का इस्तेमाल करते हैं।
दो संख्याएँ माँगना: get_int
मैं अपने लिए "x" नाम का एक वेरिएबल बनाता हूँ और उसे "get int" की रिटर्न वैल्यू के बराबर रखता हूँ। यह वह दूसरा फ़ंक्शन है जिसके मौजूद होने का मैंने वादा किया था।
और चलिए उपयोगकर्ता से x की क़ीमत माँगते हैं, इस तरह के वाक्य के साथ: "What's x?" प्रश्नचिह्न। और फिर एक स्पेस, कर्सर को थोड़ा सरकाने के लिए।
चलिए एक और वेरिएबल लेते हैं, "y", और उसे फिर से "get int" के बराबर रखते हैं। इस बार उपयोगकर्ता से पूछते हैं: "What's y?"
असल में एक ही फ़ंक्शन को दो बार इस्तेमाल करके, पर दो अलग-अलग क़ीमतें पाने के लिए।
अब चलिए कुछ बिल्कुल सीधा-सादा करते हैं।
अगर x, y से छोटा है, तो printf से छापिए: "x is less than y", backslash n कर्सर को नीचे ले जाने के लिए। उद्धरण चिह्न बंद, सेमीकोलन।
compare को कंपाइल करके चलाना
तो यह कोई बहुत दिलचस्प प्रोग्राम नहीं है। लेकिन कम से कम यह गतिशील (डायनामिक) है, क्योंकि अब मैं उपयोगकर्ता से दो संख्याएँ माँग रहा हूँ।
तो यह करते हैं। "make compare", एंटर।
लगता है काम कर गया।
और असल में, मैं जाँच सकता हूँ कि यह काम कर गया या नहीं। इसके लिए मैं अपनी डायरेक्टरी की फ़ाइलों की सूची देखने वाली कमांड टाइप करता हूँ, छोटे में "ls"।
और अब आप देखेंगे कि मेरे पास hello.c है, लेकिन hello नहीं है, क्योंकि मैंने उसे कुछ मिनट पहले "rm" से हटा दिया था।
मेरे पास compare.c है, जो मैंने अभी बनाई है। और फिर मेरे पास compare नाम का एक प्रोग्राम भी है।
और वहाँ तारांकन (*) बस एक दृश्य संकेत है कि यह "एक्ज़ीक्यूटेबल" है, यानी चलाया जा सकने वाला। यह एक प्रोग्राम है जिसे आप चला सकते हैं। यह कोई सादी पुरानी फ़ाइल नहीं है।
भले ही मैंने पहले hello के साथ "ls" टाइप नहीं किया, इस संदर्भ में उसके बगल में भी इसी तरह तारांकन होता। लेकिन आप फ़ाइल एक्सप्लोरर में यह नहीं देखते।
compare चलाना और पहली कमी
अब अगर मैं compare चलाऊँ, तो चलिए कुछ बेवक़ूफ़ाना करते हैं: x के लिए 1, y के लिए 2।
ठीक है: "x is less than y"।
चलिए फिर से करते हैं। dot slash compare। x के लिए 2, y के लिए 1।
ठीक है, और मुझे कुछ दिखता नहीं।
तो मुझे कुछ क्यों नहीं दिख रहा?
तार्किक रूप से, मैंने "बड़ा है" की जाँच के लिए कोई शर्त नहीं रखी थी, "बराबर है" की तो बात ही छोड़िए।
else जोड़कर सुधार
तो चलिए इसे थोड़ा बेहतर बनाते हैं।
मैं कम से कम यह कहता हूँ: ठीक है, "else"। अगर x, y से छोटा नहीं है, तो छापिए: "x is not less than y", backslash n, उद्धरण चिह्न बंद, सेमीकोलन।
तो कम से कम मैं उस स्थिति को भी सँभाल रहा हूँ।
मैं अपनी टर्मिनल विंडो साफ़ करता हूँ। फिर से "make compare" करता हूँ। "dot slash compare"।
1 और 2 बिल्कुल वैसे ही काम करता है।
अब मैं 2 और 1 करता हूँ। अब हमारे पास बेहतर आउटपुट है।
"बराबर" का मामला भी जोड़ना
ज़ाहिर है, यह अभी पूरा नहीं है। क्योंकि अगर मैं फिर से "dot slash compare" चलाऊँ और 1 और 1 दूँ, तो अच्छा होगा कि "x is not less than y" से थोड़ा ज़्यादा ख़ास कुछ बताया जाए।
यह ग़लत नहीं है, लेकिन बहुत सटीक नहीं है।
तो मैं उस चीज़ को मिश्रण में जोड़ सकता हूँ जो हमने पहले की थी। मैं कह सकता हूँ: ठीक है, तो "else if x is greater than y", कहो "x is greater than y"। "else if x equals equals y", तो छापिए "x is equal to y", backslash n, उद्धरण चिह्न बंद।
कौन-सी पंक्ति फ़ालतू है?
लेकिन यहाँ भी, किसी ने देखा कि यह एक तरह से बेवक़ूफ़ाना ढंग से अक्षम (inefficient) है।
इसे कसने के लिए मुझे असल में कोड की कौन-सी पंक्ति सुधारनी चाहिए?
(छात्र) जी, पंक्ति 17।
हाँ। तो पंक्ति 17: मुझे लगता है मैं उस अनावश्यक सवाल से छुटकारा पा सकता हूँ। क्योंकि तार्किक रूप से, इस मोड़ पर यही स्थिति होगी।
और अब मैं इसे "make compare" से फिर कंपाइल कर सकता हूँ, "dot slash compare", फिर से, एंटर, 1 और 1। और अब हम फिर काम पर हैं, और उन तीनों स्थितियों को पकड़ रहे हैं।
सवाल: तीन अलग-अलग if क्यों नहीं?
इनमें से किसी भी चीज़ के बारे में सवाल?
मैंने जान-बूझकर यह क्यों नहीं किया?
मैं ज़रा पीछे जाता हूँ। और मैं अपनी टर्मिनल विंडो छिपा देता हूँ ताकि ज़ोर यहाँ कोड पर बना रहे।
क्यों न यह किया जाए और मेरा कोड तर्कसंगत रूप से सरल रखा जाए? यानी क्यों न बस तीन सवाल पूछे जाएँ, यहाँ पंक्ति 9, पंक्ति 13 और पंक्ति 17 पर?
(छात्र) आपको क्या पसंद नहीं?
(छात्र) क्योंकि तब वह हर एक शर्त की जाँच करेगा। भले ही, उदाहरण के लिए, पहली शर्त पूरी हो गई हो, वह दूसरी और तीसरी की भी जाँच करेगा, और हर बार ऐसे ही।
बिल्कुल सही।
सब शर्तों को जाँचना: ख़राब डिज़ाइन
यह ख़राब डिज़ाइन का एक और उदाहरण है। क्योंकि अब, चाहे जो हो, आप पंक्ति 9, 13 और 17 पर तीन सवाल पूछ रहे होंगे।
भले ही शुरू से ही x, y से छोटा निकले, आप फिर भी सबका समय बर्बाद कर रहे हैं यह कहकर: "तो क्या x, y से बड़ा है?" आपको शायद पहले से पता है कि नहीं है। "क्या x, y के बराबर है?" आपको शायद पहले से पता है कि नहीं है।
और इसलिए ये तीन कंडीशनल फ़िलहाल पारस्परिक रूप से अलग (mutually exclusive) हैं। यानी आप उन तीनों की जाँच कर रहे हैं, चाहे जो हो, भले ही तार्किक रूप से यह ज़रूरी नहीं होना चाहिए।
तो हमारा पहला तरीक़ा असल में काफ़ी बेहतर था।
फ़्लोचार्ट: कोड को चित्र के रूप में देखना
और असल में, आपको घनत्व (डेंसिटी) का फ़र्क़ दिखाने के लिए, मैं इस बिल्कुल पहले संस्करण पर लौटता हूँ, जिसमें मैं सिर्फ़ यही एक शर्त जाँच रहा था: क्या x, y से छोटा है।
तो अगर आप ज़्यादा दृश्य-शैली से सीखने वाले हैं, तो आप असल में कोड कैसा दिखता है, उसे फ़्लोचार्ट (flowchart) के रूप में भी बना सकते हैं।
तो यहाँ एक प्रोग्राम का चित्र है जो यहाँ से शुरू होता है और आदर्श रूप से यहाँ नीचे रुकता है।
और बीच की इन आकृतियों में से हर एक कोड के तार्किक घटकों को दर्शाती है।
यहाँ इस हीरे (डायमंड) में मेरा बूलियन एक्सप्रेशन है, जो कंडीशनल की शुरुआत को दर्शाता है।
तो अगर x, y से छोटा है, तो मुझे एक फ़ैसला लेना है। हाँ या नहीं? सही या ग़लत?
तो अगर वह y से छोटा है, सही, तो चलिए "x is less than y" छापते हैं, और फिर रुक जाते हैं।
पहले और दूसरे संस्करण का फ़्लोचार्ट
लेकिन उस प्रोग्राम का पहला संस्करण, याद कीजिए, कुछ नहीं कहता था अगर x, y से छोटा न हो।
क्योंकि "ग़लत" से बस प्रोग्राम रुक जाता था। "stop" जैसा कोई कीवर्ड नहीं है। बस उस स्थिति को सँभालने के लिए कोई कोड नहीं है।
लेकिन कोड के दूसरे संस्करण में, जब मैंने "else" जोड़ा, तो वह बुनियादी रूप से थोड़ा अलग दिखता था।
तो अब, उस कोड का दूसरा संस्करण पूछता है: क्या x, y से छोटा है? और अगर सही है, तो व्यवहार बिल्कुल वही है।
लेकिन अगर वह सही नहीं था, बल्कि ग़लत था, तब मुझे संदेश मिला: "x is not less than y"।
तीसरे संस्करण का फ़्लोचार्ट
लेकिन कोड के तीसरे संस्करण में, जहाँ मैंने "if, else if, else if" जोड़ा, तब चित्र थोड़ा और जटिल हो जाता है।
और मैं ऊपर से नीचे तक ज़ूम करता हूँ।
यहाँ हमारे पास एक लंबा फ़्लोचार्ट है, लेकिन सवाल असल में वही हैं।
जब मैं यह प्रोग्राम शुरू करता हूँ, तो मैं पूछता हूँ: क्या x, y से छोटा है?
अगर हाँ, तो मैं छापता हूँ "x is less than y"।
लेकिन प्रोग्राम के उस आख़िरी संस्करण में मैं अब भी मूर्खतापूर्ण ढंग से वही सवाल पूछ रहा था: "अरे रुको, क्या x, y से बड़ा है?" "अरे रुको, क्या x, y के बराबर है?"
और वही वह संस्करण है जिसमें, फिर से, मेरे पास वह सारा अनावश्यक कोड था, जिसे मैंने यहाँ अभी वापस डाला है, यानी एक बार में तीन सवाल पूछना।
बेहतर संस्करण का फ़्लोचार्ट
आदर्श रूप से, मैं यह ग़लती बार-बार-बार नहीं करना चाहता। तो अगर मैं इसके बजाय उस कोड को "else if" और "else" पर वापस ले जाऊँ, तो मेरा फ़्लोचार्ट थोड़ा अलग दिखता है, क्योंकि अब शॉर्टकट पर ध्यान दीजिए।
अगर x, y से छोटा है, सही, तो हम यह करते हैं और काम ख़त्म, बहुत तेज़ी से।
अगर x, y से छोटा नहीं है, ठीक है, तो हम एक और सवाल पूछते हैं: क्या x, y से बड़ा है?
तो अगर हाँ, तो बस वही छापकर हम प्रोग्राम के अंत तक पहुँच जाते हैं।
यह सिर्फ़ उस उलटे मामले में है जहाँ x बराबर-बराबर y हो।
क्या हम यह शर्त जाँचते हैं? नहीं। यह शर्त? नहीं। यह शर्त?
और फिर, ठीक है, अब हम छाप सकते हैं "x is equal to y", क्योंकि तर्क के हिसाब से वही होना चाहिए।
बेशक, कई बार देखा जा चुका है कि यह सबके समय की बर्बादी है। इसलिए हम इस चार्ट को और छाँट सकते हैं और बस एक सवाल, दो सवाल रख सकते हैं। और सिर्फ़ इतने से ही प्रोग्राम कस जाता है।
तो फिर से, अगर आप ज़्यादा दृश्य-शैली से सीखने वाले हैं, तो कोड के लगभग किसी भी खंड को आप इस तरह के चित्र-रूप में अनुवाद कर सकते हैं। लेकिन यह असल में वही तार्किक प्रवाह पकड़ता है जिसे इंडेंटेशन, सिंटैक्स और कोड ख़ुद दर्शाने के लिए बने हैं।
एक और उदाहरण: agree.c
ठीक है, तो एक और प्रकार के साथ एक आख़िरी अभ्यास कैसा रहेगा?
याद कीजिए कि यह हमारे लिए उपलब्ध प्रकारों की सूची है। असल में, थोड़े ब्रेक से पहले दो आख़िरी उदाहरण।
यहाँ हमारे पास उन प्रकारों की सूची है जिन्हें हम इस्तेमाल कर सकते हैं, और यहाँ उन फ़ंक्शनों की सूची है जिन्हें हम इस्तेमाल कर सकते हैं।
चलिए एक ऐसा प्रोग्राम बनाते हैं जो उस चीज़ का प्रतिनिधित्व करे जो हम आजकल काफ़ी करते हैं, लेकिन एक अलग प्रकार के साथ।
तो मैं वापस VS Code में जाता हूँ। मैं compare.c बंद करता हूँ। मैं अपनी टर्मिनल विंडो दोबारा खोलता हूँ और उसे क्लियर करता हूँ, बस ताकि हमारे पास नया प्रॉम्प्ट हो।
और चलिए agree.c नाम का एक प्रोग्राम बनाते हैं।
आजकल बहुत बार हमें "नियम और शर्तें" (terms and conditions) मानने के लिए सहमत होना पड़ता है। निष्पक्ष होकर कहें तो, यह आम तौर पर एक पॉप-अप और एक बटन के रूप में होता है जिस पर हम क्लिक करते हैं। लेकिन हम यह कमांड लाइन पर कोड में भी कर सकते हैं।
char से हाँ-या-नहीं पूछना: get_char
मैं शुरुआत में cs50.h शामिल करता हूँ और शुरुआत में stdio.h शामिल करता हूँ।
मैं फिर से, आज के मक़सद के लिए, "int main void" करता हूँ। लेकिन हम अगले हफ़्ते बताएँगे कि हम ऐसा क्यों करते रहते हैं।
और अब, हाँ-या-नहीं के जवाब के लिए, पूरी स्ट्रिंग के बजाय सिर्फ़ एक अकेला char, यानी अक्षर, माँगना काफ़ी है।
तो यह करते हैं: "char c equals get char"।
और उपयोगकर्ता से पूछते हैं, उद्धरण चिह्नों में, "Do you agree?" प्रश्नचिह्न, उदाहरण के लिए।
और अब मैं उस क़ीमत की बराबरी की तुलना कुछ जाने-पहचाने जवाबों से कर सकता हूँ।
उदाहरण के लिए, मैं कह सकता हूँ: अगर "c equals equals" उद्धरण चिह्नों में "y", तो छापिए, उदाहरण के लिए, "Agreed." (पूर्णविराम), backslash n, उद्धरण चिह्न बंद, सेमीकोलन।
वरना अगर "c equals equals n", उद्धरण चिह्नों में, तो छापिए, उदाहरण के लिए, "Not agreed." (पूर्णविराम), backslash n, सेमीकोलन।
अब, यहाँ अब भी सुधार की गुंजाइश है। लेकिन ध्यान दीजिए कि हम बस अब C में उन्हीं निर्माण-खंडों को अलग-अलग तरीक़ों से इस्तेमाल कर रहे हैं, अलग-अलग समस्याएँ हल करने के लिए।
इकहरे उद्धरण चिह्न बनाम दोहरे
लेकिन ध्यान दीजिए, पंक्ति 8 और 12 पर मैंने इकहरे (single) उद्धरण चिह्न इस्तेमाल किए हैं, जिसका मैंने पहले संकेत दिया था।
ऐसा क्यों है? इस मामले में इकहरे क्यों?
(छात्र) क्योंकि वह एक अकेला अक्षर है।
हाँ, यह एक अकेला अक्षर है, और C में बस ऐसे ही किया जाता है।
जब आप किसी अकेले अक्षर की तुलना करना चाहते हैं, तो आप "char" इस्तेमाल करते हैं और इकहरे उद्धरण चिह्न इस्तेमाल करते हैं।
जब आप टेक्स्ट की स्ट्रिंग इस्तेमाल करना चाहते हैं, यानी कई अक्षर, कई शब्द, कई वाक्य, या अनुच्छेद, तो आप स्ट्रिंग इस्तेमाल करते हैं।
else if की जगह else
तो यह काम करता दिखेगा। लेकिन मैं तर्कसंगत रूप से थोड़ा और कुशल हो सकता हूँ, अगर उपयोगकर्ता "y" टाइप नहीं करता।
मेरा मतलब है, सच कहूँ तो मैं इस "else if" को काटकर "else" बना सकता हूँ और बस मान सकता हूँ कि अगर आप मुझे "y" का जवाब नहीं देते, तो कम से कम मैं सबसे बुरा मान लूँगा और कहूँगा कि आप सहमत नहीं हैं।
लेकिन यहाँ भी, प्रोग्राम बहुत बढ़िया नहीं है।
मैं "make agree" करता हूँ, और फिर "dot slash agree" करता हूँ।
और क्या मैं सहमत हूँ? हाँ। मैं "y" टाइप करता हूँ।
इस बीच, अगर मैं "n" जैसा कुछ और टाइप करूँ, या ज़ोर देकर पूरा "no" ही लिख दूँ, तो वह लगता है कि, अरे, यह काम क्यों नहीं किया?
(छात्र) ...
बिल्कुल सही।
get_char की ख़ूबी: टाइप की जाँच
तो CS50 के फ़ंक्शनों की ख़ूबियों में से, जैसे "get char", एक यह है कि वह लागू करता है कि आप किस प्रकार का डेटा ले रहे हैं।
तो भले ही मैंने "get char" इस्तेमाल किया हो, अगर उपयोगकर्ता सहयोग नहीं करता और कई अक्षर टाइप कर देता है, तो "get char", हमारे कुछ दूसरे फ़ंक्शनों की तरह, बस इसी तरह बना है कि वह उनसे बार-बार, बार-बार पूछता रहता है, जब तक वे सहयोग न करें।
यह उपयोगी है ताकि आपको उस तरह की त्रुटि-जाँच से निपटना न पड़े।
लेकिन यहाँ मैं बड़े अक्षर में "N" टाइप कर सकता हूँ, और अब यह काम करता दिखता है। लेकिन यह सिर्फ़ "else" की वजह से काम करता है।
बड़े अक्षर "Y" की गड़बड़ी
मैं यह करता हूँ, जो बहुत वाजिब है। मैं "y" टाइप करता हूँ, बड़े अक्षर में "Y", जिससे आप उम्मीद करेंगे कि यह काम करे।
इस मोड़ पर यह एक बग (गड़बड़ी) जैसा लगता है।
मतलब, यह ठीक है कि हम "yes" और "no" का समर्थन नहीं करना चाहते। हम बस "y" और "n" का समर्थन करना चाहते हैं।
लेकिन उसके बड़े अक्षर वाले रूप का समर्थन न करना थोड़ा खीझ दिलाने वाला है।
तो हम इसे कैसे ठीक कर सकते हैं?
दोहराव: ख़राब तरीक़ा
तो मैं अपनी टर्मिनल विंडो छिपा देता हूँ। और मैं अंदर जाकर इसे इस तरह ठीक कर सकता हूँ।
मैं कह सकता हूँ: ठीक है, "else if c equals equals", इकहरे उद्धरण चिह्नों में बड़े अक्षर "Y", और फिर मैं छाप सकता हूँ "Agreed." (पूर्णविराम), backslash n, सेमीकोलन, और फिर मैं "else" कर सकता हूँ। वह काम करेगा। वह वहाँ काम करेगा।
लेकिन इस हल में आपको क्या खटकता है, शायद, भले ही आपने पहले कभी प्रोग्रामिंग न की हो? बस पिछले हफ़्ते के कुछ सबक़ लागू कीजिए।
(छात्र) यह दोहराव है।
हाँ। मेरा मतलब है, तकनीकी रूप से मैंने कॉपी-पेस्ट नहीं किया, लेकिन पंक्ति 14 पंक्ति 10 के बिल्कुल जैसी है। तो मैंने कॉपी-पेस्ट ही कर दिया होता।
और यह आम तौर पर बुरा अभ्यास है।
क्यों? अगर मैं उस मामले में अंग्रेज़ी का वाक्य कुछ और बदलना चाहूँ, तो अब मुझे उसे दो बार बदलना पड़ेगा। और मैं बस अपनी ही बात दोहरा रहा हूँ, जो ख़राब डिज़ाइन है।
तार्किक ऑपरेटर: || (या)
तो इसे दूसरे प्रकार के ऑपरेटरों से सँभालने के तरीक़े हैं, जो हमने अभी तक नहीं देखे हैं।
अगर मैं एक साथ दो सवाल पूछना चाहूँ, तो वह ठीक है। मैं कुछ ऐसा कर सकता हूँ।
यानी: अगर "c equals equals" उद्धरण चिह्नों में "y", या "c equals equals" उद्धरण चिह्नों में बड़ा "Y"।
मैं तथाकथित "लॉजिकल ऑपरेटर" (logical operators, तार्किक संचालक) का इस्तेमाल करके चीज़ों को कस सकता हूँ। इसमें मैं अब एक बूलियन एक्सप्रेशन लेता हूँ और उसे दो छोटे बूलियन एक्सप्रेशनों से बनाता हूँ।
और मुझे इस बात की परवाह है कि उन सवालों में से किसी एक का जवाब सही हो।
तो चाहे वह छोटा "y" हो या बड़ा "Y", यह कोड अब काम करेगा। और अगर कुछ और हो, तो हम डिफ़ॉल्ट रूप से "सहमत नहीं" मानेंगे।
तो दो खड़ी रेखाएँ (||), जो शायद ऐसा अक्षर नहीं है जिसे आप अक्सर टाइप करते हों, और जो आपके कीबोर्ड पर कहाँ है यह इस पर निर्भर करता है कि वह अमेरिकी अंग्रेज़ी है या कुछ और, का मतलब बस तार्किक "या" (logical or) है।
&& (और) यहाँ क्यों नहीं चलेगा
यह यहाँ प्रासंगिक नहीं है। लेकिन आप कुछ संदर्भों में "और" दर्शाने के लिए दो एम्परसैंड (&&) भी इस्तेमाल कर सकते हैं।
लेकिन यहाँ यह समझ में नहीं आता। क्यों?
इन दोनों उपवाक्यों के बीच "और" कहना साफ़ तौर पर सही क्यों नहीं है?
(छात्र) ...
(छात्र) जी, क्योंकि वह छोटा "y" है।
बिल्कुल सही। वेरिएबल एक साथ छोटा और बड़ा अक्षर दोनों नहीं हो सकता। यह बस बिल्कुल समझ में नहीं आता।
तो यह एक बग होता। लेकिन यहाँ दो खड़ी रेखाओं का इस्तेमाल, असल में, सही है।
लूप: बार-बार दोहराना
ठीक है, तो चलिए कंडीशनलों के अलावा एक आख़िरी रंगीन चीज़ करते हैं।
हमारे पास अब ये लूप (loops) थे। याद कीजिए कि लूप बस ऐसी चीज़ है जो कोई काम बार-बार-बार करती है।
यहाँ, उदाहरण के लिए, Scratch में हम तीन बार "meow" इस तरह कर सकते हैं।
C में इसे करने के कुछ अलग-अलग तरीक़े होंगे।
while लूप: उल्टी गिनती से
यह एक है।
आप C में एक वेरिएबल घोषित कर सकते हैं, जैसे "i" इंटीजर के लिए, या जो भी नाम देना चाहें, और उसे तीन के बराबर रख सकते हैं, यानी वह संख्या जिसकी आपको परवाह है।
फिर आप एक लूप इस्तेमाल कर सकते हैं। और "repeat" ब्लॉक के सबसे नज़दीक तर्कसंगत रूप से "while" लूप है।
C में "repeat" जैसा कोई कीवर्ड नहीं है। इसलिए हम इसका शब्दशः अनुवाद नहीं कर सकते।
लेकिन हम कह सकते हैं: "while i is greater than 0", यानी जब तक i शून्य से बड़ा है।
क्यों? क्योंकि तार्किक रूप से मैं यही करना चाहता हूँ।
अगर मैं 3 से गिनना शुरू करूँ, तो शायद मैं एक-एक करके घटाता जाऊँ और 0 तक पहुँच जाऊँ। उस बिंदु पर मैं यह काम करना बंद कर सकता हूँ।
तो मैं एक वेरिएबल "i" को 3 पर शुरू (इनिशियलाइज़) करूँगा। और फिर मैं कहूँगा: जब तक i शून्य से बड़ा है, आगे बढ़कर यह करो।
i-- से घटाना
और उस लूप के अंत में, दोबारा घूमने से पहले, मैं कोड की यह पंक्ति इस्तेमाल करूँगा। हमने इसे नहीं देखा है, लेकिन आप अनुमान लगा सकते हैं।
"i minus minus" (i--) का मतलब बस यह है कि i में से 1 घटा दो।
तो इसका असर यह होगा कि 3 से शुरू होकर, 2 पर, फिर 1 पर, फिर 0 पर जाएगा।
और जैसे ही यह 0 पर जाएगा, यह बूलियन एक्सप्रेशन अब सही नहीं रहेगा। इसलिए लूप अपने-आप रुक जाएगा, क्योंकि बस इतना ही है।
तो इस घटाने के अलावा घुँघराले कोष्ठकों के अंदर हम क्या रखेंगे?
मुझे लगता है कि मैं सिर्फ़ "meow" कहकर काम चला सकता हूँ। और यह अब 1, 2, 3 बार छापेगा।
ऊपर की ओर गिनना
और फिर भी यह दिलचस्प है। मैंने सहज रूप से 1, 2, 3 गिना, जबकि मैं प्रस्ताव रख रहा हूँ कि हम 3, 2, 1 गिनें।
तो क्या हम तर्क को दूसरी दिशा में लागू कर सकते हैं, जहाँ हम 3 से नीचे की ओर गिनने के बजाय 0 से ऊपर की ओर गिनें?
हाँ, बिल्कुल। हमें बस कुछ बदलाव करने होंगे।
हम "i" को शुरू में 0 के बराबर रख सकते हैं।
हम अपने बूलियन एक्सप्रेशन को बदलकर बार-बार, बार-बार यह जाँचने के लिए रख सकते हैं कि "i, 3 से छोटा है"।
और इस लूप के हर चक्र (इटरेशन) में, चलिए "i plus plus" से i को बढ़ाते जाते हैं।
और इस बिंदु पर इसका असर 1, 2, 3 करने का होगा। 3, 3 से छोटा नहीं है, इसलिए मैं और उँगलियाँ नहीं उठाऊँगा। मैं कुल मिलाकर तीन बार "meow" करूँगा।
while लूप का फ़्लोचार्ट
और फिर से, अगर आप दृश्य-शैली के व्यक्ति हैं, तो यहाँ दिखाया गया है कि हम शुरू में 0 से गिनना कैसे शुरू कर सकते हैं।
जाँचिए कि i, 3 से छोटा है, जो शुरू में है।
और अगर हाँ, तो हम "meow" छापते हैं।
फिर हम i को बढ़ाते हैं, और हमें फिर से बूलियन एक्सप्रेशन की ओर घुमा दिया जाता है, क्योंकि while लूप ऐसे ही काम करते हैं।
आपके पास शर्त लगातार बार-बार, बार-बार जाँची जाती रहती है। C ऐसे ही काम करती है।
जैसे ही मैं i को 0 से 1 से 2 से 3 तक बढ़ा देता हूँ, तो 3, 3 से छोटा नहीं होगा, इसलिए जवाब "ग़लत" होगा, और लूप बस रुक जाएगा।
तो उससे वही नतीजा मिल जाता है।
for लूप: कम लिखना
लेकिन पता चलता है कि किसी निश्चित संख्या में बार लूप चलाना इतना ही आम है कि आपको सख़्ती से "while" लूप इस्तेमाल करना ज़रूरी नहीं है।
एक "for" लूप भी वहाँ एक विकल्प है। इसका सिंटैक्स थोड़ा अजीब है। इसे याद रखना थोड़ा कठिन है। लेकिन यह आपको थोड़ा कम कोड लिखने देता है, क्योंकि आप एक ही पंक्ति में ज़्यादा कोड लिखते हैं।
तो आप for लूप को जिस तरह पढ़ते हैं, वह भावना में बिल्कुल वही है।
आप वेरिएबल को शुरू करते हैं, यानी इस पहले सेमीकोलन के बाईं ओर की हर चीज़।
फिर शर्त जाँचते हैं, और कंप्यूटर यह सब आपके लिए करता है: "अगर i, 3 से छोटा है", और अगर हाँ, तो आप घुँघराले कोष्ठकों के अंदर की चीज़ चलाते हैं।
और फिर अपने-आप, दूसरे सेमीकोलन के दाईं ओर की चीज़ होती है, यानी इस मामले में i, 0 से 1 तक बढ़ जाता है।
शर्त जाँची जाती है: क्या 1, 3 से छोटा है? हाँ है, इसलिए हम फिर से "meow" छापते हैं, और i को बढ़ाकर 2 कर देते हैं।
क्या 2, 3 से छोटा है? हाँ, इसलिए हम फिर "meow" करते हैं।
i को बढ़ाकर 3 कर दिया जाता है। क्या 3, 3 से छोटा है? नहीं, इसलिए for लूप रुक जाता है।
तो यह बिल्कुल वही है, बस इस पहली पंक्ति में ज़्यादा जादू हो रहा है। इतना ज़्यादा, जितना आपको ख़ुद असल में लिखना पड़ता है उससे भी ज़्यादा। और यह तर्कसंगत रूप से ज़्यादा आम परंपरा है। लेकिन अगर आप चाहें तो ख़ुद दोनों तरीक़े पूरी तरह सही हैं।
बिल्ली का प्रोग्राम: cat.c
तो चलिए अब VS Code में सचमुच इस बिल्ली की शुरुआत लागू करते हैं।
मैं VS Code पर वापस जाता हूँ और agree.c बंद करता हूँ। मैं अपनी टर्मिनल विंडो दोबारा खोलता हूँ और cat.c में एक असली बिल्ली बनाता हूँ।
और चलिए इसे शुरू में ग़लत तरीक़े से करते हैं।
stdio.h शामिल कीजिए, "int main void"। और फिर main के अंदर, उद्धरण चिह्नों में "meow", backslash n, सेमीकोलन छापते हैं।
और फिर, अरे, मैं बस कॉपी-पेस्ट कर देता हूँ।
यह ज़ाहिर है ग़लत तरीक़ा है, इसे करने का बुरा तरीक़ा, क्योंकि मैं सचमुच कॉपी और पेस्ट कर रहा हूँ।
लेकिन यह सही है, अगर मैं चाहता हूँ कि बिल्ली तीन बार "meow" करे।
मैं "make cat" कर सकता हूँ। मैं "dot slash cat" कर सकता हूँ। और मुझे मेरा "meow, meow, meow" मिल जाता है।
while लूप से बिल्ली को सुधारना
लेकिन अब असल में उन नए निर्माण-खंडों में से कुछ का इस्तेमाल करते हैं, जहाँ हमने Scratch को C में बदला था।
मैं इस कोड पर वापस जाता हूँ। और मैं पहले "while" लूप करूँगा।
तो मैं इसके बजाय "int i equals 3" कर सकता था, अगर हम शुरू में नीचे की ओर गिनें।
"while i is greater than 0", तब आगे बढ़कर उद्धरण चिह्नों में "meow", backslash n छापिए।
और फिर "i plus plus" करना है या "i minus minus"? "i minus minus", क्योंकि हम 3 से शुरू कर रहे हैं।
अब मैं वापस अपनी टर्मिनल विंडो में जाता हूँ और उसे क्लियर करता हूँ। फिर से "make cat", "dot slash cat" करता हूँ। और हमें तीन "meow" मिलते हैं।
और यह अब तर्कसंगत रूप से बेहतर तरीक़े से लागू है।
उल्टा करके देखना
अगर मैं चीज़ों को पलटना चाहूँ तो?
तो मैं अब शायद सामान्य-इंसान वाला तरीक़ा अपना सकता हूँ। मैं 0 से गिनना शुरू कर सकता हूँ।
और मैं यह तब तक कर सकता हूँ जब तक "i, 3 से छोटा है"। और मैं यह तब कर सकता हूँ जब तक मैं हर चक्र में i को बढ़ाता रहूँ।
अब मैं फिर से "make cat", "dot slash cat", एंटर कर सकता हूँ।
और यह भी काम करता है।
1 से 3 तक गिनने का तरीक़ा और परंपरा
लेकिन इसे करने का एक और तरीक़ा भी है।
अगर मैं सामान्य इंसान की तरह गिनना चाहूँ, यानी 1 से गिनना शुरू करूँ और 2 और 3 तक ऊपर जाऊँ, तो मैं यह कर सकता हूँ।
लेकिन यह, तर्कसंगत रूप से, यह सही है। यह तीन बार दोहराएगा। लेकिन यह थोड़ा उलझाने वाला है, क्योंकि अब मुझे यह सोचना पड़ता है कि 4 से छोटा होने का क्या मतलब है। ठीक है, उसका मतलब 3 के बराबर है।
मैं थोड़ा और स्पष्ट हो सकता हूँ और कह सकता हूँ: ठीक है, यह तब तक करो जब तक i, 3 से छोटा या उसके बराबर है, उन्हीं ऑपरेटरों में से एक और का इस्तेमाल करके।
तो मैं एक बार फिर "make cat", "dot slash cat" कर सकता हूँ। और वह भी काम करेगा।
अब इनमें से कौन-सा सही या सबसे अच्छा है?
सच कहें तो परंपरा, आम तौर पर और कोड में, यह है कि 0 से गिनना शुरू करें और ऊपर की ओर गिनें, लेकिन उस क़ीमत तक नहीं पहुँचें जो आप चाहते हैं।
इस तरह कम से कम आपको शुरुआती बिंदु और अंतिम बिंदु, कहें तो, एक साथ स्क्रीन पर दिखाई देते हैं।
for लूप में बदलना
लेकिन बेशक, मैं यह सब और थोड़ा संक्षिप्त कर सकता हूँ और इस पूरी चीज़ को एक "for" लूप में बदल सकता हूँ।
और मैं इसके बजाय यह कर सकता हूँ: "for int i equals 0, i less than 3, i plus plus"।
और फिर यहाँ नीचे, मैं उद्धरण चिह्नों में "meow" छाप सकता हूँ।
और अगर सिर्फ़ इसलिए कि इस बार मैंने कम कुंजियाँ दबाईं, तो यह थोड़ा अच्छा लगता है। इसे बनाना थोड़ा ज़्यादा कसा हुआ और कुशल है, भले ही असर वही है।
असल में, जब मैं इस cat को "make" करता हूँ और आख़िरी बार "dot slash cat" करता हूँ, तो यह भी मुझे तीन "meow" देता है।
हमेशा के लिए: अनंत लूप
तो क्या ग़लत हो सकता है?
कभी-कभी आप कोई चीज़ हमेशा के लिए करने को प्रेरित हो सकते हैं। और हमने Scratch में यह किया होगा। और असल में, हमने तब किया था जब कुछ चीज़ें दीवारों से इधर-उधर टकराकर उछल रही थीं, वग़ैरह।
आप कोड में भी वही चीज़ पा सकते हैं।
असल में, C में हम "while" लूप इस्तेमाल कर सकते हैं। लेकिन "forever" ब्लॉक जैसा कुछ नहीं है। इसलिए "while" काफ़ी है।
लेकिन याद कीजिए कि "while" लूप को एक बूलियन एक्सप्रेशन की ज़रूरत होती है। और अगर मैं कुछ हमेशा के लिए करना चाहता हूँ, तो मुझे यहाँ असल में एक ऐसा एक्सप्रेशन चाहिए जो हमेशा सही हो।
तो मैं कुछ बेवक़ूफ़ाना और मनमाना कर सकता हूँ, जैसे "while 2 is greater than 3" या "while 1 is less than 2"। मेरा मतलब है, ऐसा तथ्य-कथन बनाना जो कभी न बदले। इसलिए यह बस हमेशा चलता रहेगा।
while true
लेकिन अगर पूरा लक्ष्य ही कुछ हमेशा के लिए करना है, और इस बूलियन एक्सप्रेशन को सही बनाना है, तो प्रोग्रामिंग में परंपरा यह है कि बस सचमुच "while true" लिख दिया जाए।
और इसका मतलब, और कार्यात्मक रूप से अर्थ, यह है कि आप यह काम हमेशा के लिए करेंगे, जब तक कि आप किसी तरह उन घुँघराले कोष्ठकों से समय से पहले बाहर न निकल जाएँ। उस पर जल्दी ही और बात होगी।
तो अगर मैं हमेशा "meow" करना चाहता हूँ, तो मैं अब बस यह कर सकता हूँ। और यह एक अनंत, जान-बूझकर बनाया गया लूप होगा।
लेकिन किसी खेल के उलट, जहाँ आप चाह सकते हैं कि वह कुछ देर तक चलता रहे, चलता रहे, चलता रहे, मुझे पक्का नहीं कि यह हमारे लिए सबसे अच्छी चीज़ होगी।
चलिए इसे आज़माते हैं।
बिल्ली का अनंत "म्याऊँ"
तो मैं यहाँ पूरी तसल्ली के लिए CS50 की लाइब्रेरी शामिल करता हूँ, बस इसलिए कि वह भी हमें "bool" जैसी सुविधाएँ देती है।
यहाँ मैं "while true" कहूँगा। और फिर अपने घुँघराले कोष्ठकों के अंदर मैं बस "meow" छापूँगा। चलिए, backslash n, सेमीकोलन।
चलिए यहाँ आख़िरी बार "make cat" करते हैं।
मैं यहाँ "dot slash cat" करता हूँ। और यह उस चिढ़ाने वाले बिल्ली के खेल जैसा है, बस "meow, meow, meow" बिना रुके, अंतहीन।
मैंने अब अपनी टर्मिनल विंडो पर एक तरह से नियंत्रण खो दिया है।
और मेरी बात याद रखिए: किसी मोड़ पर आप भी यह कर सकते हैं।
ब्रेक के बाद: Control C
लेकिन चलिए एक रसीला 10 मिनट का ब्रेक लेते हैं। बाहर ट्रांसेप्ट में कुछ स्वादिष्ट ब्लूबेरी मफ़िन हैं। 10 मिनट में वापस आइए। और हम पता लगाएँगे कि इस बिल्ली को यहाँ कैसे रोकना है।
ठीक है, तो लगभग 10 मिनट हो गए हैं। और VS Code जैसे घबरा रहा है: "Codespace में ऊँचा CPU इस्तेमाल पाया गया। सर्वोत्तम अनुभव के लिए कुछ प्रक्रियाओं (प्रोसेस) को रोकने पर विचार करें।"
तो यह वही है जो होता है जब आपके पास जान-बूझकर या अनजाने में कोई अनंत लूप हो, क्योंकि मैं बिना रुके "meow" छापता रहा हूँ।
और मेरे सहकर्मी ने मुझे चेताया था कि मुझे इसे बहुत देर तक चलने नहीं देना चाहिए, क्योंकि हो सकता है हम पूरे माहौल पर से नियंत्रण ही खो दें।
लेकिन इसे हल करने का जवाब "Control C" है।
तो कुछ रहस्यमय कुंजी-संयोजन हैं जिनका इस्तेमाल आप आम तौर पर इस तरह चीज़ों को रोकने (इंटरप्ट करने) के लिए कर सकते हैं।
और असल में, अगर मैं वापस जाऊँ, तो आप देखेंगे कि मैंने अपने Codespace पर एक तरह से नियंत्रण खो दिया है। मैं पूरी विंडो को ही दोबारा लोड करने की कोशिश करता हूँ।
लेकिन अगर मैंने समय पर "Control C" दबाया होता, उम्मीद है कि यह अब पटरी से न उतरे, तो "Control C" हमारा दोस्त होता।
वाह, हम वापस आ गए।
ठीक है, अब बिल्ली को थोड़ा गतिशील बनाना
ठीक है, तो अब जब हमें अपने तथाकथित Codespace पर दोबारा नियंत्रण मिल गया है, तो हम अपने "meow" करने वाले प्रोग्राम को थोड़ा ज़्यादा गतिशील कैसे बना सकते हैं?
तो चलिए उपयोगकर्ता से पूछना शुरू करते हैं कि वे बिल्ली से कितनी बार "meow" करवाना चाहते हैं। निश्चित रूप से अनगिनत बार करने के बजाय, और यहाँ तक कि सिर्फ़ तीन बार करने के बजाय।
मुझे लगता है कि अब तक हमारे पास ये सभी निर्माण-खंड हैं।
तो मैं cat.c में ही रहता हूँ और अपने main फ़ंक्शन की सामग्री का मुख्य भाग हटा देता हूँ।
और चलिए यह करते हैं। मैं अपने लिए एक "int" बनाता हूँ, और उसका नाम "n" रखता हूँ, यानी number (संख्या) के लिए। हालाँकि अगर मैं चाहता तो इससे ज़्यादा लंबा नाम रख सकता था।
मैं उसे "get int" की तथाकथित रिटर्न वैल्यू के बराबर रखता हूँ, जो, याद कीजिए, उपयोगकर्ता से एक इंटीजर लेगा।
और उद्धरण चिह्नों में, चलिए उपयोगकर्ता से पूछते हैं: "What's n?" ठीक वैसे ही जैसे मैंने पहले पूछा था "What's x?" और "What's y?", जहाँ n वह संख्या है कि मैं बिल्ली से कितनी बार "meow" करवाना चाहता हूँ।
for लूप में n का इस्तेमाल
अब मैं इस वेरिएबल का इस्तेमाल कैसे कर सकता हूँ?
तो हमारे पास वह निर्माण-खंड भी है। मैं "while" लूप या "for" लूप इस्तेमाल कर सकता हूँ।
और अगर मैं "for" लूप इस्तेमाल करूँ, तो मैं यह कर सकता हूँ। मैं इंटीजर के लिए एक वेरिएबल "i" शुरू कर सकता हूँ और उसे शुरू में 0 के बराबर रख सकता हूँ।
फिर मैं "i less than" कर सकता हूँ, इस बार 3 नहीं, बल्कि "n"।
तो मैं उस वेरिएबल को लूप के अंदर एक प्लेसहोल्डर के रूप में इस्तेमाल कर सकता हूँ, यह बताने के लिए कि मैं यह 3 की जगह n बार करना चाहता हूँ।
और इस लूप के हर चक्र में मैं "i plus plus" कर सकता हूँ।
बेशक, अगर मैं चाहूँ तो दस्तावेज़ीकरण का इस्तेमाल करके नीचे की ओर भी गिन सकता था। लेकिन तर्क के हिसाब से मैं कहूँगा कि यह प्रामाणिक (canonical) तरीक़ा है: 0 से शुरू करें और उस क़ीमत तक ऊपर जाएँ, पर उस तक पहुँचें नहीं, जिसकी आपको असल में परवाह है।
और अब मैं उद्धरण चिह्नों में "meow" backslash n सेमीकोलन छापता हूँ। वापस अपने टर्मिनल पर आता हूँ।
फिर से "make cat", "dot slash cat", एंटर।
इस बार मुझसे "n" पूछा जाता है। मैं अब भी 3 दे सकता हूँ। और इस बार मुझे 3 "meow" मिलेंगे।
लेकिन अगर मैं इसे "dot slash cat" से फिर चलाऊँ और कोई अलग इनपुट दूँ, जैसे 4, तो ज़ाहिर है मुझे इसके बजाय 4 "meow" मिलेंगे।
get_int मेरे लिए क्या करता है
अब, "get int" मेरे लिए क्या कर रहा है?
तो वह कुछ चीज़ें करता है, जैसे "get char" मेरे लिए कुछ चीज़ें करता है।
उदाहरण के लिए, मान लीजिए कि इस सवाल का सही जवाब एक संख्या n देने के बजाय मैं कुछ यादृच्छिक कहता हूँ, जैसे "dog"। वह इंटीजर नहीं है।
और इसलिए "get int" फ़ंक्शन इस तरह बना है कि वह उपयोगकर्ता के इनपुट को अपने-आप अस्वीकार कर देता है और बस बार-बार, बार-बार दोबारा पूछता है।
मैं "bird" आज़मा सकता हूँ, और वह फिर यही करेगा।
तो "get int" के अमल (इम्प्लीमेंटेशन) में कहीं एक लूप है जो हमने लिखा है और जो आपके लिए इस तरह की त्रुटि-जाँच करता है।
सीमा: ऋणात्मक संख्या
लेकिन वह सब कुछ नहीं करता, क्योंकि इंटीजर संख्याओं की एक काफ़ी व्यापक श्रेणी है। यह ऋणात्मक अनंत से लेकर धनात्मक अनंत तक है, और यह बहुत सारी संभावनाएँ हैं।
लेकिन मान लीजिए मैं उनमें से कुछ संभावनाएँ नहीं चाहता। मान लीजिए बिल्ली से ऋणात्मक एक बार "meow" करने को कहने का कोई मतलब नहीं है, और फिर भी प्रोग्राम उसे स्वीकार कर लेता है।
वह कुछ नहीं करता, या कुछ ग़लत नहीं करता। लेकिन मुझे लगता है कि एक बेहतर डिज़ाइन वाला प्रोग्राम कहेगा: "नहीं, नहीं, नहीं। ऋणात्मक एक का कोई मतलब नहीं है। इसके बजाय 0, या 1, या 2, या ज़्यादा बार 'meow' करते हैं।"
तो मैं अपनी कुछ ख़ुद की त्रुटि-जाँच जोड़ना कैसे शुरू करूँ, और उपयोगकर्ता को उस प्रकार का इनपुट देने के लिए कैसे मजबूर करूँ जो मैं चाहता हूँ?
एक कमज़ोर तरीक़ा: दोबारा पूछना
तो मैं अपनी टर्मिनल विंडो साफ़ करता हूँ और अपने कोड में वापस ऊपर जाता हूँ।
और क्यों न मैं कुछ ऐसा करूँ?
"n" लेने के बाद, चलिए बस जाँचते हैं कि क्या n शून्य से छोटा है, क्योंकि अगर हाँ, तो मैं उपयोगकर्ता से दोबारा पूछना चाहता हूँ।
और मैं उपयोगकर्ता से दोबारा ऐसे पूछ सकता हूँ: "n equals get int", उद्धरण चिह्नों में "What's n?" प्रश्नचिह्न, सेमीकोलन।
वेरिएबल बनाना बनाम दोबारा इस्तेमाल करना
अब, यहाँ क्या हो रहा है?
तो पंक्ति छह पर मैं दो काम कर रहा हूँ। मैं उपयोगकर्ता से एक इंटीजर ले रहा हूँ, और मैं उसे सिर्फ़ वेरिएबल n में सँभालकर नहीं रख रहा, बल्कि तकनीकी रूप से वेरिएबल n को बना भी रहा हूँ।
तो मैंने इसे पहले बताया नहीं था, लेकिन पंक्ति छह पर, जब आप किसी वेरिएबल का प्रकार और वेरिएबल का नाम बताते हैं, तो आप कंप्यूटर की मेमोरी में कहीं वह वेरिएबल बना रहे होते हैं।
और C में प्रकार बताना ज़रूरी है।
लेकिन अगर वेरिएबल पहले से मौजूद है, और आप बस उसे दोबारा इस्तेमाल करना और बाद में बदलना चाहते हैं, तो पंक्ति नौ की तरह बस उसे उसके नाम से बताना काफ़ी है।
प्रकार को फिर से बताना एक तरह से बेवक़ूफ़ाना होगा, क्योंकि C को पहले से पता है कि वह किस प्रकार का है, क्योंकि आपने पंक्ति छह पर C को बता दिया था कि वह क्या है।
इसीलिए पंक्ति छह और नौ थोड़ी अलग हैं।
यह तरीक़ा काम नहीं करता
तो देखते हैं कि अब यह कैसे काम करता है।
मैं अपनी टर्मिनल विंडो में वापस जाता हूँ और इस cat को दोबारा बनाता हूँ।
मैं फिर से "dot slash cat" करता हूँ। मैं सहयोग न करते हुए फिर से ऋणात्मक एक टाइप करता हूँ।
और ध्यान दीजिए कि इस बार मुझसे दोबारा पूछा गया है।
ठीक है, ठीक है, ठीक है। चलिए तीन टाइप करते हैं, और अब यह काम करता है।
लेकिन आप शायद तार्किक रूप से देख सकते हैं कि यह कहाँ जा रहा है।
मैं इसे फिर से चलाता हूँ: "dot slash cat", ऋणात्मक एक टाइप करता हूँ, ऋणात्मक एक टाइप करता हूँ, और, हम्म, इसने मुझसे फिर नहीं पूछा।
लेकिन यह कोड के अनुरूप है। अगर मैं अपनी टर्मिनल विंडो यहाँ छिपा दूँ, तो आप देखेंगे कि मेरे पास इस सवाल का सही जवाब देने के लिए एक, या शायद दो, कोशिशें हैं। और उसके बाद मुझसे और नहीं पूछा जाता।
दोहराव बढ़ता जाएगा, यह बुरा तरीक़ा है
अब, आप कल्पना कर सकते हैं कि यह शायद इसे करने का सबसे अच्छा तरीक़ा नहीं है, अगर मैं पंक्ति नौ के अंदर जाऊँ और फिर कर्सर नीचे ले जाकर कहूँ: ठीक है, तो अगर n अब भी शून्य से छोटा है, तो चलिए फिर से "getInt" करते हैं और पूछते हैं "What's n?" प्रश्नचिह्न।
और अरे, ठीक है, अगर वह अब भी शून्य से छोटा है, तो चलिए बस वही पूछते रहते हैं।
यह बुरा क्यों है?
मैं ख़ुद को दोहरा रहा हूँ। मैं असल में कॉपी-पेस्ट कर रहा हूँ, भले ही मैं दोबारा टाइप कर रहा हूँ।
मेरा मतलब है, यह कभी ख़त्म ही नहीं होता। जैसे आप उपयोगकर्ता को कितने मौक़े देंगे?
भावना में, आप उम्मीद करेंगे कि वे इतनी बार असहयोग न करें। लेकिन असल में इसे सही तरीक़े से करने के लिए, हमें शायद उनसे उतनी बार पूछना चाहिए जितनी बार भी सही इनपुट पाने में लगे।
तो यह वह रास्ता नहीं है जिस पर हमें जाना चाहिए।
लूप में सवाल को दोहराना
लेकिन बेशक, हमारे पास अब तक पहले से लूप की धारणा है। तो हम इसे एक लूप में कर सकते हैं: सवाल एक बार पूछें, और शायद बस वही सवाल बार-बार दोहराएँ।
तो मैं यह कैसे कर सकता हूँ?
मैं यह सब हटा देता हूँ। और मैं बस इसे तार्किक रूप से लिखकर दिखाने की कोशिश करता हूँ।
तो मैं उपयोगकर्ता से एक वेरिएबल n लेना चाहता हूँ। और चलिए इस तरह आगे बढ़ते हैं।
"while true": मुझे अब अनंत लूप बनाना आता है। और भले ही उसने मेरे लिए बिल्ली के साथ एक समस्या खड़ी की, मुझे यक़ीन है कि हम लूप को समय से पहले इस तरह रोक सकते हैं, जैसा मैंने पहले प्रस्ताव रखा था।
मैं यह कर सकता हूँ: "int n equals get int", और उपयोगकर्ता से फिर पूछिए: "What's n?" प्रश्नचिह्न।
continue और break
और फिर मैं कुछ ऐसा कर सकता हूँ।
अगर n शून्य से छोटा है, तो, पता है क्या? बस उसी लूप में आगे बढ़ते जाइए।
वरना, अगर ऐसा नहीं है कि n शून्य से छोटा है, तो मैं क्या करना चाहता हूँ? मैं इस लूप से बाहर निकलना चाहता हूँ।
तो यह नया सिंटैक्स है। यह कुछ ऐसा है जो आप कर सकते हैं और देख सकते हैं। जहाँ अगर n शून्य से छोटा है, ठीक है, "continue" का मतलब है लूप की शुरुआत में वापस जाओ और ठीक वही चीज़ फिर से करो।
वरना, अगर आप इसके बजाय "break" कहें, तो उसका मतलब है लूप से बाहर निकल जाओ और उस लूप से जुड़े जिस भी घुँघराले कोष्ठक के नीचे, वहाँ जाओ।
तो "continue" असल में आपको ऊपर ले जाता है। "break" आपको नीचे ले जाता है, कहें तो।
undeclared identifier: एक त्रुटि
तो तार्किक रूप से, मुझे लगता है यह सही है। लेकिन यह कोड, अजीब बात है, ठीक से काम नहीं करेगा और मुझे n की क़ीमत नहीं देगा।
मैं अपनी टर्मिनल विंडो दोबारा खोलता हूँ। चलिए इस cat को "make" करते हैं।
और, हम्म: "cat.c पंक्ति 19, अक्षर 25 पर त्रुटि है: use of undeclared identifier n", यानी बिना घोषित किए पहचानकर्ता n का इस्तेमाल।
इसका क्या मतलब है?
फिर से, cat.c की पंक्ति 19। मैं अपनी टर्मिनल विंडो छिपाता हूँ और पंक्ति 19 को हाइलाइट करता हूँ।
पंक्ति 19 में n का इस्तेमाल हो रहा है। लेकिन मैंने उसे पंक्ति 8 में बनाया था। तो समस्या क्या है? वह ऊपरी तौर पर घोषित क्यों नहीं है?
(छात्र) क्योंकि आप n का इस्तेमाल उस लूप के भीतर कर रहे हैं जो आपने लिखा।
स्कोप (दायरा)
हाँ। यह एक बारीक बात है, लेकिन मैं इस लूप के अंदर n बना रहा हूँ। मेरा मतलब है, सचमुच पंक्ति 7 और 17 पर घुँघराले कोष्ठकों के बीच।
इसका निहितार्थ, C के काम करने के तरीक़े के कारण, यह है कि वह वेरिएबल केवल उस लूप के अंदर ही मौजूद है।
यह उस चीज़ की समस्या है जिसे "स्कोप" (scope, दायरा) कहते हैं।
वेरिएबल n सिर्फ़ उस while लूप के स्कोप के अंदर मौजूद है जिसमें उसे घोषित किया गया था।
n को लूप के बाहर घोषित करना
तो मैं इसे असल में कैसे ठीक करूँ?
तो मुझे तार्किक रूप से किसी तरह उस वेरिएबल n को लूप के बाहर घोषित करना होगा, ताकि वह प्रोग्राम में आगे भी मौजूद रहे।
और इसे ठीक करने के कुछ अलग तरीक़े हैं। लेकिन सबसे अच्छा तरीक़ा शायद यह है कि n की घोषणा को, यानी n के बनाए जाने को, घुँघराले कोष्ठकों के बाहर ले जाया जाए। और शायद उसे यहाँ पंक्ति 5 के नीचे, एक तरह से ठूँस दिया जाए। यानी अब भी main के अंदर, जो भी वह है, उस पर अगले हफ़्ते और बात होगी, लेकिन बाक़ी सब चीज़ों के साथ उन्हीं घुँघराले कोष्ठकों में।
तो मैं असल में यह कर सकता हूँ। और यहीं सिंटैक्स थोड़ा अलग हो जाता है।
मैं इसे बहुत सरलता से इस तरह हल कर सकता हूँ: मैं एक नई पंक्ति 6 पर जाकर बस "int n" सेमीकोलन कहूँ। और बस इतना ही।
यह "n" नाम के एक वेरिएबल की घोषणा करता है। यह "n" नाम का एक वेरिएबल बनाता है। और शुरू में यह उसे कोई क़ीमत नहीं देता। तो कौन जाने उसमें क्या है, इस पर फिर कभी बात होगी।
लेकिन अब पंक्ति 9 पर मुझे उसे दोबारा बनाने की ज़रूरत नहीं है। मुझे बस उसे एक क़ीमत देनी है।
n अब पूरे कोड में उपलब्ध है
और क्योंकि अब n घोषित हो चुका है, पंक्ति 6 पर, और घुँघराले कोष्ठकों के बीच, पंक्ति 5 से लेकर नीचे पंक्ति 24 तक, इसलिए अब n मेरे लिखे इस पूरे कोड के लिए "स्कोप में" है, कहें तो।
तो मैं अपनी टर्मिनल विंडो दोबारा खोलता हूँ और वह पुरानी त्रुटि साफ़ करता हूँ।
मैं फिर से "make cat" करता हूँ। अब त्रुटि संदेश चला गया है।
मैं "dot slash cat" करता हूँ। "What's n?"
अब हम फिर काम पर हैं, और मैं "meow meow meow" के लिए 3 दे सकता हूँ।
लूप में बार-बार पूछना
लेकिन इससे भी बेहतर, क्योंकि अब मैं एक लूप के अंदर हूँ, देखिए कि मैं ऋणात्मक 1, ऋणात्मक 1, ऋणात्मक 1, ऋणात्मक 1, ऋणात्मक 2, ऋणात्मक 3, ऋणात्मक 50 दे सकता हूँ।
आख़िर में, मैं 3 जैसी किसी चीज़ से सहयोग कर सकता हूँ।
और क्योंकि मैं एक लूप में हूँ, जो डिज़ाइन से ही अनंत बार चल सकता है, जब तक उपयोगकर्ता असल में सहयोग न करे और मुझे उसी लूप से बाहर निकलने न दे।
continue और break दोनों ज़रूरी नहीं
अब, कड़ाई से कहें तो मुझे "continue" और "break" दोनों की ज़रूरत नहीं है। मैं दिखाना चाहता था कि दोनों मौजूद हैं। लेकिन यह उतने कोड का लगभग दोगुना है जितने की मुझे असल में ज़रूरत है।
अगर तार्किक रूप से मैं बस इस लूप से तभी बाहर निकलना चाहता हूँ, यानी "अगर और केवल अगर" n शून्य से बड़ा या उसके बराबर है, क्योंकि मैं 0 बार "meow" के विचार से तो सहज हूँ, लेकिन ऋणात्मक का कोई मतलब नहीं है, तो मैं बस तर्क को पलट सकता हूँ।
मैं कह सकता हूँ: अगर n शून्य से बड़ा या बराबर है, तो आगे बढ़कर "break" करो।
और मैंने कोड को और कस दिया है।
मैं तकनीकी रूप से कुछ और भी कर सकता था। मैं ऐसा कुछ कह सकता था: "if n is less than 0", लेकिन एक मिनट रुकिए, मैं तो उसे उलटना (गेट करना) चाहता था।
आप इस तरह की तरकीबें शुरू कर सकते हैं: एक विस्मयादिबोधक चिह्न और कुछ अतिरिक्त कोष्ठक, ताकि आप तर्क को उलट सकें। यह पहले से ही पढ़ने में थोड़ा कठिन होगा, भले ही वह तार्किक रूप से सही हो।
मैं बस पहले की तरह और स्पष्ट रूप से कहूँगा: अगर n शून्य से बड़ा या बराबर है, तो इस लूप से बाहर निकल जाओ।
do while लूप
तो यह अनंत लूप का इस्तेमाल करने का एक तरीक़ा है।
लेकिन पता चलता है कि एक और रचना (कंस्ट्रक्ट) है जो आप पूरी तरह कर सकते हैं, जो C की एक ख़ूबी है।
"while true" का इस्तेमाल करके "while" लूप को अनंत बनाने और फिर अंत में हाथ से उससे बाहर निकलने के बजाय, एक पूरी तरह अलग प्रकार का लूप मौजूद है, जिसे "do while" लूप कहते हैं।
और आप सचमुच "do" शब्द कह सकते हैं, जिसका मतलब है "यह करो"। फिर आप ठीक वही कर सकते हैं जो हमने पहले किया था: "n equals get int", उद्धरण चिह्नों में "What's n?" प्रश्नचिह्न।
तो बिल्कुल पहले जैसा। लेकिन फिर उन घुँघराले कोष्ठकों के बाद, आप "while" कीवर्ड इस्तेमाल करते हैं। यानी लूप की शुरुआत की जगह अंत में। और वहीं आप अपना बूलियन एक्सप्रेशन रखते हैं।
मैं यह सब तब तक करना चाहता हूँ जब तक n शून्य से छोटा है।
do while और while में फ़र्क़
तो आप एक तरह से तर्क को उलट सकते हैं और अब चीज़ों को और कस सकते हैं, बस कंप्यूटर से यह कहकर: "यह करो।" यह क्या? उन घुँघराले कोष्ठकों के बीच की हर चीज़, जब तक n शून्य से छोटा है।
और यह निहित रूप से सारे "continue" और सारे "break" को सँभाल लेता है, बस वही करके जो आपने कहा: "यह तब तक करो जब तक यह सही है।"
लेकिन इस "do while" लूप और सामान्य "while" लूप में फ़र्क़ सचमुच यह है कि शर्त ऊपर की जगह नीचे जाँची जाती है।
तो जब आप "while" कोष्ठक और कुछ कहते हैं, तो वह सवाल पहले पूछा जाता है और फिर शायद आप आगे बढ़ते हैं।
यह शर्त बिल्कुल अंत में ही पूछी जाती है।
और यह उपयोगी क्यों है?
अक्सर ऐसे प्रोग्राम लिखते समय जहाँ आप कुछ कम से कम एक बार करना चाहते हैं, जैसे आप ज़ाहिर है उपयोगकर्ता से यह सवाल कम से कम एक बार पूछना चाहते हैं, तब "while true" या किसी और "while" जैसा सवाल पूछने का कोई मतलब नहीं है। आपको बस उसे कर देना चाहिए।
और फिर आपको उसे दोबारा तब करना चाहिए अगर वह एक्सप्रेशन "सही" निकले और आपको कुछ करने को कहे।
एक मज़ाक़ (मीम)
अब, आपने अब तक इन लूपों के साथ शायद खेला नहीं है, जब तक आपने पहले प्रोग्रामिंग न की हो।
इस पल के लिए एक मज़ेदार तरह का मीम है।
तो देखते हैं कि क्या इससे थोड़ी हँसी निकलती है।
अगर आपको "Looney Tunes" याद है, तो यह जानकार लोगों के लिए मज़ेदार है।
(स्क्रीन पर मीम दिखाया जाता है।)
धन्यवाद।
ठीक है, इसका अभी कोई मतलब नहीं है। आख़िर में होगा।
और हो सकता है अब भी मज़ेदार न लगे, लेकिन कम से कम इसका मतलब समझ आएगा।
और यह "do while" लूप का अंतर दिखाता है। जैसे रोड रनर रुक रहा है क्योंकि वह शर्त जाँच रहा है: "जब तक किनारे पर नहीं हूँ, मैं दौड़ूँगा।" लेकिन अगर वह किनारे पर है, तो वह आगे नहीं बढ़ेगा।
लेकिन बेशक, यहाँ कोयोट (भेड़िया-सा जानवर) चाहे जो हो दौड़ेगा, और फिर बहुत देर से ही जाँचेगा। "हा हा, मैं अब भी किनारे पर हूँ।"
ठीक है, तो अहा, धन्यवाद।
ठीक है, अब आप ठंडे हो गए।
ठीक है, तो इसके नतीजे के रूप में अब और भी कई मीम समझ में आएँगे।
अपना ख़ुद का फ़ंक्शन बनाना
लेकिन चलिए इस कोड पर दोबारा नज़र डालते हैं और शायद यहाँ कुछ थोड़ा अलग करते हैं। जहाँ हम अब इन कंडीशनलों और लूपों के साथ बस इधर-उधर छेड़खानी नहीं करना चाहते।
चलिए सॉफ़्टवेयर को सचमुच थोड़ा बेहतर डिज़ाइन करते हैं।
और ऐसा करने के लिए, हम एक ऐसे विचार पर दोबारा आएँगे जिसे हमने पिछले हफ़्ते छुआ था और जिसका प्रॉब्लम सेट 0 से लेना-देना था: अपना ख़ुद का फ़ंक्शन बनाओ।
जैसे C में वह सब कुछ नहीं आता जो आप चाहेंगे। CS50 की लाइब्रेरी में भी वह सब कुछ नहीं आएगा जो आप चाहेंगे।
और दिन के अंत में, प्रोग्रामिंग का बहुत बड़ा हिस्सा अपने विचारों को "अमूर्त" करना (abstracting away) है, ताकि आप एक समस्या एक बार हल करें और फिर उसे बार-बार, बार-बार दोबारा इस्तेमाल करें।
और अरे, आप उसे एक तथाकथित लाइब्रेरी में पैक भी कर सकते हैं, जैसी हमारे पास है, और दूसरे लोगों को भी उसका इस्तेमाल करने दे सकते हैं।
Scratch में "meow" ब्लॉक
तो यहाँ, उदाहरण के लिए, Scratch में हम "meow" करने की धारणा इस तरह लागू कर सकते थे: बिल्ली से "meow until done" ध्वनि बजवाकर।
हमने उसे अमूर्त कर दिया, और फिर हमारे पास "meow" नाम का एक जादुई नया पहेली-टुकड़ा था।
C में यह आज थोड़ा अजीब होगा, लेकिन अगले हफ़्ते ये ब्योरे ज़्यादा समझ में आने लगेंगे।
आप इसके बजाय यह करेंगे: सचमुच "void" टाइप करें, फिर उस फ़ंक्शन का नाम जिसे आप बनाना चाहते हैं, और फिर कोष्ठकों में दोबारा "void"।
void का मतलब
अभी के लिए, इतना जान लीजिए कि यह फ़ंक्शन की रिटर्न वैल्यू है। तो "void" का मतलब है कि वह कुछ वापस नहीं देता।
और यह फ़ंक्शन का इनपुट, यानी उसके आर्ग्युमेंट हैं। "void" का मतलब है कि वह कोई इनपुट नहीं लेता।
और यह तर्कसंगत है, क्योंकि सचमुच "meow" कुछ वापस नहीं देता। वह कुछ लेता नहीं है। वह बस "meow" करता है।
उसका एक तथाकथित साइड इफ़ेक्ट है, पिछले हफ़्ते सुनाई देने वाला।
तो इसका मतलब है: "अरे देखो, 'meow' नाम का एक फ़ंक्शन गढ़ो जो कोई इनपुट नहीं लेता, कोई आउटपुट नहीं देता, लेकिन जिसका साइड इफ़ेक्ट स्क्रीन पर 'meow' छापना है।"
तीन बार meow: फ़ंक्शन के साथ
इस बीच, अगर मैं पिछले हफ़्ते कोड में कुछ ऐसा करना चाहता जहाँ मैंने तीन बार "meow" किया, तो वह ठीक है। हमारे पास इसके लिए निर्माण-खंड हैं।
और यहीं से अपना ख़ुद का फ़ंक्शन बनाना ज़्यादा प्रभावशाली लगने लगता है।
अब मैं "meow" करने की धारणा को अमूर्त कर सकता हूँ। यह C के साथ नहीं आता। यह CS50 की लाइब्रेरी के साथ नहीं आता। मैंने पिछले कोड में यह "meow" फ़ंक्शन अभी-अभी बनाया है।
तो मैं एक "for" लूप और उस नए फ़ंक्शन से तीन बार "meow" को कोड कर सकता हूँ।
इनपुट लेने वाला meow(n)
लेकिन मैं इसे और अमूर्त कर सकता हूँ।
पिछली बार Scratch में हमने जिसे सुधार (refinement) कहा था, वह यह था: मैं उस नए फ़ंक्शन को संपादित कर सकता था, और मैं कह सकता था कि वह असल में एक इनपुट लेता है, जिसे आर्ग्युमेंट भी कहते हैं, "n" नाम का।
और मैंने साफ़ किया कि इसका मतलब है कुछ संख्या में बार "meow" करना। और फिर उन Scratch ब्लॉकों के अंदर, मैंने "meow" करने का काम n बार दोहराया।
तो C में मैं बिल्कुल वही चीज़ पा सकता हूँ, भले ही वह थोड़ी ज़्यादा रहस्यमय दिखेगी।
लेकिन "meow" अब भी कुछ वापस नहीं देता। उसका एक सुनाई देने वाला या दिखाई देने वाला साइड इफ़ेक्ट है, लेकिन वह कोई क़ीमत वापस नहीं देता।
लेकिन यह संस्करण एक इनपुट लेता है।
और यह थोड़ा अजीब लग सकता है। लेकिन बिल्कुल पहले की तरह, जब आप C में कोई वेरिएबल बनाते हैं तो आप प्रकार और नाम बताते हैं।
जब आप C में अपना ख़ुद का फ़ंक्शन बनाते हैं और वह एक या अधिक इनपुट लेता है, यानी आर्ग्युमेंट, तो आप उनका भी प्रकार और नाम बताते हैं।
वहाँ ऊपर कोष्ठकों के ठीक भीतर कोई सेमीकोलन नहीं होता। और आप अभ्यास से इस परंपरा के आदी हो जाएँगे।
लेकिन इस कोड का बाक़ी हिस्सा बिल्कुल वही है, सिवाय इसके कि तीन की जगह मैं अब "n" इस्तेमाल कर रहा हूँ।
तो फिर से, मैं बस पिछले हफ़्ते के ठीक वही विचार जोड़ रहा हूँ, भले ही इस हफ़्ते यह कहीं ज़्यादा रहस्यमय लगता है। लेकिन ज़्यादा-ज़्यादा अभ्यास से यह ज़्यादा-ज़्यादा जाना-पहचाना लगने लगेगा।
meow फ़ंक्शन को सचमुच लिखना
तो मैं इसे ख़ुद कैसे लागू करूँ?
मैं प्रस्ताव रखता हूँ कि हम कुछ ऐसा करें।
मैं VS Code पर वापस जाता हूँ, और चलिए main के अंदर लिखा ज़्यादातर कोड सचमुच हटा देते हैं।
और मैं बस थोड़ी देर के लिए मान लेता हूँ कि "meow" करना मौजूद है।
और मैं कहूँगा, पहले संस्करण के लिए: "for int i equals 0, i less than 3"। तो हम अभी इनपुट नहीं लेंगे। "i plus plus"।
और फिर मैं यहाँ कहूँगा: "meow", यही मैं चाहता हूँ कि यह फ़ंक्शन करे।
अब, अगर मैं ऊपर वापस स्क्रॉल करूँ, तो आप देखेंगे कि अभी "meow" की कोई परिभाषा नहीं है।
तो मैं उसे भी गढ़ूँगा। मैं ऊपर जाकर कहूँगा: "void meow void"।
और फिर से, यह पहला संस्करण का मतलब है: कोई इनपुट नहीं, कोई आउटपुट नहीं, बस साइड इफ़ेक्ट। और वह साइड इफ़ेक्ट बहुत सरलता से बस उद्धरण चिह्नों में "meow" छापना होगा, backslash n के साथ।
और अब, अगर मैं अपनी टर्मिनल विंडो खोलूँ, उसे पहले से साफ़ करूँ, "make cat" करूँ, अब तक सब ठीक, "dot slash cat", हम वापस काम पर हैं।
लेकिन मैंने फ़ंक्शन को अमूर्त कर दिया है।
परिभाषा को नीचे ले जाना: एक समस्या
अब, पिछले हफ़्ते की तरह, जब मैंने नाटकीय ढंग से "meow" की परिभाषा को स्क्रीन के बिल्कुल नीचे घसीटा था, बस यह बात समझाने के लिए कि आपको उसे अब देखने की ज़रूरत नहीं है, "आँख से दूर, मन से दूर", मैं यहाँ भी कुछ वैसा ही करने की कोशिश करता हूँ।
मैं उसे चुनकर हटा देता हूँ और मनमाने ढंग से बहुत, बहुत, बहुत नीचे जाता हूँ, बस नाटकीय होने के लिए, और उसे कोड की लगभग 100वीं पंक्ति के पास चिपका देता हूँ और वापस ऊपर स्क्रॉल करता हूँ।
अब, आँख से दूर, मन से दूर: मैं "meow" करने के विचार को पहले ही लागू कर चुका हूँ। हमें उसे दोबारा देखने या उसके बारे में बात करने की ज़रूरत नहीं है।
लेकिन C में एक चेतावनी है। जब मैं अब अपना टर्मिनल क्लियर करके इस cat को "make" करता हूँ, तो अब मैंने एक समस्या खड़ी कर दी है।
और ऐसा लगता है कि कोड से ज़्यादा समस्याएँ हैं।
मैं पहली ऐसी त्रुटि तक वापस ऊपर स्क्रॉल करता हूँ, और आपको यह दिखेगा: "cat.c की पंक्ति नौ पर, अक्षर नौ, एक त्रुटि है: call to undeclared function meow", और फिर कुछ काफ़ी रहस्यमय।
कंपाइलर नीचे की परिभाषा क्यों नहीं देखता
लेकिन इसका मतलब है कि "meow" को अब असली फ़ंक्शन के रूप में नहीं पहचाना जा रहा।
मैं जानता हूँ कि यह cs50.h से नहीं आता, और मैं जानता हूँ कि यह stdio.h से नहीं आता। यह तो बस वहाँ नीचे है।
लेकिन कंपाइलर यहाँ थोड़ा मूर्ख क्यों बन रहा है?
(छात्र) ...
हाँ, क्योंकि चूँकि पहला संस्करण काम कर गया था, तर्क के हिसाब से लगता है कि उसे नीचे रखना बस एक बुरा विचार था। क्योंकि C कंपाइलर काफ़ी सरल होते हैं।
जैसे वे आपके ऊपर एहसान करके फ़ाइल के बिल्कुल नीचे तक जाँचने की पहल नहीं करेंगे। वे आपको शब्दशः लेंगे।
तो अगर पंक्ति नौ तक "meow" मौजूद नहीं है, तो वह आपकी ज़िम्मेदारी है। वह एक त्रुटि है।
मुख्य फ़ंक्शन ऊपर रखने की बात
तो मैं इसे ठीक करने के लिए बस जो किया उसे पलट सकता हूँ और उसे वापस सबसे ऊपर ले जा सकता हूँ।
लेकिन मैं तर्क देता हूँ कि आम तौर पर, C प्रोग्राम लिखते समय, "main" फ़ंक्शन, जिसे मैं इस्तेमाल करता रहता हूँ और जिस पर हम अगले हफ़्ते और बात करेंगे, सचमुच आपके कोड का मुख्य हिस्सा होने के लिए है।
इसलिए यह तर्कसंगत है कि वह ऊपर होना चाहिए। क्योंकि जब आप फ़ाइल खोलते हैं, तो अच्छा लगेगा कि वह मुख्य प्रोग्राम दिखे जिसकी आपको परवाह है, यानी main फ़ंक्शन।
तो यह तर्क दिया जा सकता है कि अपने सारे फ़ंक्शनों को ऊपर रखना थोड़ा खीझ दिलाने वाला है, क्योंकि इससे main और-और नीचे धकेला जाएगा।
प्रोटोटाइप: कंपाइलर से वादा
तो इसका एक हल है।
और यह, मैं कहूँगा, एकमात्र समय है जब कॉपी-पेस्ट करना उचित है।
मैं इन ख़ाली पंक्तियों में से ज़्यादातर को हटा देता हूँ, जो बेवजह नाटकीय हैं। और उसे बस main के नीचे ले आता हूँ, जैसे यहाँ।
हल यह है कि: फ़ंक्शन की पहली पंक्ति, यानी उसका तथाकथित "सिग्नेचर" (signature), कॉपी करें। और फिर बस वही एक पंक्ति, और सिर्फ़ वही एक पंक्ति, सेमीकोलन के साथ main के ऊपर रख दें।
और इसे "प्रोटोटाइप" (prototype) कहते हैं।
तो प्रोटोटाइप कंपाइलर के लिए बस थोड़ा-सा संकेत है, एक वादा, कहें तो: "अरे कंपाइलर, 'meow' नाम का एक फ़ंक्शन मौजूद होगा। वह कोई इनपुट नहीं लेता और कोई आउटपुट नहीं देता", सेमीकोलन।
और यह भरोसे पर चलता है कि वह आगे चलकर फ़ाइल में बाद में कहीं मौजूद होगा।
यह क्यों काम करता है, इस पर हम अगले हफ़्ते और बात करेंगे, लेकिन यह कंपाइलर से एक तरह का वादा है कि वह अंत में परिभाषित हो जाएगा।
टिप्पणी (comment)
अब, मैंने यहाँ पंक्ति चार पर जो किया है, वह एक बीच की बात के रूप में, आम तौर पर "टिप्पणी" (comment) कहलाती है।
मैं बस स्क्रीन पर ठीक वही रखना चाहता था जो मैं बोल रहा था।
C में कोई भी चीज़ जो "slash slash" (//) से शुरू होती है, वह ख़ुद के लिए एक नोट है। Scratch में चिपकने वाले नोट (स्टिकी नोट) की तरह, जो सिर्फ़ इंसान के लिए है, कंप्यूटर के लिए नहीं।
और यह ख़ुद को या किसी और को याद दिलाने का तरीक़ा है कि उस पंक्ति या उन पंक्तियों में क्या हो रहा है।
लेकिन मैं इसे अभी के लिए हटा देता हूँ, क्योंकि यह ग़ैर-ज़रूरी है। क्योंकि अब अगर मैं अपने टर्मिनल पर जाऊँ और उन त्रुटियों को साफ़ करूँ, इस cat को फिर "make" करूँ, तो अब यह काम करता है, क्योंकि "meow" फ़ंक्शन ठीक वहीं परिभाषित हो गया है जहाँ उसे होना चाहिए।
meow में इनपुट जोड़ना
और अब मैं इस cat का नया संस्करण और बेहतर बना सकता हूँ।
मैं "meow" फ़ंक्शन को बदल सकता हूँ ताकि वह बार की संख्या के इनपुट के रूप में एक वेरिएबल "n" ले।
और फिर यहाँ अंदर मैं कुछ ऐसा कर सकता हूँ: मेरा "for" लूप, "for int i equals 0, i less than n, i plus plus"।
और फिर इस "for" लूप में, मैं उद्धरण चिह्नों में "meow" छाप सकता हूँ।
और फिर मुझे इसे भी बदलना पड़ेगा, क्योंकि मुझे इसे कॉपी करके दोबारा चिपकाना पड़ेगा, कहें तो, या बस हाथ से ठीक करना होगा।
लेकिन अब मैं यह सब हटा सकता हूँ और, उदाहरण के लिए, "meow 3" कर सकता हूँ।
और यह अब Scratch कोड का दूसरा संस्करण होगा, कहें तो।
"make cat" अब भी बिल्कुल वैसे ही काम करेगा: "meow meow meow"।
लेकिन अब मैंने अपना ख़ुद का फ़ंक्शन लागू किया है जो इनपुट लेता है, भले ही वह कोई आउटपुट वापस नहीं देता।
सवाल?
ठीक है, इन उदाहरणों के बारे में अभी तक कोई सवाल?
उलझन?
उपयोगकर्ता से n माँगना
ठीक है, मैं इसमें एक और ख़ूबी जोड़ता हूँ, यह दिखाने के लिए कि हम सिर्फ़ इनपुट ही नहीं ले सकते, बल्कि अगर चाहें तो आउटपुट भी दे सकते हैं।
अगर मैं इस कोड में वापस जाऊँ, तो मैं प्रस्ताव रखता हूँ कि 3 को "हार्ड कोड" करना, यानी उस पर अड़े रहना, थोड़ा मूर्खतापूर्ण है। उपयोगकर्ता से इनपुट लेना अच्छा होगा।
तो मैं यह कर सकता हूँ। मैं "int n equals get int" इस्तेमाल कर सकता हूँ और कुछ ऐसा कह सकता हूँ: "What's n?" प्रश्नचिह्न।
और फिर मैं "n" को आगे दे सकता हूँ, बस कुछ चीज़ें दिखाने के लिए।
तो एक, अब प्रोग्राम गतिशील है। मैं उपयोगकर्ता से पूछूँगा कि कितनी बार "meow" करना है। और मैं वह क़ीमत "n" आगे दूँगा।
एक जान-बूझकर उलझाने वाली बात
अब यह फ़िलहाल जान-बूझकर उलझाने वाला है, क्योंकि एक मिनट रुकिए।
मेरे पास "n" यहाँ परिभाषित है, यहाँ इस्तेमाल हुआ, फिर यहाँ दोबारा परिभाषित हुआ, और फिर यहाँ दोबारा इस्तेमाल हुआ।
तो पता चलता है कि भले ही आप "n" यहाँ ऊपर बनाएँ और "n" नाम का इस्तेमाल करें, तो भी स्कोप की उसी समस्या के कारण कोई दूसरा फ़ंक्शन उसे देख नहीं सकता।
स्कोप की गड़बड़ी: बिना इनपुट का meow
तो उदाहरण के लिए, मान लीजिए मुझे यह ठीक से याद नहीं था, और मैंने भोलेपन में बस यह कह दिया कि "void", "meow" को कोई इनपुट लेने की ज़रूरत नहीं है, क्योंकि अरे, "n" तो पहले से main में परिभाषित है।
मैं अपना टर्मिनल खोलता हूँ और उसे साफ़ करता हूँ, "make cat" करता हूँ, और देखता हूँ कि यहाँ कौन-सी त्रुटि आती है।
तो त्रुटि "cat dot", अरे, माफ़ कीजिए, मैंने यहाँ दो ग़लतियाँ कीं। मुझे ऊपर का प्रोटोटाइप भी बदलकर "void" करना होगा, जिसका मतलब है, फिर से, कि "meow" कोई इनपुट नहीं लेता।
अब मैं दोबारा "make cat" चलाता हूँ।
और यहाँ फिर से एक अघोषित पहचानकर्ता (undeclared identifier) है: "n"।
तो "cat.c" की पंक्ति 14 पर, जो यहाँ है, उसे यह पसंद नहीं कि मैं "n" इस्तेमाल कर रहा हूँ।
लेकिन एक मिनट रुकिए, मैंने "n" यहाँ बनाया था। पर पहले जैसे ही तर्क से, वह ठीक है।
आपने "n" पंक्ति 8 पर बनाया। लेकिन "n" किस स्कोप में मौजूद है?
(छात्र) सिर्फ़ घुँघराले कोष्ठकों के बीच, यानी पंक्ति 7 और 10 के बीच।
हाँ। तो जब तक आप पंक्ति 14 पर पहुँचते हैं, वह स्कोप से बाहर है, कहें तो, इसलिए यह बस काम नहीं करता।
हल: n को इनपुट के रूप में आगे देना
तो हल बिल्कुल वही है जो मैंने पहली बार किया था।
मैं उसे इनपुट के रूप में "meow" को दे सकता हूँ, और मुझे C को बताना पड़ता है कि वह उस इनपुट की उम्मीद करे।
और मैं वही नाम इस्तेमाल कर सकता हूँ। लेकिन यह तर्कसंगत रूप से कभी-कभी उलझाने वाला होने लगेगा।
तो मैं यह करता हूँ। मैं अपने कोड में वापस जाता हूँ। मैं यह बदलाव पलट देता हूँ ताकि अब "meow" इनपुट ले।
लेकिन सिर्फ़ उसे "n" कहने और संख्या के लिए हर जगह "n" इस्तेमाल करने के बजाय, यह पागलपन है, चलिए इसे बस "times" कहते हैं।
तो "meow" कुछ संख्या में "times" लेता है, और फिर वह उसी क़ीमत का इस्तेमाल करता है।
और अब मैं पंक्ति 9 पर "n" आगे दे रहा हूँ। लेकिन पंक्ति 12 से आगे के "meow" फ़ंक्शन के संदर्भ में, वही वेरिएबल "n" अब "times" कहलाता है, क्योंकि आप उसे इनपुट के रूप में आगे दे रहे हैं और उसे उसका अपना नाम दे रहे हैं।
और यह पूरी तरह आपका अधिकार है। यह बस स्कोप की बात है।
मेरा मतलब है, मैं उसे "m" या वर्णमाला का कोई और अक्षर कह सकता था। लेकिन "times" और भी साफ़ है, क्योंकि यह वह संख्या है जितनी बार मैं बिल्ली से "meow" करवाना चाहता हूँ।
लेकिन फिर से, यहाँ पूरी बात बस इसी स्कोप के मामले की है।
अच्छा कोड कैसे परखें: सहीपन, डिज़ाइन, शैली
ठीक है, तो अब चलिए कुछ चीज़ों पर एक ऊँचे स्तर से नज़र डालते हैं जिनके बारे में हम सोचते रहे हैं। और फिर हम एक-दो आख़िरी गहरी डुबकियाँ लगाएँगे, उन कुछ समस्याओं पर जिन्हें हम इन सभी निर्माण-खंडों से हल कर सकते हैं, और कुछ समस्याओं पर जिन्हें हम फ़िलहाल अनदेखा कर रहे हैं।
तो अच्छा कोड लिखने की बात आती है, तो CS50 और असल में पूरी दुनिया आम तौर पर इन तीन आयामों (axes) पर ध्यान देती है: सहीपन (correctness), डिज़ाइन (design) और शैली (style)।
इसका क्या मतलब है?
सहीपन (Correctness)
सहीपन का मतलब बस यह है कि क्या कोड वैसे ही काम करता है जैसे उसे करना चाहिए?
एक कक्षा के संदर्भ में, उसे ठीक वही करना चाहिए जो गृहकार्य, यानी प्रॉब्लम सेट, आपसे करने को कहता है।
असली दुनिया में, उसे ठीक वही करना चाहिए जो किसी ने तय किया कि सॉफ़्टवेयर को करना चाहिए: प्रोडक्ट मैनेजर, CEO या ऐसा कोई।
सहीपन का मतलब बस यह है कि वह वैसे व्यवहार करता है जैसे उसे करना चाहिए।
डिज़ाइन (Design)
लेकिन यह इससे अलग है कि कोड कितना अच्छी तरह डिज़ाइन किया गया है।
और हमने इसे कुछ बार देखा है। मेरे पास Scratch और C में कुछ सरल उदाहरण थे जो 100% सही थे। यानी तर्क के हिसाब से उन्होंने सही काम किया, लेकिन मैं कंप्यूटर का समय बर्बाद कर रहा था। मैं ज़रूरत से ज़्यादा बूलियन एक्सप्रेशन पूछकर इंसान का समय बर्बाद कर रहा था, वग़ैरह।
तो डिज़ाइन ज़्यादा इस बारे में है, जैसे अंग्रेज़ी की दुनिया में, कि सिर्फ़ सही बातें कहना नहीं, बल्कि उन्हें अच्छे ढंग से कहना। जैसे एक अच्छी, सुसंगत दलील देना, सिर्फ़ ऐसी नहीं जो संयोग से सही हो।
शैली (Style)
इस बीच, शैली वह तीसरा आयाम है जिस पर हम किसी के कोड की गुणवत्ता को परख सकते हैं, और वह ज़्यादा सौंदर्य (दिखावट) की बात है।
जैसे क्या सब कुछ सलीक़े से छपा है? यानी अच्छी तरह इंडेंट किया गया? क्या वेरिएबलों के नाम अच्छे हैं, या उन्हें बस "x, y, z" जैसा कुछ मनमाने ढंग से कहा गया है?
तो शैली असल में दूसरे इंसानों के लिए मायने रखती है, कंप्यूटर के लिए नहीं, दूसरे इंसानों के लिए।
check50, design50 और style50
और इन्हें समझाने के लिए, आप देखेंगे कि प्रॉब्लम सेट 1 से आगे आपको कई औज़ार दिए जाएँगे जिन्हें आप इस्तेमाल कर सकते हैं।
तो उन औज़ारों में से एक का नाम "check50" है।
और हर प्रॉब्लम सेट में, C और Python और दूसरी भाषाओं की हर समस्या में, आपको दिखाया जाएगा कि आप अपने ही कोड का परीक्षण कैसे कर सकते हैं।
और आप सचमुच CS50 की बनाई एक कमांड चला सकते हैं जिसका नाम "check50" है।
फिर आप एक तथाकथित "स्लग" (slug) बताएँगे, जिसका मतलब बस उस गृहकार्य की समस्या के लिए एक अनोखा पहचानकर्ता है।
और आपको जल्दी से यह फ़ीडबैक मिल जाएगा कि आपका कोड सही है या नहीं।
इसका मतलब यह नहीं कि वह अच्छी तरह लागू किया गया है, या अच्छी तरह डिज़ाइन किया गया है, या सुंदर है, यानी अच्छी शैली वाला है। लेकिन कम से कम यह अच्छा कोड जमा करने की पहली कसौटी है।
design50
लेकिन डिज़ाइन कहीं ज़्यादा व्यक्तिपरक (सब्जेक्टिव) है।
डिज़ाइन वह चीज़ है जिस पर आपको किसी इंसान से फ़ीडबैक मिलता है, उदाहरण के लिए सेक्शन में या किसी टीचिंग असिस्टेंट से, या सॉफ़्टवेयर में।
आप असल में VS Code के ऊपर देख सकते हैं कि वहाँ कुछ बटन हैं जिनका मैंने अभी इस्तेमाल नहीं किया, लेकिन कर सकता था।
"design50" CS50 डक के ऊपर बना है। इसमें अगर आपका कोई प्रोग्राम किसी टैब में खुला है और आप "design50" पर क्लिक करते हैं, तो आपको ChatGPT जैसी सलाह मिलेगी कि आप उस कोड का सहीपन नहीं, बल्कि उस कोड का डिज़ाइन, उसकी गुणवत्ता, कैसे बेहतर बना सकते हैं।
यह थोड़ा ज़्यादा व्यक्तिपरक है, और एक अच्छे टीचिंग असिस्टेंट के कहने के तरीक़े पर आधारित है।
style50
इस बीच, "style50" तीसरा औज़ार है, जो आपको आपके कोड की शैली पर फ़ीडबैक देगा।
यह आपको बाईं ओर दिखाएगा कि आपका कोड कैसा दिखता है, और दाईं ओर कि आपका कोड असल में कैसा दिखना चाहिए, ताकि वह उस चीज़ से मेल खाए जो हमने कक्षा में सिखाई है और CS50 के तथाकथित "स्टाइल गाइड" से मेल खाए।
और आप में से जिन लोगों को पहले से प्रोग्रामिंग का कुछ अनुभव है, उन्हें निस्संदेह CS50 के कुछ शैलीगत चुनाव पसंद नहीं आएँगे। और असली दुनिया में भी यही होगा।
लेकिन जैसा मैंने पहले इशारा किया था, आम कंपनियों में आपके पास एक आधिकारिक स्टाइल गाइड या औज़ार होगा जिसका सब पालन करते हैं, ताकि सबका कोड असल में बाक़ी सबके कोड जैसा दिखे, भले ही लोगों ने समस्याओं के अलग-अलग हल दिए हों।
तो सहीपन, डिज़ाइन और शैली: सिर्फ़ हम ही नहीं, बल्कि व्यापक रूप से पूरी दुनिया कोड की गुणवत्ता को इसी तरह परखती है। और हम इसे इन CS50-विशिष्ट औज़ारों के ज़रिए करते हैं।
कोड को और बेहतर बनाना: टिप्पणियाँ और get_n
ठीक है, तो इस प्रोग्राम में एक आख़िरी रंग कैसा रहेगा?
VS Code में वापस, मेरे पास अभी एक सही हल है। यह अच्छी शैली में है, मैं मान लेता हूँ, भले ही उसमें कुछ और टिप्पणियाँ हो सकती थीं।
तो उदाहरण के लिए, मैं कुछ ऐसा कर सकता हूँ: "meow some number of times", यानी अपने लिए एक टिप्पणी। या यहाँ ऊपर मैं कुछ ऐसा कह सकता हूँ: "get a number from user"।
बस ख़ुद को और अपने TA या सहकर्मी को याद दिलाने के लिए कि यह कोड क्या कर रहा है।
लेकिन डिज़ाइन के मामले में मैं और क्या कर सकता हूँ?
तो यह फ़ंक्शन "get int" मुझे सचमुच एक इंटीजर देगा, लेकिन सिर्फ़ धनात्मक या शून्य नहीं, बल्कि ऋणात्मक भी।
और मैं अंदर जाकर पहले की तरह बहुत सारा कोड जोड़ सकता हूँ, जैसे मैं असल में कर सकता था: इस पंक्ति की जगह मैं कुछ ऐसा कर सकता था: "int n" सेमीकोलन, "do" यह करो, या "n equals get int"। फिर मैं कह सकता हूँ "What's n?" प्रश्नचिह्न। और उसके बाद मैं कुछ ऐसा कर सकता हूँ: "while n is less than zero", यही करते रहो।
तो मेरे पास उपयोगकर्ता का इनपुट लेने का एक काफ़ी लंबा-चौड़ा तरीक़ा हो सकता है।
अपना ख़ुद का फ़ंक्शन: get_n
या मैं अपना ही एक और फ़ंक्शन बना सकता हूँ जो उपयोगकर्ता से सिर्फ़ धनात्मक इंटीजर या ग़ैर-ऋणात्मक इंटीजर ही लेता है।
उदाहरण के लिए, मैं कुछ ऐसा कर सकता हूँ। मैं नीचे, शायद अपने main फ़ंक्शन के नीचे, एक फ़ंक्शन घोषित कर सकता हूँ, ऐसा कि "int", कैसा रहेगा, "get n"।
और फिर इसके अंदर मैं कहूँगा "void", क्योंकि मैं कोई इनपुट आगे नहीं दे रहा।
फिर इस फ़ंक्शन के अंदर मैं "int n" करूँगा, "do", "n equals get int", उद्धरण चिह्नों में "What's n?" प्रश्नचिह्न।
और फिर यहाँ नीचे, मैं "while n is less than zero" करूँगा।
लेकिन "n" के साथ तुरंत कुछ करने के बजाय, क्योंकि मैं अब अपने तथाकथित main फ़ंक्शन के अंदर नहीं हूँ, मैं जो करूँगा, जो नया है, वह यह है कि इस क़ीमत "n" को वापस लौटाऊँगा (return करूँगा)।
return: क़ीमत वापस देना
और ध्यान दीजिए कि क़ीमत वापस लौटाने की यह धारणा, जो पहली बार मैंने साफ़ तौर पर की है, पंक्ति 19 के इस छोटे संकेत से मेल खाती है। इसका मतलब है कि यह "get n" फ़ंक्शन, जिसे मैं गढ़ रहा हूँ, "void" नहीं लौटाएगा, जिसका अर्थ "कुछ नहीं" है, बल्कि एक इंटीजर लौटाएगा।
और अब ज़िंदगी में इस फ़ंक्शन का पूरा मक़सद यही है।
अगर मैं यहाँ वापस नीचे स्क्रॉल करूँ, तो मैं कोड का यह पूरा खंड हटा सकता हूँ और बस कह सकता हूँ: "get n from the user"। और फिर मैं तुरंत उस क़ीमत के साथ "meow" को बुला सकता हूँ।
मुझे एक और काम करना होगा। मुझे कोड की इस पंक्ति को हाइलाइट करना होगा। और मैं ऊपर एक और प्रोटोटाइप जोड़ने जा रहा हूँ। यह वह एकमात्र समय है, फ़िलहाल, जब कॉपी-पेस्ट को प्रोत्साहित किया जाता है और जो करना सबसे अच्छा है।
तो मैंने अपना ख़ुद का फ़ंक्शन गढ़ा है, "get n"। पूरी बात अब यह है कि मेरे पास यहाँ एक तरह का अमूर्तन (abstraction) है, एक ऐसा फ़ंक्शन जिसका जीवन में पूरा एकमात्र मक़सद मुझे सिर्फ़ एक इंटीजर देना नहीं, बल्कि वह इंटीजर देना है जो शून्य या धनात्मक हो और ऋणात्मक नहीं।
अगर मैं अपनी टर्मिनल विंडो खोलूँ, पहले की गंदगी साफ़ करूँ, "make cat", "dot slash cat", "What's n?" 3, तो अब मैं वापस काम पर हूँ।
और फिर से, हमने असल में पिछली बार के Scratch से इस बार C में अनुवाद किया है: ठीक वैसे ही जैसे हम अब कोड को मॉड्यूलों में बाँट सकते हैं, इन निचले स्तर के ब्योरों को अमूर्त कर सकते हैं, और अंत में अपना ही फ़ंक्शन बना सकते हैं।
वह फ़ंक्शन, पहले की तरह, सिर्फ़ आर्ग्युमेंट ही नहीं लेता, बल्कि इस मामले में उसके साइड इफ़ेक्ट नहीं हैं (यानी उसका कोई साइड इफ़ेक्ट नहीं है), बल्कि इस बार उसकी एक रिटर्न वैल्यू है।
Super Mario Brothers: एक पहेली
ठीक है, तो जब आप अंदर आए थे, तब हमारे पास पुराने ज़माने के Super Mario Brothers के खेलने की एक छोटी-सी झलक थी। यह एक साइड-स्क्रॉलिंग खेल था जिसमें Mario नीचे कूदता, ऊपर-नीचे और बाएँ से दाएँ जाता, और सिक्के जमा करने और स्तर के अंत तक पहुँचने की कोशिश करता।
इस तरह के खेल में रास्ते भर कई बाधाएँ हैं, जहाँ दुनिया कुछ ऐसी दिख सकती है। जैसे यहाँ एक गड्ढा है जिसे Mario को कूदकर पार करना है, और ये सिक्के हैं जो आम तौर पर इन प्रश्नचिह्नों के पीछे छिपे होते हैं। वह कूदकर उनसे अपना सिर टकरा सकता है और असल में अंक जमा कर सकता है।
अब, हम अभी कुछ भी ग्राफ़िकल नहीं करने जा रहे। हम फ़िलहाल Scratch वाले रूप में ग्राफ़िक्स को पीछे छोड़ रहे हैं। लेकिन C से हम इनमें से कुछ विचार लागू कर सकते हैं।
चार प्रश्नचिह्न की एक पंक्ति
उदाहरण के लिए, अगर मैं सिर्फ़ चार प्रश्नचिह्नों की यह एक पंक्ति बनाने के लिए कोड लिखूँ, तो मैं कहूँगा कि हम इसे कई तरीक़ों से कर सकते हैं।
दूसरे शब्दों में, देखते हैं कि क्या हम आज के सभी निर्माण-खंडों का इस्तेमाल करके, "Mario.c" नाम की किसी फ़ाइल में, Super Mario Brothers का अपना एक छोटा-सा संस्करण बनाना शुरू कर सकते हैं।
तो मैं अपनी टर्मिनल विंडो खोलता और साफ़ करता हूँ। मैं "code Mario.c" चलाता हूँ, और चलिए बस कुछ बहुत सरल करने की कोशिश करते हैं, जैसे एक पंक्ति में चार प्रश्नचिह्न छापना।
तो इसके लिए मुझे printf चाहिए, इसलिए मैं stdio.h शामिल करूँगा। फिर मैं "int main void" करूँगा, अगली बार इस पर और बात होगी।
और main के अंदर, मेरे डिफ़ॉल्ट फ़ंक्शन में, जो पहले की तरह अपने-आप मेरे लिए बुलाया जाता है, मैं सबसे सरल संभव अमल छापूँगा: बस चार प्रश्नचिह्न ऐसे ही छाप दूँगा।
तो अभी लूप की कोई ख़ास ज़रूरत नहीं है। लेकिन मुझे लगता है कि हम उस ख़रगोश के बिल में भी उतर सकते हैं।
मैं नीचे अपनी टर्मिनल विंडो में जाता हूँ, इस संस्करण को "make Mario" करता हूँ, "dot slash Mario", एंटर, और वाह।
हमारे पास आसमान में चार प्रश्नचिह्नों का एक बहुत सादा, श्वेत-श्याम, टेक्स्ट वाला संस्करण है।
लूप से प्रश्नचिह्न छापना
अब, मैं यहाँ चार प्रश्नचिह्नों को हार्ड कोड करके थोड़ी धोखेबाज़ी कर रहा हूँ।
अगर मैं चार नहीं, बल्कि तीन, या पाँच, या कोई और संख्या चाहता तो?
तो हम यह भी एक लूप से कर सकते थे।
तो मैं इस कोड को यहाँ बदलता हूँ और कुछ ऐसा करता हूँ: "for int i equals, मान लीजिए, 0, i less than, फ़िलहाल मान लीजिए 4, i plus plus"।
फिर इस लूप के अंदर, मैं एक बार में एक प्रश्नचिह्न छाप सकता हूँ, सेमीकोलन।
अब मैं वापस नीचे जाता हूँ, इस संस्करण को "make Mario" करता हूँ, "dot slash Mario", एंटर, और वाह।
ग़लती: पंक्ति की जगह स्तंभ (column)
इस बार यह असल में सही नहीं है।
तो इस बदलाव से मुझे पंक्ति की जगह स्तंभ (खड़ी कतार) क्यों मिल रहा है?
(छात्र) ...
(छात्र) क्योंकि आपने प्रश्नचिह्न के बाद "backslash n" दिया है।
हाँ। मैंने मूर्खता से हर प्रश्नचिह्न के बाद "backslash n" शामिल कर दिया।
ठीक है, तो यह आसान सुधार लगता है। मैं इसे हटा देता हूँ।
मैं अब Mario को फिर कंपाइल करता हूँ, फिर चलाता हूँ, और अब बहुत क़रीब।
अब मैंने कुछ बेवक़ूफ़ाना कर दिया है।
ठीक है, मुझे "backslash n" चाहिए। तो मुझे लगता है कि मैं इसे यहाँ चाहता हूँ। या आप इसके बजाय क्या सुझाते हैं?
backslash n को लूप के बाहर रखना
मुझे लगता है कि मुझे "backslash n" को लूप के बाहर रखना चाहिए। यानी जब मैं सारे प्रश्नचिह्न छापना ख़त्म कर लूँ, तब मुझे "backslash n" मिले।
और वह ठीक है, भले ही हमने यह पहले नहीं देखा। "Backslash n" एक एस्केप सीक्वेंस है जिसे आप निश्चित रूप से अकेले भी छाप सकते हैं।
तो मैं उद्धरण चिह्नों में "backslash n" को लूप के बाहर, उन घुँघराले कोष्ठकों के नीचे, रखता हूँ।
अब अगर मैं "make Mario", "dot slash Mario" करूँ, तो मुझे एक पंक्ति में चार प्रश्नचिह्न मिलते हैं, और बिल्कुल अंत में नई पंक्ति भी।
तो फिर से, यह एक तरह की छोटी बच्चों वाली कसरत है। लेकिन यह दिखाती है कि आप कुछ अलग-अलग तकनीकों और कुछ अलग-अलग निर्माण-खंडों को, जिन्हें हमने इस्तेमाल किया, जोड़कर उस चीज़ का सही हल बना सकते हैं जो कुछ ही देर पहले एक बिल्कुल नई समस्या थी।
दूसरा रूप: ईंटों का स्तंभ
ठीक है, चलिए एक और आज़माते हैं।
तो Super Mario Brothers में आगे चलकर, जब आप भूमिगत दुनिया में जाते हैं, तब आप देखते हैं, या बल्कि वह अब भी ज़मीन के ऊपर है, आप ईंटों का ऐसा एक स्तंभ देखते हैं जिसे उसे कूदकर पार करना है। तो वे यहाँ हैं।
हम स्तंभ कैसे बना सकते हैं?
तो हमारे पास पहले से वह हल लगभग था। और असल में, अगर मैं यहाँ VS Code पर वापस जाऊँ और बस Mario के इस संस्करण को बदलूँ, तो मुझे लगता है कि हम इस चीज़ को काफ़ी हद तक वैसा ही डिज़ाइन कर सकते हैं।
बस "i less than 3" होगा। और मैं वहाँ अंत में "backslash n" रखना चाहता हूँ।
"make Mario", "dot slash Mario"। और भले ही यह टेक्स्ट वाला है, मेरे पास तीन का मेरा स्तंभ है। अरे, देखते हैं। मुझे प्रश्नचिह्न नहीं चाहिए।
चलिए इसे थोड़ा बेहतर बनाते हैं। शायद हम हैश चिह्न (#) इस्तेमाल करेंगे, क्योंकि वह एक तरह से वर्ग जैसा दिखता है।
तो "make Mario", "dot slash Mario"। ठीक है, अब हम वापस काम पर हैं।
तीसरा रूप: 3 गुणा 3 की ईंटों की ग्रिड
लेकिन चलिए इसे और दिलचस्प बनाते हैं, अब Mario की भूमिगत दुनिया में जाकर।
और यहाँ Mario की तीसरी और आख़िरी समस्या है, जहाँ हम यहाँ घेरे गए ईंटों की इस 3 गुणा 3 की ग्रिड जैसी चीज़ लागू करना चाहते हैं।
तो यह वाली दिलचस्प है, क्योंकि हमने कभी दो आयामों में कुछ नहीं किया है।
मैंने क्षैतिज (आड़ा) किया। मैंने ऊर्ध्वाधर (खड़ा) किया। लेकिन हमने असल में उन विचारों को एक साथ नहीं जोड़ा है।
पंक्ति-दर-पंक्ति छापना
तो मैं अब थोड़ा और ध्यान से सोचता हूँ कि मैं पंक्ति, पंक्ति कैसे छाप सकता हूँ।
और यहीं, अगर आपके मन में पुराने ज़माने के टाइपराइटरों से कुछ परिचय है, तो यह एक तरह से वही विचार है: आप ईंटों की एक पंक्ति छापना चाहते हैं, फिर शुरुआत में लौटना चाहते हैं, ईंटों की एक पंक्ति, फिर शुरुआत में लौटना, और ईंटों की एक पंक्ति।
और printf हमारे लिए हमेशा से यही तो करता आया है।
यह टेक्स्ट को पंक्ति-दर-पंक्ति-दर-पंक्ति छापता है। यह इधर-उधर कूदता नहीं है।
लूप के भीतर लूप (nested loops)
तो हम शायद इसका इस तरह फ़ायदा उठा सकते हैं।
मैं यहाँ अपने main फ़ंक्शन में जाता हूँ। और अगर मैं कोई द्वि-आयामी (दो आयाम वाली) चीज़ छापना चाहूँ, तो मैं इसे पंक्तियों और स्तंभों के रूप में सोचता हूँ।
तो शायद मैं यह कर सकता हूँ: "for int i equals 0, i less than 3, i plus plus"।
क्यों? क्योंकि मैं कोई काम तीन बार करना चाहता हूँ।
भले ही मुझे पता न हो कि मैं इस हल के साथ कहाँ जा रहा हूँ, मैं कम से कम कुछ तीन बार करना चाहता हूँ, जैसे टेक्स्ट की तीन पंक्तियाँ।
लेकिन इसका क्या? हर पंक्ति पर मैं क्या करना चाहता हूँ? मैं तीन चीज़ें छापना चाहता हूँ।
तो मैं यही विचार चुरा सकता हूँ: "int i equals 0, i less than 3, i plus plus"। और फिर इस लूप के अंदर, मैं बस एक बार में एक ईंट छापता हूँ। अभी कोई नई पंक्ति नहीं, एक बार में एक ईंट।
दोनों लूपों के वेरिएबल के नाम अलग रखें
लेकिन यहाँ थोड़ी समस्या है।
लूपों को इस तरह एक के भीतर एक रखना सही है। बाहरी लूप होना बिल्कुल ठीक है, भीतरी लूप होना बिल्कुल ठीक है।
लेकिन मैं शायद नहीं चाहता कि भीतरी लूप का वेरिएबल बाहरी लूप के वेरिएबल से होड़ करे, दोनों को एक ही नाम देकर।
और यह ठीक है। कोड में यह काफ़ी पारंपरिक है कि जब आपको दूसरा इंटीजर चाहिए, और वह "i" नहीं हो सकता क्योंकि आप उसे पहले ही इस्तेमाल कर चुके हैं, तो ठीक है, आप "j" इस्तेमाल कर सकते हैं।
तो "i", "j" और "k" इस्तेमाल करना आम तौर पर ठीक है।
अगर आप "l", "m" और "o" इस्तेमाल कर रहे हैं, तो उस मोड़ पर आप शायद कुछ ग़लत कर रहे हैं।
कोई कड़ी रेखा नहीं है, लेकिन किसी मोड़ पर यह हास्यास्पद हो जाता है, और आपको बेहतर वेरिएबल नाम सोचने चाहिए। लेकिन "i" और "j", शायद "k", ठीक है।
3 गुणा 3 की ग्रिड छापना
तो अब असल में क्या हो रहा है?
मैं प्रस्ताव रखता हूँ कि यह मेरा "हर पंक्ति के लिए" है। यह मेरा "हर स्तंभ के लिए" है। मैं एक ईंट छापना चाहता हूँ।
अब यह पूरी तरह सही नहीं है। लेकिन मैं इस संस्करण को "make Mario" करता हूँ, "dot slash Mario", और अरे, अब यह क्या है? 1, 2, 3, वहाँ नौ ईंटें हैं।
तो मैं क़रीब हूँ। इसे 3 गुणा 3, यानी कुल नौ होना चाहिए।
लेकिन इसे बिल्कुल सही बनाने के लिए मैं क्या करूँ?
(छात्र) बाईं ओर के आसपास।
हाँ, किस पंक्ति संख्या पर, या मैं नई पंक्ति कहाँ रखूँगा? क्योंकि मुझे लगता है कि मैं इसे यहाँ नहीं रखना चाहता, क्योंकि मैं पहले की तरह मुसीबत में पड़ जाऊँगा।
(छात्र) पीछे के हिस्से में कैसा रहेगा?
किसके बाद?
(छात्र) 13 के बाद।
हाँ। तो जब मैं बाईं से दाईं ओर स्तंभ की हर ईंट छापना ख़त्म कर लूँ, उसके बाद मैं यहाँ एक अकेली नई पंक्ति छापूँगा, और कुछ नहीं।
और अब अगर मैं अपना टर्मिनल खोलूँ, Mario को फिर बनाऊँ, "dot slash Mario", तो अब हमारे पास सही चीज़ है।
और यह एक पूरा वर्ग नहीं है, जैसा यह वाला (स्लाइड पर) है, क्योंकि हैश चिह्न क्षैतिज की तुलना में ज़्यादा ऊर्ध्वाधर हैं। लेकिन यह काफ़ी क़रीब है।
यहाँ से सीख यह है कि आप निश्चित रूप से इस तरह के विचारों को एक के भीतर एक रख सकते हैं और उन्हें जोड़ सकते हैं।
बेहतर नाम: row और column
और ईमानदारी से, "i" और "j" शायद इसे ज़रूरत से ज़्यादा उलझाने वाला बना रहे हैं।
मैं इन्हें बेहतर नाम दे सकता हूँ, जैसे "row, row, row", और फिर शायद "col" या "column" कहूँ। अगर साफ़ हो, तो मैं पूरा स्पेलिंग लिख सकता हूँ: "column, column"। बस ख़ुद को, अपने TA को, अपने सहकर्मियों को साफ़ करने के लिए कि ये वेरिएबल असल में क्या दर्शाते हैं।
और असल में, पुराने ज़माने के टाइपराइटर की तरह, बाहरी लूप पंक्ति-दर-पंक्ति-दर-पंक्ति सँभाल रहा है। लेकिन हर बार जब आप किसी पंक्ति पर होते हैं, तो आप पहले "column, column, column, column, column" करना चाहते हैं। और तर्क के हिसाब से यही एक के भीतर एक रखना (नेस्टिंग) हासिल कर रहा है।
और फिर से, अगर मैं "make Mario", "dot slash Mario" करूँ, तो मैंने बस वेरिएबल के नाम बदले हैं। इससे आगे कोई कार्यात्मक असर नहीं है।
हार्ड कोड किए 3 की समस्या
अब, यह थोड़ा ज़्यादा बारीक है, लेकिन इस प्रोग्राम में थोड़ा दोहराव है। थोड़ा "जादू" (अपने-आप समझ आने वाली बात) है।
और यह बारीक है, लेकिन क्या कोई अनुमान लगाना चाहता है कि यहाँ अब भी क्या सुधारा जा सकता है? शायद आपको क्या खटक रहा है?
(छात्र) आपने यहाँ और यहाँ तीन को हार्ड कोड किया है।
हाँ। यह कोई बड़ी बात नहीं है। यह कक्षा की एक कसरत जैसा है। जैसे, अगर मैं हाथ से तीन टाइप कर रहा हूँ तो किसे परवाह है?
लेकिन अगर मैं इस वर्ग को समय के साथ और-और बड़ा करना चाहूँ, तो मुझे इसे दो अलग-अलग जगहों पर बदलना पड़ेगा।
और मैंने पिछली बार और आज भी अनुमान लगाया था, कि आख़िर में यह आपको काट खाएगा। आप कुछ बेवक़ूफ़ाना कर देंगे, या कोई सहकर्मी नहीं समझेगा कि आपने तीन को कई जगह हार्ड कोड किया है। बस ख़राब डिज़ाइन।
n और const: स्थिरांक (constant)
तो हम इसे कैसे ठीक कर सकते हैं?
हम "n" जैसा कोई वेरिएबल घोषित कर सकते हैं, उसे तीन के बराबर रख सकते हैं, और फिर दोनों जगह "n" इस्तेमाल कर सकते हैं।
और यह काफ़ी अच्छा है। यह बेहतर है, क्योंकि अब हम क़ीमत को दोबारा इस्तेमाल कर रहे हैं।
लेकिन हम इससे भी एक क़दम बेहतर कर सकते हैं।
पता चलता है कि C में, और कई भाषाओं में भी, "स्थिरांक" (constant) की धारणा है।
इसमें अगर आप किसी चीज़ को वेरिएबल में रखना चाहते हैं, पर आप कंपाइलर को संकेत देना चाहते हैं कि यह क़ीमत कभी बदलनी नहीं चाहिए, और इससे भी बेहतर, आप ख़ुद को, यानी एक इंसान को, और अपने सहकर्मी को तो छोड़ ही दीजिए, इस क़ीमत को ग़लती से बदलने से रोकना चाहते हैं, तो आप इसे "constant" यानी छोटे में "const" घोषित कर सकते हैं।
तो अगर मैं अब VS Code में पंक्ति पाँच पर वापस जाऊँ और "const" कहूँ, तो इसका मतलब है कि "n" एक ऐसा इंटीजर है जिसकी क़ीमत स्थिर है।
तो अगर मैं अपने कोड में आगे चलकर कुछ बेवक़ूफ़ाना करूँ, और "n" को किसी और चीज़ के बराबर रखने की कोशिश करूँ, तो कंपाइलर मुझे ऐसा करने नहीं देगा। वह मुझे ख़ुद से बचाएगा।
तो यह भी थोड़ा बेहतर डिज़ाइन ही है।
सवाल?
ठीक है। इनमें से किसी के बारे में सवाल?
Mario। उदाहरण।
यह हमारी तरह की असली दुनिया की समस्याओं में से पहली थी, भले ही टेक्स्ट के रूप में सरल की गई।
कंप्यूटर क्या अच्छे से नहीं कर सकते: सीमाएँ
ठीक है।
अब आख़िर में, चलिए उन चीज़ों पर ध्यान दें जो हम कंप्यूटरों से असल में अच्छे से नहीं कर सकते, यानी उनकी कुछ सीमाओं पर।
अंकगणितीय ऑपरेटर
तो यहाँ उन कुछ ऑपरेटरों की चीट शीट है जो हमने अब तक देखे हैं।
हमने इनके साथ तुलना करने और कुछ जोड़ने वग़ैरह के साथ खेला है।
लेकिन यहाँ हमारे पास जोड़, घटाव, गुणा, भाग, और "मॉड्यूलो" (modulo) ऑपरेटर हैं। यह असल में शेषफल (remainder) वाला ऑपरेटर है, जिसे आप एक ही कमांड से, यानी इस तरह के एक ही ऑपरेटर से, कर सकते हैं।
चलिए इनमें से कुछ का इस्तेमाल करके अपना ही कैलकुलेटर बनाते हैं और देखते हैं कि यह कैलकुलेटर हमारे लिए क्या कर सकता है और क्या नहीं।
calculator.c: दो संख्याओं का जोड़
तो यहाँ वापस VS Code में, मैं अपना टर्मिनल खोलता हूँ। चलिए "calculator.c" नाम का एक प्रोग्राम बनाते हैं।
और इस प्रोग्राम में, चलिए शुरू में कुछ बहुत सरल करते हैं, जो बस दो संख्याओं को जोड़ता है।
तो पहले cs50.h शामिल करते हैं, ताकि हम अपने "get" फ़ंक्शन इस्तेमाल कर सकें। फिर stdio.h शामिल करते हैं, ताकि हम printf इस्तेमाल कर सकें। हमारा रोज़ का "int main void" बस कॉपी-पेस्ट कर लेते हैं।
और main के अंदर, चलिए यह करते हैं।
वेरिएबल "x" घोषित कीजिए, उसे "get int" के बराबर रखिए। और उपयोगकर्ता से पूछिए "What's x?" प्रश्नचिह्न।
फिर एक और वेरिएबल "y" घोषित कीजिए, उसे "get int" के बराबर रखिए, और उपयोगकर्ता से पूछिए "What's y?" प्रश्नचिह्न।
फिर कुछ बहुत सरल करते हैं, जैसे एक तीसरा वेरिएबल दीजिए, अरे, उसे हम "z" कहेंगे, उसे "x plus y" के बराबर रखिए।
और फिर आख़िर में, बस "x plus y" का जोड़ छाप देते हैं।
तो यह दो संख्याओं के जोड़ के लिए एक बहुत सरल कैलकुलेटर है।
printf में %i
"printf", उद्धरण चिह्नों में, "What's the answer going to be?"
तो यह "percent s" नहीं है। यह थोड़ी देर पहले जल्दी में बताया गया था। इंटीजर के लिए इस्तेमाल करने का प्लेसहोल्डर क्या है?
"Percent i", "backslash n"।
और उस प्लेसहोल्डर की जगह मैं क्या रखना चाहता हूँ? इस मामले में बस "z"।
हमने यह बिल्कुल इसी तरह पहले नहीं किया है, लेकिन फिर से, यह बस हमारे पहले के कुछ विचारों का मेल है।
मैं इस कैलकुलेटर को "make" कर सकता हूँ, एंटर, "dot slash calculator", एंटर।
"What's x?" एक है, "What's y?" दो है, और असल में मुझे तीन मिलता है।
तो बुरा कैलकुलेटर नहीं है। लगता है यह सही काम कर रहा है, लेकिन शायद यह सबसे अच्छा डिज़ाइन नहीं है।
डिज़ाइन: फ़ालतू वेरिएबल से बचें
आम तौर पर यह अच्छा नहीं माना जाता कि आप "z" जैसा वेरिएबल बनाएँ, अगर आप उसे बस थोड़ी देर बाद एक ही जगह इस्तेमाल करने वाले हैं।
आप मेरा समय बर्बाद क्यों कर रहे हैं, एक वेरिएबल बनाकर बस एक बार और सिर्फ़ एक बार इस्तेमाल करने के लिए?
कभी-कभी यह ठीक है, अगर इससे आपका कोड ज़्यादा पठनीय या ज़्यादा स्पष्ट हो जाता है।
और असल में, हो सकता है कि वह हो, अगर मैं उसे "sum" कहूँ। यह तर्कसंगत रूप से एक कुल फ़ायदा है, क्योंकि मैं पाठक को साफ़ कर रहा हूँ कि यह दो वेरिएबलों का जोड़ है।
लेकिन तब भी मैं बाल की खाल निकाल रहा हूँ।
मैं उस तीसरे वेरिएबल से पूरी तरह छुटकारा पा सकता हूँ। और अरे, मैं बस यहीं "x plus y" कर सकता हूँ।
वह पूरी तरह ठीक और वाजिब है, ख़ासकर इसलिए कि वह अब भी कोड की काफ़ी छोटी पंक्ति है। किसी के लिए पढ़ना कठिन नहीं है। यह एक वाजिब फ़ैसला लगता है।
लेकिन यह, फिर से, मेरी उस टिप्पणी की ओर इशारा करता है कि डिज़ाइन व्यक्तिपरक है। यहाँ कोई अटल नियम नहीं हैं। हो सकता है कुछ TA मुझसे असहमत हों, लेकिन मुझे यह ठीक लगता है। यह पठनीय है, जो आख़िरकार शायद सबसे ज़रूरी बात है।
"make calculator", "dot slash calculator", एंटर, एक, दो। और हमें अब भी तीन मिलता है।
तो कोड अब भी काम कर रहा है।
तेज़ टाइप करने की तरकीबें
एक बीच की बात: अगर आप सोचने लगे हैं कि मैं इतना तेज़ कैसे टाइप करता हूँ, तो कभी-कभी मैं ऑटोकम्प्लीट से थोड़ी धोखेबाज़ी कर रहा होता हूँ।
तो अगर मुझे पता है कि मैं "calculator" नाम का प्रोग्राम बनाना चाहता हूँ और "calculator.c" मौजूद है, तो मैं "C-A-L" और "tab" टाइप करना शुरू कर सकता हूँ।
और आप "tab" दबाकर फ़ाइल के नाम का बाक़ी हिस्सा अपने-आप पूरा करवा सकते हैं, अगर वह वहाँ मौजूद हो।
इससे भी बेहतर, अगर मैं पहले टाइप की गई कमांडों पर वापस जाना चाहूँ, तो मैं अपने ऊपर और नीचे के तीर (arrow) कुंजियों का इस्तेमाल करके अपना इतिहास देख सकता हूँ।
तो अगर मैं ऊपर, ऊपर, ऊपर जाऊँ, तो आपको मेरी हाल की टाइप की सारी कमांडें दिखेंगी, और इससे भी मेरा समय बचता है।
तो बस छोटे-छोटे कीबोर्ड शॉर्टकट जो चीज़ों को तेज़ करते हैं।
गुणा: x * 2
ठीक है, तो चलिए कुछ ऐसा करते हैं। सिर्फ़ जोड़ नहीं। क्यों न हम कुछ गुणा इस्तेमाल करें?
तो कैसा रहेगा कि हम उपयोगकर्ता से दो संख्याएँ नहीं, बल्कि शुरू में बस एक, "x", माँगें? और चलिए "x" को 2 से गुणा करते हैं।
और मैं "x asterisk 2" करूँगा, जो C में गुणा का ऑपरेटर है।
चलिए कैलकुलेटर के इस संस्करण को "make" करते हैं, "dot slash calculator"।
और अब "What's x?" चलिए 1 देते हैं। तो 1 गुणा 2 है 2।
चलिए फिर करते हैं। 2 टाइप करते हैं। 2 गुणा 2 है 4।
फिर करते हैं। 3, 3 गुणा 2 है 6, और इसी तरह।
यह ठीक है। लगता है यह काम करता है।
पिछले एक-दो साल के एक मीम की नक़ल
लेकिन शायद चलिए पिछले एक-दो साल के किसी हाल के मीम को लागू करते हैं।
कैसा रहेगा यह? देखते हैं कि आप इसे पहचानते हैं या नहीं।
तो मैं इस कोड को पूरी तरह हटाने जा रहा हूँ। और अपने कैलकुलेटर के अंदर मैं कुछ ऐसा करूँगा: "int dollars equals 1", यानी डिफ़ॉल्ट रूप से 1 डॉलर।
फिर मैं बस प्रदर्शन के लिए जान-बूझकर एक अनंत लूप बनाऊँगा।
फिर मैं उपयोगकर्ता से एक अक्षर (char) लूँगा और कुछ ऐसा कहूँगा, "get char" इस्तेमाल करके, जो एक अकेला अक्षर लेता है।
कैसा रहेगा कि मैं उपयोगकर्ता से कहूँ: "Here's this many dollars, percent i", और उसके आगे अमेरिकी डॉलर का चिह्न ($), "Double it and give to next person?" प्रश्नचिह्न, अगर इससे परिचित हैं तो।
और मैं उनसे हाँ-नहीं का जवाब माँगूँगा। लेकिन मैं डॉलर की मौजूदा संख्या को उसमें डाल दूँगा, ताकि उन्हें पता रहे कि वे किस पर दाँव लगा रहे हैं।
y पर दोगुना, वरना बाहर
फिर इसके नीचे मैं कहूँगा: अगर इंसान का टाइप किया अक्षर "equals equals y" है, यानी हाँ, तो मैं आगे बढ़कर "dollars times equals 2" करूँगा। याद कीजिए कि यह किसी चीज़ को दोगुना करने के लिए, इस मामले में, हमारा छोटा रास्ता था।
मैं ज़्यादा पांडित्यपूर्ण ढंग से कह सकता था: "equals dollars times 2"। लेकिन फिर से, मैं कुछ कुंजी-दबाव बचा सकता हूँ और इसके बजाय "dollars times equals 2" कर सकता हूँ।
"plus plus" जैसा कोई "star star" तरकीब, यानी तारांकन वाली तरकीब, नहीं है। आपको इसे कम से कम इसी तरह करना होगा।
लेकिन अगर उपयोगकर्ता इसे दोगुना करके अगले व्यक्ति को नहीं देना चाहता, तो चलिए यह "else" में करते हैं और बस इस अनंत लूप से पूरी तरह बाहर निकल जाते हैं।
हर ब्योरे का कारण: प्लेसहोल्डर
लेकिन ध्यान दीजिए कि मैंने जान-बूझकर क्या किया है। "get char" में, printf की तरह ही, मैंने एक प्लेसहोल्डर रखा है।
क्यों? हमने "get char", "get int" और "get string" को printf की ही तरह इस तरह लागू किया है कि आप उनमें प्लेसहोल्डर दे सकते हैं और क़ीमतें भर सकते हैं।
क्यों? क्योंकि, फिर से मीम की ख़ातिर, मैं उपयोगकर्ता को बताना चाहता हूँ कि मैं उन्हें कितना पैसा थमाने जा रहा हूँ जब मैं उनसे सवाल पूछता हूँ: "क्या आप इसे दोगुना करके अगले व्यक्ति को देना चाहते हैं?" मैं वह संख्या दिखाना चाहता हूँ।
और डॉलर का चिह्न बस इसलिए है कि हम डॉलर की बात कर रहे हैं। "percent i" इसलिए है कि हम इंटीजरों की बात कर रहे हैं।
प्रोग्राम को चलाना
ठीक है। अगर मैंने इसे बिगाड़ा नहीं, तो चलिए कैलकुलेटर के इस संस्करण, या मीम, को "make" करते हैं। अब तक सब ठीक। "dot slash calculator", एंटर।
यह रहा 1 डॉलर, जो पंक्ति छह पर मेरे "dollars" वेरिएबल का शुरुआती मान था। "Double it and give it to the next person?"
ठीक है। "y"।
यह रहे 2 डॉलर। "Double it and give it to the next person?"
ठीक है। ठीक है। ठीक है। ठीक है। ठीक है।
मैं इसे तेज़ी से करता हूँ। यह काफ़ी अच्छा होता जा रहा है। आप घातांक (exponentiation) की ताक़त देख सकते हैं। यह काफ़ी ऊँचा होता जा रहा है।
चलते रहिए। चलते रहिए। बहुत सारे डॉलर।
बहुत आगे चला गया। मीम में ऐसा नहीं होता।
यहाँ क्या हुआ? क्या चल रहा है?
(छात्र) ...
आपको क्या लगता है?
बिल्कुल सही। अच्छी सूझ-बूझ।
———————————————————
भाग 1
धन्यवाद।
ठीक है, यह CS50 है, और यह सप्ताह एक है, हमारा दूसरा सप्ताह एक साथ।
और आप याद करेंगे कि पिछले सप्ताह, सप्ताह शून्य, हमने Scratch पर ध्यान केंद्रित किया था,
अंततः, यह ग्राफिकल प्रोग्रामिंग भाषा जिसके द्वारा आप खींचकर और छोड़कर
पहेली के टुकड़े जोड़ सकते हैं जो एक साथ इंटरलॉक होते हैं, केवल अगर यह तार्किक रूप से समझ में आता है
ऐसा करने के लिए।
और आप में से कई लोगों ने वास्तव में शायद मिडिल स्कूल में या उससे पहले किसी बिंदु पर इसके साथ खेला होगा।
लेकिन हमारे उद्देश्यों के लिए, Scratch के लक्ष्य
थे हमें कुछ मौलिक निर्माणों के लिए एक प्रकार का मानसिक मॉडल देना
जिसे हम आज C में, कुछ हफ्तों में Python में और उसके बाद भी बार-बार देखने वाले हैं।
और उनमें शामिल हैं जैसे फंक्शन और रिटर्न वेरिएबल और आर्गुमेंट
और वेरिएबल और लूप और कंडीशनल और बहुत कुछ।
और इसलिए भले ही आज थोड़ा सा फायर होज़ जैसा लगे, जैसा कि यहाँ चित्रित है,
मैं सराहना करता हूँ कि आज के कई विचार बिल्कुल वही हैं
जो पिछले सप्ताह के विचार थे।
बस सिंटैक्स बदलने वाला है।
यह थोड़ा अलग दिखने वाला है।
यह थोड़ा डरावना दिखने वाला है।
इसे याद रखना थोड़ा कठिन होने वाला है, सिवाय अभ्यास के साथ,
वह मसल मेमोरी आएगी।
लेकिन विचार अंततः वही रहने वाले हैं।
और वास्तव में, यह, अगर अपरिचित है, सड़क के नीचे MIT
का हैक्स की परंपरा है जिसके द्वारा छात्र साल में एक बार कुछ काफी पागलपन भरा करते हैं।
और इस बिंदु पर, उन्होंने एक वास्तविक काम करने वाले,
पानी पीने के फव्वारे को एक वास्तविक फायर हाइड्रेंट से जोड़ दिया।
और वहाँ का चिन्ह, बहुत पिक्सेलेटेड, कहता है, MIT से शिक्षा प्राप्त करना
फायर होज़ से पीने की कोशिश करने जैसा है।
और वास्तव में कंप्यूटर साइंस, प्रोग्रामिंग, CS50
कभी-कभी ऐसा ही महसूस होगा, लेकिन समझें कि अंततः सबसे महत्वपूर्ण
यह नहीं है कि आप दिन-प्रतिदिन कहाँ महसूस करते हैं,
बल्कि तीन महीने बाद आप पिछले सप्ताह की तुलना में कहाँ महसूस करते हैं,
तथाकथित सप्ताह शून्य।
तो आइए वापस देखें कि सप्ताह शून्य कैसा दिखता था।
यह कुछ इस तरह दिखता था, सबसे सरल प्रोग्राम,
जिसके माध्यम से हम उस बिल्ली को कहते हैं, हैलो, वर्ल्ड।
आज, वही कोड कुछ इस तरह दिखना शुरू होने वाला है, जो
हमने आपको पिछले सप्ताह एक झलक दी थी।
लेकिन इस बार, मैंने जानबूझकर इसे रंग-कोड किया है
यह संदेश भेजने की कोशिश करने के लिए कि, जबकि Scratch में,
हमारे पास यह पीला पहेली टुकड़ा था जो चीजों को शुरू करता था,
जो खुद वास्तव में कुछ नहीं करता था, लेकिन प्रोग्राम को शुरू करता था,
जबकि असली काम यहाँ बैंगनी में किया जाता था।
आज भी वही सच होने वाला है, जिससे मैं
स्क्रीन पर इस पीले कोड पर थोड़ी देर के लिए हाथ हिलाऊँगा,
लेकिन वास्तव में सबसे अधिक प्रभाव डालने वाला यही बैंगनी लाइन है और उसके अंदर सफेद टेक्स्ट।
और हम अगले कुछ हफ्तों में इन सभी लाइनों का अर्थ तोड़ेंगे,लेकिन कभी-कभी हम विवरणों पर हाथ हिला देंगेअगर हम महसूस करते हैं कि कहानी के इस बिंदु पर यह थोड़ा अनावश्यक है।और वास्तव में, मुझे अभी के लिए रंग-कोडिंग हटा देने दें,और हम देखेंगे कि यह उस प्रकार का कोड है जिसे C नामक भाषा मेंहम आज और अगले कई हफ्तों के लिए खेलना और उपयोग करना शुरू करने वाले हैं।और वास्तव में, यह उस चीज़ का प्रतिनिधि है जिसे हम आम तौर पर सोर्स कोड कहते हैं।तो सोर्स कोड वह है जो प्रोग्रामर लिखते हैं।यह वह है जो आप लिखते हैं।यह वह है जो आपने लिखा, हालांकि पहेली के टुकड़ों को खींचकर और छोड़कर।इस सप्ताह से आगे, आप अपने कीबोर्ड का अधिक उपयोग करना शुरू करने वाले हैं,और आप सोर्स कोड लिखने वाले हैं।तो यह कोड है जिसे हम मनुष्य कुछ प्रशिक्षण और कुछ अभ्यास के साथ समझ सकते हैं।लेकिन बेशक, पिछले सप्ताह के अनुसार, कंप्यूटर अंततःकौन सी भाषा समझते हैं?केवल।तो बाइनरी, शून्य और एक।और इसलिए आप और मैं, हाँ, आज से कोड लिख सकते हैं एक रूप में जोकुछ इस तरह दिखता है, जो स्वीकारोक्ति से थोड़ा रहस्यमय और क्रिप्टिक लग सकता है,लेकिन यह निश्चित रूप से शून्य और एक के पूरे झुंड से बेहतर है।लेकिन हम सोर्स कोड में लिखने वाले हैं, लेकिन मशीनें जिनके लिए हम कोड लिखते हैंअंततः केवल इन शून्य और एक को समझती हैं, जो बहुत अच्छी तरह सेहैलो वर्ल्ड कह सकते हैं, लेकिन हम इसे आगे मशीन कोड कहने वाले हैं।तो मशीन कोड वह है जो कंप्यूटर समझते हैं।केवल शून्य और एक।सोर्स कोड वह है जो आप और मैं समझते हैं और वास्तव में लिखते हैं।तो यह तर्कसंगत है कि हमें किसी तरह एक को दूसरे में अनुवाद करना होगासोर्स कोड से मशीन कोड में।और मैंने पिछले सप्ताह इसका बहुत संक्षेप में उल्लेख किया था,लेकिन हम उसी मानसिक मॉडल का उपयोग करने वाले हैं जिससे हम जो सोर्स कोड लिखते हैंकिसी समस्या का इनपुट हो सकता है।उससे हम जो आउटपुट चाहते हैं वह मशीन कोड होने वाला है।तो आज इस कहावत वाले ब्लैक बॉक्स के अंदर हम आपको जिस विशेष सॉफ्टवेयर से लैस करने वाले हैंवह सोर्स कोड को इनपुट के रूप में लेता है, मशीन कोड को आउटपुट के रूप में पैदा करता है,और उस प्रकार के प्रोग्राम को कंपाइलर कहा जाता है।और दुनिया में कंपाइलरों के बहुत सारे अंतर हैं।हम आपको सबसे लोकप्रिय में से एक का उपयोग करने वाले हैं,लेकिन यह बस एक सॉफ्टवेयर का टुकड़ा है जो किसी और ने लिखा है जोएक भाषा को दूसरी में परिवर्तित करता है।सोर्स कोड, उदाहरण के लिए, C नामक भाषा में, मशीन कोड में,शून्य और एक जो हमारे मैक, पीसी, फोन और अन्य डिवाइस वास्तव में समझते हैं।
अगला भाग चाहिए तो बताओ।
बिना रुके क्रमशः देते जाओThought for 5s
भाग 2
तो हम यह कहाँ करने वाले हैं और कैसे करने वाले हैं?
तो मैंने पिछले सप्ताह वादा किया था कि हम आपको इस साल के टूल से परिचित कराएँगे,
जिसे मैंने क्लास की शुरुआत में बहुत संक्षेप में इस्तेमाल किया था उस चैट बॉट को जल्दी बनाने के लिए।
हम इसे हालांकि इस सप्ताह Python के लिए नहीं, बल्कि वास्तव में एक अलग भाषा
C के लिए इस्तेमाल करने वाले हैं। और वास्तव में, यह टूल, Visual Studio Code, या संक्षेप में VS Code,
उद्योग में बहुत लोकप्रिय है।
यह वही है जो असली प्रोग्रामर, कहने के लिए, आजकल हर समय इस्तेमाल कर रहे हैं।
बिल्कुल विकल्प हैं।
अगर आप में से कुछ ने पहले प्रोग्रामिंग की है, तो आपने अलग टूल इस्तेमाल किए या अनुभव किए होंगे।
लेकिन यह एक बहुत आम टूल है जिसे आप CS50 के बाद भी देखेंगे।
और वास्तव में, यह कुछ ऐसा है जिसे अंततः आप मुफ्त में
अपने खुद के मैक और पीसी पर इंस्टॉल कर सकते हैं ताकि कोर्स के अंत तक,
आप पूरी तरह से CS50 और किसी भी CS50 संबंधित टूल से स्वतंत्र हो जाएँ।
लेकिन हमने क्लास की बिल्कुल शुरुआत के लिए
अनिवार्य रूप से इस टूल का क्लाउड-आधारित संस्करण प्रदान किया है।
तो आपको किसी भी मैक या पीसी या उसके जैसे पर बस एक वेब ब्राउज़र की जरूरत है ताकि सब कुछ
आपके लिए पहले से इंस्टॉल हो, पहले से कॉन्फ़िगर हो।
आपको टर्म की शुरुआत में बेवकूफी भरे तकनीकी सपोर्ट
सिरदर्द से नहीं निपटना पड़ेगा क्योंकि यह बस काम करना चाहिए।
लेकिन टर्म के अंत तक, एक बार जब आप तकनीक
और विशेष रूप से कोड के साथ थोड़े अधिक सहज हो जाएँ, तो आप बिल्कुल इस टूल से ऑफ-बोर्ड हो सकते हैं,
इसे अपने खुद के मैक और पीसी पर इंस्टॉल, डाउनलोड कर सकते हैं,
और लगभग बिल्कुल वही वातावरण पूरी तरह से अपने नियंत्रण में रख सकते हैं।
तो आज से, आप एक इंटरफ़ेस देखने वाले हैं जो काफी इस तरह दिखता है
काफी अक्सर।
और हमने पिछले सप्ताह बहुत संक्षेप में इसी इंटरफ़ेस का इस्तेमाल किया था।
आगे बढ़ते हुए, यहाँ हम कोड लिखने वाले हैं।
ऊपर दाएँ में एक या अधिक कोड टैब दिखाई देने वाले हैं,
किसी भी टैब्ड वातावरण के समान जो आप इस्तेमाल कर सकते हैं।
यहाँ, उदाहरण के लिए, बस पहली फ़ाइल का स्क्रीनशॉट है
जिसे हम आज बनाएंगे जिसे hello.c कहा जाता है।
इसका नाम hello.c इसलिए है क्योंकि यह
C नामक भाषा में है, जैसा कि हम जल्द ही देखेंगे, कोई शब्द खेल नहीं।
इस बीच, यहाँ कोड रंग-कोडेड होता है, बिल्कुल उसी तरह नहीं
जैसा आपने पहले देखा क्योंकि मैंने मैन्युअली इसे scratch ब्लॉक जैसा दिखने दिया।
लेकिन VS Code और अन्य प्रोग्रामिंग वातावरण
जो सुविधाएँ प्रदान करते हैं उनमें से एक को सिंटैक्स हाइलाइटिंग कहा जाता है, जिससे आप इन रंगों के बारे में चिंता
या सोचते भी नहीं।
लेकिन जैसे ही आप एक पहचानी गई भाषा में कोड लिखते हैं,
VS Code जैसे टूल आपके कोड के अलग-अलग हिस्सों को बस रंग-कोड कर देंगे
बस अलग-अलग विशेषताओं को उभरने के लिए।
और हम आज के दौरान देखेंगे कि वे विशेषताएँ क्या हैं।लेकिन आप स्क्रीन के नीचे दाएँ में भी काफी समय बिताएंगे, जैसा मैंने पिछले सप्ताह संक्षेप में किया,तथाकथित टर्मिनल विंडो, जहाँ आप कोड कंपाइल करने और कोड लिखने के कमांड चलाने वाले हैं।और वास्तव में, जैसा कि हम आज देखेंगे, आप अपने माउसका इस्तेमाल और क्लिक थोड़ा कम करने वाले हैं।आप अपने कीबोर्ड का इस्तेमाल और टाइपिंग थोड़ा अधिक करने वाले हैं।और अंततः, भले ही पहले यह एक कदम पीछे जैसा लगेकिसी ऐसी चीज़ का इस्तेमाल न करना जो इतनी यूज़र फ्रेंडली हो,वास्तविकता यह है कि लगभग हर प्रोग्रामर अंततः खुद कोकीबोर्ड का अधिक बार, अधिक तेजी से इस्तेमाल करके बहुत अधिक उत्पादक, बहुत अधिक शक्तिशाली पाता है,बजाय पारंपरिक माउस या ट्रैकपैड के।इस बीच, हम बाएँ में कुछ कुछ परिचित सुविधाएँ देखेंगे।जैसे यह वह जगह है जहाँ आप समय के साथ बनाई जाने वाली फ़ाइलें और फ़ोल्डर देखेंगे।सबसे बाएँ यहाँ एक एक्टिविटी बार होने वाला है, जो अनिवार्य रूप सेमेनू का एक आधुनिक रूप है जिसके माध्यम से आप चीज़ें खोल और बंद कर सकते हैं और अन्य सुविधाओं तक पहुँच सकते हैं।मेरे उद्देश्यों के लिए, मैं आम तौर पर इस हिस्से को यहाँ छिपा दूँगा।मैं आम तौर पर इस हिस्से को यहाँ छिपा दूँगा ताकि जब हम एक साथ हों,हम लगभग पूरी तरह से कोड और कमांड पर ध्यान केंद्रित कर रहे हों।लेकिन मैं बस कुछ तेज़ कीबोर्ड शॉर्टकट टाइप कर रहा हूँअपने खुद के यूज़र इंटरफ़ेस को उस तरह सरल बनाने के लिए।तो यह सब कहने के साथ, बस कुछ शब्दावली।तो यह पूरा सामूहिक वातावरण जिसका मैं यहाँ वर्णन कर रहा हूँआम तौर पर ग्राफिकल यूज़र इंटरफ़ेस के रूप में जाना जाता है।क्यों?खैर, यह यूज़र्स के लिए एक इंटरफ़ेस है जो ग्राफिकल प्रकृति का है,आइकन और बटन और उसके जैसे के साथ।इसके लिए शॉर्टहैंड नोटेशन GUI है, संक्षेप में GUI।लेकिन इस ग्राफिकल यूज़र इंटरफ़ेस के भीतर, जैसा वादा किया,नीचे दाएँ में वह टर्मिनल विंडो होने वाली है जहाँ मैंने वादा किया था कि हमअपने अधिकांश कमांड टाइप करेंगे।और कंप्यूटिंग में आपको थोड़ा अधिक жарगन देने के लिए,इसे आम तौर पर कमांड लाइन इंटरफ़ेस, या संक्षेप में CLI कहा जाता है,जिसमें आप कमांड उस इंटरफ़ेस में टाइप कर रहे होते हैं।और कंप्यूटिंग सॉफ्टवेयर की दुनिया अनिवार्य रूप सेGUI और CLI में विभाजित है।और कभी-कभी एक सॉफ्टवेयर के पास दोनों में से एक-एक भी हो सकता है।लेकिन बिना आगे की बात किए, क्यों न हम पूरी तरह से पहलेइस यहाँ प्रोग्राम पर ध्यान केंद्रित करें, जिसे मैं कहने की हिम्मत करता हूँ कि सबसे सरल प्रोग्राम हैजो आप C जैसी भाषा में लिख सकते हैं, और देखें कि हम वास्तव में कैसे कंपाइलऔर इसे एक साथ चला सकते हैं।
भाग 3
तो मैं VS Code यहाँ जा रहा हूँ, जहाँ मैंने अपना फ़ाइल एक्सप्लोरर
सभी आइकन के साथ छिपा दिया है।
और मैंने अपना एक्टिविटी बार छिपा दिया है ताकि मेरे पास केवल कोड के टैब
और नीचे कमांड प्रॉम्प्ट के लिए जगह हो।
मैं इसे कमांड प्रॉम्प्ट कह रहा हूँ क्योंकि यह डॉलर साइन पर है
जहाँ मैं अपने कुछ कमांड चलाने वाला हूँ।
और यह सम्मेलन से डॉलर साइन है।
इसका मुद्रा से कोई लेना-देना नहीं है।
यह बस एक कंप्यूटिंग सम्मेलन है।
कुछ सिस्टम कैरट सिंबल इस्तेमाल करेंगे।
कुछ सिस्टम ग्रेटर देन सिंबल इस्तेमाल करेंगे, बल्कि, या कुछ और।
लेकिन इसका मतलब बस यहाँ अपने कमांड टाइप करें।
पहला ऐसा कमांड जो मैं टाइप करने वाला हूँ वह यह है।
code hello.c, बीच में एक सिंगल स्पेस के साथ।
मैंने फ़ाइल के नाम में कोई स्पेस इस्तेमाल नहीं किया।
मैंने फ़ाइल के किसी पहलू को कैपिटलाइज़ नहीं किया बस क्योंकि यह सम्मेलन है,
आपके मैक या पीसी के विपरीत, जहाँ आप फ़ाइलों के नाम स्पेस और कैपिटलाइज़ेशन के साथ रखने की आदत में हो सकते हैं।
आम तौर पर, आप अपना जीवन सरल बना लेंगे बस लोअर केस
और बिल्कुल कोई स्पेस इस्तेमाल न करके।
जैसे ही मैं Enter दबाता हूँ, आप देखेंगे कि एक बिल्कुल नया टैब दिखाई देता है
hello.c नाम का, लाइन 1 पर कर्सर ब्लिंक करता हुआ।
और यह अनिवार्य रूप से VS Code है, जो अब मेरे लिए इंतजार कर रहा है
अपने कोड की पहली लाइन टाइप करने के लिए।
ध्यान दें, हालांकि, कि कमांड पूरा हो गया है,
जिससे मेरे पास यहाँ एक और कर्सर है, जिसे अगर मैं टर्मिनल विंडो में क्लिक करूँ
और उसे फोरग्राउंड दूँ, तो मेरा कर्सर वहाँ ब्लिंक कर सकता है।
इसका बस मतलब है कि जब मैं तैयार हूँ तो मैं एक और कमांड टाइप कर सकता हूँ।
तो आइए आगे बढ़ें और इस कोड को जल्दी बनाएँ।
और मैंने यह कई बार किया है, इसलिए मैं इसे काफी तेजी से टाइप कर सकता हूँ।
लेकिन इस टैब में, मैं include standard IO.h करने वाला हूँ, कहने के लिए,
int main void, फिर तथाकथित कर्ली ब्रेसेस के अंदर,
उसमें चार स्पेस से इंडेंट करते हुए।
मैं कहने वाला हूँ print f, कोट अनकोट, hello, comma, world, बैकस्लैश,
और क्लोज कोट, सेमीकोलन।
और वाह, मैंने C में अपना पहला प्रोग्राम लिख दिया। इस तरह की क्लास में,
मेरे द्वारा लिखी गई हर एक लाइन कोड को लिखने की जरूरत नहीं।
वास्तव में, कोर्स की वेबसाइट पर वह सब कुछ की कॉपी होगी
जो हमने किया है, साथ ही कोर्स के नोट्स में उससे अंश।
लेकिन आपका स्वागत है लेकिन उम्मीद नहीं की जाती कि आप वास्तविक समय में फॉलो करें
जो मैं यहाँ टाइप कर रहा हूँ।
तो बस इतना ही।
जैसे मैंने C में अपना बहुत पहला प्रोग्राम लिख दिया।
अगर मैंने यह एक वास्तविक मैक या पीसी पर कमांड लाइन इंटरफ़ेस के बिना किया होता,
तो मेरे डेस्कटॉप पर एक नया आइकन हो सकता था, कहने के लिए, hello नाम का।
और आदर्श रूप से, मैं उस पर डबल क्लिक या टैप करके प्रोग्राम चला सकता था।लेकिन क्योंकि मैं इस विशिष्ट प्रोग्रामिंग वातावरण में हूँजिसमें GUI और CLI का मिश्रण है, मुझे वास्तव मेंअपनी टर्मिनल विंडो में नीचे क्लिक करने की जरूरत है,और मुझे अब पहले इस प्रोग्राम को कंपाइल करने की जरूरत है।क्योंकि इस समय, यह केवल सोर्स कोड के रूप में मौजूद है।तो ऐसा करने के लिए, मैं अपने कोड को बहुत उपयुक्त रूप से कहकर कंपाइल करने वाला हूँmake स्पेस hello।और मैं स्पेस का उच्चारण कर रहा हूँ, लेकिन शाब्दिक रूप से मैंने स्पेस बार दबाया।Make स्पेस hello, जैसा कि यह अर्थपूर्ण रूप से संकेत देता है,hello नाम का एक प्रोग्राम बनाएगा।ध्यान दें कि मैंने फिर से hello.c नहीं कहा क्योंकि कंपाइलर, आइए अभी के लिए इसेmake कहें, भले ही यह थोड़ा सफेद झूठ हो,अनुमान लगाने वाला है कि अगर मैं hello नाम का प्रोग्राम बनाना चाहता हूँ,तो यह स्वचालित रूप से इस मामले में hello.c नाम की फ़ाइल की तलाश करेगा।तो थोड़ा जादू।Enter।और उल्लेखनीय रूप से, जब भी आप इस तरह के कमांड पर कोई आउटपुट नहीं देखते,वह शायद अच्छी बात है।आम तौर पर बोलते हुए, जब आप अपने कोड को कंपाइल करते समय आउटपुट देखते हैं,आपने कुछ गलत किया है, या इस मामले में, मैंने कुछ गलत किया हो सकता है।लेकिन कोई आउटपुट अच्छा है, क्योंकि अब मैं क्या कर सकता हूँ, और यह थोड़ा क्रिप्टिक है,मैं इस प्रोग्राम को डबल क्लिक या कहीं टैप करके नहीं चला सकता,बल्कि डॉट स्लैश hello बिना किसी स्पेस के करके।और यह थोड़ा अजीब है, लेकिन डॉट स्लैश का मतलबहै कि hello नाम का प्रोग्राम बनाने के बाद,वह प्रोग्राम मेरे वर्तमान फ़ोल्डर में समाप्त होने वाला है।यह क्लाउड में कहीं है, हाँ, उस पर थोड़ी देर में और,लेकिन hello नाम का प्रोग्राम बस मेरे वर्तमान फ़ोल्डर में कहीं है।जब मैं डॉट स्लैश कहता हूँ, तो वह जैसे कहना है वर्तमान फ़ोल्डर में जाओऔर उसमें hello नाम के प्रोग्राम को विशेष रूप से चलाओ।अब, जैसा कि मैं अक्सर करूँगा, मैं अपनी उंगलियाँ क्रॉस करूँगा,आशा करूँगा कि मैंने किसी भी तरह से इसे गड़बड़ नहीं किया,और मुझे एक सेकंड में देखना चाहिए, hello world वास्तव में स्क्रीन पर प्रिंट हुआ।और इसलिए उन कमांडों का बस पुनरावृत्ति करने के लिए, एक,मैंने code hello dot c चलाया, जो VS Code विशिष्ट चीज़ है।Code, VS Code के लिए शॉर्ट, बस hello dot c नाम की एक नई फ़ाइल बनाता है,और फिर मैं अपने खुद के कीबोर्ड के साथ आगे बढ़ रहा हूँ।Make hello उस सोर्स कोड को मशीन कोड में कंपाइल करता है,इससे hello नाम की एक नई फ़ाइल बनती है।और उस प्रोग्राम, hello, को चलाने के लिए, मैं यह अजीब कमांड टाइप करता हूँ डॉट स्लैश hello।लेकिन यह एक पैराडाइम है, चाहे आप अपने प्रोग्रामों को कुछ भी कहें,हम बार-बार बार-बार देखने वाले हैं।तो भले ही आपने कुछ ऐसा बिल्कुल नहीं किया हो,यह बहुत जल्दी परिचित हो जाएगा।
भाग 4 जारी रखने के लिए तैयार हूँ। बिना रुके आगे बढ़ रहा हूँ।
जब तुझे कह चुका हूँ क्रमशः पूरा दे डाल, बिना रुककर पूछे। तो फ्री टोकन क्यों बरबाद कर रहा है, बीच में रुककर पूछकरThought for 7s
भाग 4
हाँ, सवाल?
जब आप make hello कहते हैं, तो कंप्यूटर कैसे जानता है
कि कोड का कौन सा हिस्सा hello का वर्णन करता है?
अच्छा सवाल।
जब मैं make hello कहता हूँ, तो कंप्यूटर कैसे जानता है
कि कोड का कौन सा हिस्सा इस प्रोग्राम hello का वर्णन करता है,
यह शाब्दिक रूप से hello dot c की पूरी सामग्री ले लेने वाला है
और उन्हें किसी तरह एक प्रोग्राम में बदलने वाला है।
और क्या इसका hello नाम होना जरूरी है या नाम?
क्या इसका नाम hello होना जरूरी है?
नहीं।
मैं इसे goodbye या कुछ भी अधिक मेरे पहले प्रोग्राम dot c कह सकता था,
कुछ भी बिल्कुल।
जब तक मैं इन शब्दों को यहाँ तदनुसार बदल दूँ।
लेकिन इसका होना चाहिए जैसे, इसे उसी चीज़ से होना चाहिए।
हाँ।
अगर मेरे पास जैसे green dot c है, तो यह green या जो भी बनाएगा।
बिल्कुल।
अगर आप वहाँ नाम बदलते हैं, तो आपको अपने कमांड तदनुसार बदलने होंगे।
इन यहाँ पर अन्य सवाल?
कदम।
नहीं?
ठीक है।
तो आइए तोड़ें कि हमने अभी क्या किया और यह कोड क्यों काम करता है
उस तरह जैसे यह करता है।
खैर, पुनरावृत्ति करने के लिए, Scratch में, हमारे पास इस तरह का प्रोग्राम था।
जब हरा झंडा क्लिक किया गया, हम स्क्रीन पर hello world कहना चाहते थे।
उसके अनुरूप कोड मोटे तौर पर यहाँ है।
और वास्तव में, ध्यान दें कि पीला या नारंगी कोड लाइन्स अप होता है
when green flag clicked के साथ।
यहाँ बैंगनी कोड say ब्लॉक के साथ लाइन्स अप होता है।
और इसके अंदर सफेद कोड मोटे तौर पर अनुरूप होता है
उस सफेद अंडाकार के साथ जो हमने पिछले सप्ताह बार-बार इस्तेमाल किया।
तो आइए अधिक एक-से-एक पत्राचार करें।
और ये स्लाइड जानबूझकर डिज़ाइन की गई हैं
आपको फिर से वह प्रकार का मानसिक मॉडल देने के लिए पिछले सप्ताह के समान विचारों को लेकर
और बस इस सप्ताह से आगे सिंटैक्स बदलने का।
तो जब हमारे पास इस तरह का फंक्शन होता है,
और याद करें कि एक फंक्शन बस एक क्रिया या क्रिया है,
यह काम का एक छोटा टुकड़ा पूरा करता है,
कोड में, विशेष रूप से C में, आप बेशक बैंगनी पहेली
टुकड़ा नहीं टाइप करने वाले, बल्कि आप शब्द print कहने वाले हैं।
खैर, अधिक तकनीकी रूप से, print F, जहाँ F जैसा हम जल्द ही देखेंगे
का मतलब प्रिंटेड आउटपुट को फॉर्मेट करना है।
क्योंकि यह सिर्फ कुछ कच्चा टेक्स्ट अकेले प्रिंट करने से अधिक शक्तिशाली है।
फिर आपके पास पेरेंथेसिस हो सकते हैं, खुले और बंद, बाएँ और दाएँ।
और ध्यान दें कि यह कोई दुर्घटना नहीं है कि MIT ने फंक्शन के इनपुट के लिए अंडाकार चुना,
क्योंकि यह मोटे तौर पर पेरेंथेसिस की शुरुआत
और बाएँ और दाएँ पेरेंथेसिस जैसा दिखता है।
इस बीच, अनुरूप
C कोड में पेरेंथेसिस के अंदर क्या जाता है?
खैर, दिन के अंत में, न्यूनतम रूप से, hello, comma, world,क्योंकि वह शाब्दिक रूप से वह है जो हम स्क्रीन पर प्रिंट करना चाहते हैं।लेकिन C में, Scratch के विपरीत, थोड़ा ओवरहेड है,थोड़ा अतिरिक्त सिंटैक्स जिससे आपको निपटना ही पड़ता है कंप्यूटर को स्पष्ट करने के लिए कि आप क्या प्रिंट करना चाहते हैं।विशेष रूप से, आपको वह सब कुछ घेरना होगाजो आप प्रिंट करना चाहते हैं डबल कोट्स के साथ यह स्पष्ट करने के लिएकि hello कोई विशेष फंक्शन या वेरिएबल या कुछऔर नहीं है।यह hello world वह अंग्रेजी वाक्यांश है जो आप प्रिंट करना चाहते हैं।तो यहाँ डबल कोट, वहाँ डबल कोट का मतलब है यहाँ शुरुआतऔर अंत है जो मैं प्रिंट करना चाहता हूँ।आप उत्सुकता से अधिकांश मामलों में शब्द या शब्दों के अंत में बैकस्लैश n भी डालने वाले हैंजो आप प्रिंट करना चाहते हैं।हम उसे एक पल में हटाएँगे और देखेंगे कि यह क्या करता है।और फिर अंत में, और शायद प्रोग्रामिंग हलकों में सबसे अधिक परेशान करने वाला,आपको अपने विचार को सेमीकोलन के साथ खत्म करना होता है।बिल्कुल जैसे अंग्रेजी में, आप अधिकांश वाक्यों को पीरियड के साथ खत्म करते हैं।और प्रोग्रामिंग की बात C के साथ विशेष रूप से यह है,अगर आप इन लगभग किसी भी विवरण को गड़बड़ करते हैं जो मैंने अभी गिनाए,कुछ गलत होने वाला है।और इसलिए आप अच्छी कंपनी में हैं।पहला प्रोग्राम जो आप लिखने या कंपाइल करने की कोशिश करते हैं,संभावना है कि यह सही तरीके से काम न करे क्योंकि आप समय के साथइन प्रतीत होने वाले छोटे और वास्तव में छोटे विवरणों को स्पॉट करने की मसल मेमोरी विकसित करेंगे,लेकिन जो कंप्यूटर के लिए मायने रखते हैं।ठीक है, तो अगर आप परिचित हैं, बेशक,गणित में फंक्शन के नोटेशन से,जैसे कोड में एक फंक्शन वास्तव में गणित में फंक्शन के समान विचार है,जिससे फंक्शन f कुछ इनपुट लेता है, उदाहरण के लिए, x,और आम तौर पर कुछ आउटपुट पैदा करता है।तो अगर आप अधिक उस पृष्ठभूमि से आ रहे हैं,समझें कि हम यहाँ वास्तव में मोटे तौर पर वही कर रहे हैं।लेकिन कोड में, याद करें कि हमारे पास आउटपुट के अलग प्रकार हो सकते हैं।तो अगर यह हमारा भव्य मानसिक मॉडल है और कहेंहमारे पास इस ब्लैक बॉक्स के अंदर एक फंक्शन है जो आर्गुमेंट लेता है,अर्थात, इसके इनपुट के रूप में, इसमें कभी-कभी साइड इफेक्ट हो सकते हैं।और याद करें कि साइड इफेक्ट अक्सर दृश्य चीजें होती हैं जो परिणामस्वरूप होती हैं।वे बस स्क्रीन पर खेलते हैं।शायद यह स्पीकर से आता है।यह कुछ आम तौर पर क्षणिक है जो बस होता है।लेकिन यह आवश्यक रूप से उसी तरह उपयोगी नहीं हैजैसा एक अन्य प्रकार का फंक्शन जिसे हम बस थोड़ी देर में वापस लौटेंगे।लेकिन पिछले सप्ताह, याद करें कि हमें बिल्ली के साथ एक स्पीच बबलस्क्रीन पर प्रकट करने और उस स्पीच बबल में hello, world कहने को मिला।जब इनपुट hello, world था।और अनुरूप फंक्शन इसके बजाय say था।तो आइए देखें कि क्या हम अब तोड़ नहीं सकते कि हमने जो कोड लिखा वह वास्तव मेंहमारे लिए बिट बाय बिट क्या कर रहा है।तो मुझे VS Code यहाँ वापस जाने दें।और मुझे इसे थोड़े तरीके से तोड़ने का प्रस्ताव दें।मुझे बैकस्लैश n हटा देने दें अगर केवल इसलिए कि पहली नजर में,कौन जानता है या परवाह करता है कि वह क्या कर रहा है।आइए बस इसे हटा दें अगर हम इसे नहीं समझते।मैं अब अपनी टर्मिनल विंडो में वापस जा सकता हूँ।और मैं फिर से डॉट स्लैश hello enter कर सकता हूँ।लेकिन प्रतीत होता है कोई बदलाव नहीं, जो अच्छा है।ऐसा नहीं लगता कि मैंने इसे तोड़ा।लेकिन मैंने आपको यहाँ तरह से गुमराह किया है।क्यों?क्यों कुछ भी नहीं बदला प्रतीत हुआ?मैंने इसे फिर से कंपाइल नहीं किया।तो याद करें कि कंपाइलर सोर्स कोड को मशीन कोड में परिवर्तित करता है।लेकिन मैंने वह कुछ मिनट पहले ही कर लिया था।अगर मैंने सोर्स कोड बदल दिया है, तो यह तर्कसंगत हैकि मुझे कोड को फिर से कंपाइल करने की जरूरत है उन प्रभावों को वास्तव में देखने के लिए।तो मुझे वह फिर से करने दें।Make hello enter।कुछ भी गलत नहीं हुआ प्रतीत होता है।लेकिन मुझे अब डॉट स्लैश hello enter करने दें।और यह अब सूक्ष्म है।और वास्तव में, मुझे ज़ूम इन करने दें।यह वास्तव में बस एक सौंदर्य बग है।और अब तक कार्यात्मक रूप से, प्रोग्राम अभी भी तकनीकी रूप सेhello world प्रिंट कर रहा है।लेकिन प्रतीत होता है क्या गलत है?या दूसरे शब्दों में, बैकस्लैश n ने स्पष्ट रूप से क्या किया?हाँ।हाँ, तो यह किसी तरह मुझे एक नई लाइन दे रहा है।और वह अनिवार्य रूप से है जो बैकस्लैश n दर्शाता हैवहाँ एक नई लाइन दो।और मैं वह क्यों कर रहा था?खैर, वास्तव में बस सौंदर्यशास्त्र के लिए।अगर यह डॉलर साइन मेरे प्रॉम्प्ट का प्रतिनिधित्व करता है जहाँ मैं कमांड टाइप करता हूँ,अगर कुछ भी, तो यह बस तरह से बेवकूफी भरा लगता हैकि मैंने यहाँ एक प्रोग्राम खत्म किया, और फिर प्रॉम्प्ट उसी लाइन पर है।यह बस गलत लगता है, भले ही आप तर्क कर सकते हैं कि वह मेरा इरादा था,भले ही इस मामले में यह नहीं था।तो विकल्प क्या होगा?खैर, आप यहाँ जो देख रहे हैं वह वास्तव में आम तौर परएस्केप सीक्वेंस के रूप में जाना जाता है, जो प्रतीकों के विशेष अनुक्रम हैं,जैसे बैकस्लैश और n, इस मामले में, जो थोड़ा असामान्य कुछ करते हैं।और यहाँ बस कुछ का गैर-पूर्ण सूची है जो आप वास्तविक दुनिया में सामना करेंगे।और CS50 सहित, बैकस्लैश n आपको एक नई लाइन पर ले जाता है।बैकस्लैश r एक तथाकथित कैरिज रिटर्न है।अगर आपने कभी पुराने स्कूल टाइपराइटर देखा या इस्तेमाल किया है,यह टाइपिंग हेड को बाएँ n पर वापस लाने की प्रक्रिया को संदर्भित करता है।तो यह कर्सर को क्षैतिज रूप से हिलाता है, ऊर्ध्वाधर के विपरीत।यह दिलचस्प है।बैकस्लैश डबल कोट।यह पैटर्न क्यों मौजूद है?बैकस्लैश डबल कोट।हाँ।अगर आप बस डबल कोट लिखते हैं, तो यह उस स्टेप को बंद कर देता है जिसे आप कहने की कोशिश कर रहे हैं।बिल्कुल।तो याद करें कि वाक्यांश जो हमने टाइप करने, प्रिंट आउट करने की कोशिश की, जैसे hello, comma, world।अगर किसी कारण से आप hello, world नहीं कहना चाहते,बल्कि आप किसी तरह व्यंग्यात्मक रूप से कहना चाहते, जैसे hello, world, या कुछवैसा, खैर, आप कोट, कोट, कोट, कोट नहीं डाल सकते,और उम्मीद कर सकते कि कंप्यूटर जाने कि कौन सा कोट किसके अनुरूप है।यह बस तर्कसंगत रूप से अस्पष्ट है।तो अगर डबल कोट्स के अंदर, आप वास्तव मेंवास्तविक डबल कोट्स प्रिंट करना चाहते हैं, यह एक एस्केप सीक्वेंस है जोकंप्यूटर को बताता है, यह कोई कोट नहीं है जो मेरे विचार की शुरुआतऔर अंत को चित्रित करता है।यह शाब्दिक रूप से एक डबल कोट है।और हम अन्य स्थितियाँ देखेंगे जिनमें एक सिंगल कोट या एपोस्ट्रॉफीसमान है।हम पागल स्थितियाँ देखेंगे जिनमें आप बैकस्लैश प्रिंट करना चाहते हैं।लेकिन बैकस्लैश का पहले से ही कुछ विशेष अर्थ है।तो इन सभी समस्याओं के समाधान हैं।लेकिन आइए यहाँ खरपतवार में बहुत दूर न जाएँ।लेकिन मुझे कोड पर वापस जाने दें और प्रस्ताव दें कि विकल्प अन्यथाक्या हो सकता था।अगर मुझे बैकस्लैश n के बारे में नहीं पता होता, तो कर्सर को अगली लाइन पर ले जाने की मेरी प्रवृत्तिशाब्दिक रूप से बस Enter दबाने या कुछ ऐसा करने की हो सकती थी, जैसे डबल कोट को हिलाना,पेरेंथेसिस को हिलाना, सेमीकोलन को अगली लाइन पर ले जाना।लेकिन यह आपको गलत तरीके से रगड़ना शुरू कर देना चाहिए।और वास्तव में, यह अधिकांश प्रोग्रामिंग भाषाओं के सिद्धांत का उल्लंघन करता हैऔर कि अधिकांश प्रोग्रामिंग भाषाएँ लाइन-आधारित हैं।आप अपना विचार शुरू और खत्म करते हैं, आदर्श रूप से, उसी लाइन पर।और यह उसका उल्लंघन करता है।और दो, भले ही आप कोड पहली बार देख रहे हों,मान लें कि यह भी बस बेवकूफी भरा लगता है,अपने विचार के हिस्से को अगली लाइन पर ले जाना।यह बस थोड़ा मैला लगता है, और यह है।तो C और कई अन्य भाषाएँ, उनमें Python,इसे इन तथाकथित एस्केप सीक्वेंस देकर हल करते हैं।तो अगर आप वहाँ एक नई लाइन चाहते हैं, तो आप बैकस्लैश n करते हैं,और आपको वहाँ अपनी नई लाइन मिलेगी।अब, यह थोड़ा अतिशयोक्ति है जो मैंने कहा,और कि कभी-कभी कोड की लाइनें इतनी लंबी होंगी कि वे रैपहो जाएँगी कई लाइनों पर।लेकिन आम तौर पर, यह एक सम्मेलन है जिससे हम बचने की कोशिश करने वाले हैं।
भाग 5
ठीक है, और क्या गलत हो सकता है?
खैर, आइए यह करें।
मुझे अपनी टर्मिनल विंडो साफ करने दें, जो मैं Control L दबाकर कर सकता हूँ,
या मैं शाब्दिक रूप से clear टाइप कर सकता हूँ।
और मैं बार-बार ऐसा करने वाला हूँ बस स्क्रीन साफ रखने के लिए,
भले ही इसका कोई कार्यात्मक प्रभाव न हो।
यह बस एक सौंदर्य है।
मुझे गलती से कुछ और करने दें।
मान लीजिए कि मैं अपना विचार खत्म करना भूल गया, और मैंने सेमीकोलन छोड़ दिया।
लेकिन अन्यथा, कोड परफेक्ट है।
मुझे अब make hello करने दें।
Enter।
अब हम कुछ आउटपुट देखने वाले हैं जो थोड़ा अधिक रहस्यमय है।
मुझे यहाँ वापस स्क्रॉल करने दें यह स्पष्ट करने के लिए
कि अभी क्या हुआ है कि मैंने make hello चलाया,
लेकिन मुझे दूसरे प्रॉम्प्ट पर वापस नहीं मिला।
मुझे तुरंत डॉलर साइन नहीं दिखता क्योंकि यहाँ एक एरर मैसेज है
जो लगभग उतना ही लंबा है जितना कोड जो मैंने लिखने की कोशिश की।
चिंता न करें, आइए देखें।
यहाँ उस फ़ाइल का नाम है जिसमें समस्या मौजूद है।
तर्कसंगत है कि यह hello.c में है।
यहाँ लाइन नंबर है जिसमें समस्या प्रतीत होती है, लाइन 5।
और वह सहायक है क्योंकि यह इससे लाइन्स अप होता है।
और फिर अगर आप गिनना चाहें, तो यह 29वाँ कैरेक्टर है।
तो अगर मैं बाएँ से दाएँ गिनूँ, कैरेक्टर 29 के आसपास, कुछ गलत है।
कुछ गायब है।
तो यह काफी अच्छा एरर मैसेज है।
वास्तव में, यह यहाँ तक कहता है expected semicolon after expression।
एक छोटा हरा कैरट सिंबल मुझे गलती की ओर इशारा कर रहा है।
तो यह, फिर से, यह कंपाइलर का एक और मूल्य है।
न केवल यह जानता है कि सोर्स कोड को मशीन कोड में कैसे परिवर्तित करना है,
यह आपके कोड में गलतियाँ खोजने में भी काफी अच्छा है
और उन्हें आपकी ओर ध्यान आकर्षित करने की कोशिश करता है।
तो मैं इसे कैसे ठीक करूँ?
खैर, मानते हुए कि आपने इस बिंदु पर एरर मैसेज समझ लिया है,
खैर, आप बस वापस जाएँ, सेमीकोलन जोड़ें।
मुझे अपनी टर्मिनल विंडो में वापस जाने दें।
मैं इसे साफ करने वाला हूँ बस गंदगी साफ करने के लिए।
मुझे make hello फिर से चलाने दें, और अब हम व्यवसाय में वापस हैं।
और वास्तव में, अगर मैं डॉट स्लैश hello करूँ, तो मेरे पास स्क्रीन पर hello world वापस है।
खैर, आइए एक और गलती करें।
मान लीजिए कि मैं भूल गया, जैसा आप कभी-कभी करेंगे,
ऊपर इस लाइन को शामिल करना, जो अगले सप्ताह अधिक समझ में आएगा।
लेकिन अभी के लिए, आइए बस इसे छोड़ दें और सीधे कोड में गोता लगाएँ।
आप सोचेंगे कि यह पर्याप्त है, बस hello world प्रिंट करना।
खैर, यहाँ, मुझे अपनी टर्मिनल विंडो में वापस जाने दें।
मुझे अब फिर से make hello करने दें, और मुझे इसके बजाय
एक पूरी तरह से अलग एरर मैसेज मिलने वाला है।
तो अब, समस्या अभी भी hello dot c के साथ है।
वह समझ में आता है।
लाइन 3, ठीक, तो कहीं वहाँ, printfअचानक समस्या है, भले ही सेमीकोलन वापस आ गया हो,और बैकस्लैश और वापस आ गया हो।तो आइए पढ़ना जारी रखें।Error, call to undeclared library function printf with type int,और फिर यह पूरा मुँह भरा हुआ है।तो यहाँ एक एरर मैसेज का उदाहरण हैजो जब तक आप तरह से कंडीशंड न हों कि इसका क्या मतलब है,और आपने इसे पहले देखा हो, यह काफी अधिक क्रिप्टिक और अस्पष्ट हैजैसे समस्या का समाधान क्या है, खासकर जब आपके बाकी कोडवास्तव में सही हैं।मैंने बस कुछ बेवकूफी भरा भूल गया।लेकिन मैं इस समस्या के बारे में कैसे सोच सकता हूँ?खैर, यह पता चलता है कि C की एक और विशेषतायह है कि यह एक झुंड हेडर फ़ाइलों के साथ आता है, एक झुंड फ़ाइलों के जिनकेनाम dot c में समाप्त नहीं होते, बल्कि dot h में समाप्त होते हैं।और ये तथाकथित हेडर फ़ाइलें, जो dot h में समाप्त होती हैं,कोड रखती हैं जो अन्य लोगों ने लिखा है जिसे आप अपने खुद के प्रोग्राम में इस्तेमाल कर सकते हैं।तो उदाहरण के लिए, इस विशेष मामले में,एक हेडर फ़ाइल हमें पहुँच दे रही है जो अधिक आम तौर पर कंप्यूटिंग मेंलाइब्रेरी कहलाती है।एक लाइब्रेरी कोड है जो किसी और ने लिखा है जिसे आप इस्तेमाल कर सकते हैं।और मैंने वास्तव में पिछले सप्ताह एक लाइब्रेरी इस्तेमाल की।जब मैंने वह import लाइन की और OpenAI, कंपनी का उल्लेख किया,मैं वास्तव में उस कंपनी से एक लाइब्रेरी इस्तेमाल कर रहा थाजिसे मैंने स्वचालित रूप से डाउनलोड और इंस्टॉल किया थाअपने प्रोग्रामिंग वातावरण में क्लास से पहले,क्योंकि मुझे नहीं पता कि चैट बॉट कैसे लागू करना है बिना उनके कंधों पर खड़े हुएऔर उनके द्वारा लिखे गए बहुत सारे कोड का इस्तेमाल किए।यहाँ वही विचार।भले ही printf C की एक विशेषता है, अगर आप इसका इस्तेमाल करना चाहते हैं,तो आपको उस लाइब्रेरी को शामिल करना होगा अपने प्रोग्राम को बताकरउस हेडर फ़ाइल को शामिल करें जो उस फंक्शन को परिभाषित करती है।और आप यह केवल सिखाए जाने या किताब या रेफरेंस में देखने से जानते हैं।लेकिन इस मामले में, मैं standard i o dot h,std i o dot h नाम की हेडर फ़ाइल इस्तेमाल करना चाहता था।यह studio dot h नहीं है।यह ऑनलाइन एक बहुत आम बग है।अगर आप खुद को studio dot h टाइप करते हुए पाते हैं, टाइपो, यह standard i o dot h है।और उस फ़ाइल में, फिर, printf फंक्शन परिभाषित है।तो अगर मैं यहाँ अपने कोड पर वापस जाऊँ, इस समस्या का समाधानवास्तव में बस उस डिलीशन को अनडू करना है जो मैंने एक पल पहले किया,क्योंकि लाइन एक अब मेरे लिए क्या कर रही है वह कंपाइलर को बता रही है,ओह, वैसे, मैंने वह सारा कोड नहीं लिखा जो मैं इस्तेमाल करने वाला हूँ।कृपया इस अन्य फ़ाइल standard i o dot h से printf की परिभाषा शामिल करें।और फिर, आप यह केवल रेफरेंस में देखने,लेक्चर में भाग लेने, या कुछ वैसा ही करके जानेंगे।अन्यथा यह स्पष्ट नहीं है।लेकिन ये वे प्रकार की चीजें हैं जिन्हें आप बहुत जल्दी देख लेते हैं।तो आप उन्हें कहाँ देखते हैं?खैर, यह पता चलता है कि C के इकोसिस्टम में सैकड़ों किताबें हैं जिन्हें आप खरीद या डाउनलोड कर सकते हैं।बहुत सारी, बहुत सारी वेबसाइटें उनमें से CS50 की अपनी एक है।और वास्तव में, C नामक प्रोग्रामिंग भाषा के लिए चीजें देखने का पारंपरिक तरीकाआधिकारिक मैनुअल पेज, या संक्षेप में man पेज देखना है,C भाषा के लिए।दुर्भाग्य से, उनमें से कई दशकों पहले लिखे गए थे जब वे निश्चित रूप सेकाफी उन्नत प्रोग्रामरों द्वारा लिखे गए थे और व्यापक दर्शकों के लिए नहीं।और इसलिए हमने जो किया है वह वह सारा स्वतंत्र रूप से उपलब्ध दस्तावेज़ीकरण आयात किया है,इसे हमारे खुद के URL यहाँ होस्ट किया है, manual.cs50.io।और हमने अनिवार्य रूप से इसे उन कम सहज लोगों के लिए सरल बनाया है, आप में से जोतकनीक के साथ कम परिचित, कम सहज हो सकते हैं,और वास्तव में अधिकांश लोगों के लिए जो मैनुअल पेज पढ़ने के आदी नहीं हैं,यह बस टीचिंग असिस्टेंट जैसी भाषा में लिखा होना उपयोगी है।तो उदाहरण के लिए, अगर आप इस तरह के URL पर जाते हैं,आप CS50 का दस्तावेज़ीकरण देखेंगे इस आधिकारिक लाइब्रेरी, standardio.h के लिए,जो C के साथ ही आता है।अगर आप इस तरह के URL पर जाते हैं, तो आप printfस्वयं विशेष रूप से के लिए दस्तावेज़ीकरण देख सकते हैं।तो उदाहरण के लिए, मुझे बस आपको इसका एक टीजर देने दें।अगर मैं अपने खुद के कंप्यूटर पर वही करूँ,तो मैं यहाँ CS50 मैनुअल पेज देख सकता हूँ।और आप हेडर फ़ाइल बाय हेडर फ़ाइल, CS50 में अक्सर इस्तेमाल होने वालेफंक्शनों का एक झुंड देखेंगे।हमने सूची को भी एक विशाल सूची से बहुत छोटी सूची में फ़िल्टर किया हैताकि आप तरह से देख सकें कि आपके लिए सबसे अधिक संभावना उपयोगी क्या है।अगर आप standardio.h जैसी विशिष्ट पेज पर जाते हैं,आप देखेंगे, उदाहरण के लिए, यहाँ बस आधा दर्जन से अधिक फंक्शनजिन पर हम आज printf से आगे नहीं छूएंगे,लेकिन जिन्हें हम समय के साथ क्लास में देखेंगे जो उपयोगी सामान करते हैं।उदाहरण के लिए, printf स्क्रीन पर प्रिंट करता है,और हम फ़ाइलें खोलने, फ़ाइलें बंद करने,और उसके जैसे अन्य फंक्शन देखेंगे, क्योंकि वह सब standardio, इनपुट और आउटपुट से संबंधित है।अगर मैं इस हेडर फ़ाइल के लिए एक विशिष्ट man पेज पर जाऊँ,आप इन पेजों के लिए मानक फॉर्मेटिंग देखेंगे।तो यहाँ फंक्शन का नाम है, printf, और यह स्क्रीन पर प्रिंट करता है।आप एक सिнопसिस देखेंगे, और यह वास्तव में संकेत देता है कि हम कम सहज मोड में हैं।अगर आप मूल, अधिक रहस्यमय दस्तावेज़ीकरण देखना चाहते हैं, बस उसे अनचेक करें,और आप मूल आधिकारिक दस्तावेज़ीकरण देखेंगे।लेकिन आप उल्लेख देखेंगे कि यह फंक्शन किस हेडर फ़ाइल में परिभाषित हैताकि आप जानें कि अपने खुद के कोड में कौन सी फ़ाइल इस्तेमाल करनी है।आप एक तथाकथित प्रोटोटाइप देखेंगे, जो बस उस फंक्शन की पहली लाइन कोड है,उस पर थोड़ी देर में और।आप एक अंग्रेजी विवरण देखेंगे।आप उदाहरण कोड देखेंगे, लंबी कहानी छोटी, यह आधिकारिक जवाब है।और भले ही इस क्लास में आपके पास वर्चुअल रबर डक तक पहुँच हो,यह s50.ai है, और इसके अन्य रूप जिन्हें आप जल्द ही देखेंगे,आपको आगे बढ़ते हुए आधिकारिक दस्तावेज़ीकरण चेक करने की प्रवृत्ति और वृत्ति भी होनी चाहिए।और आज के सभी AI चीजों जैसे आधिकारिक दस्तावेज़ीकरण पर ट्रेन किए गए हैं।तो वह स्रोत सामग्री है जिस पर इनमें से कोई भी AI, डक उनमें से,वास्तव में निर्भर कर रहे हैं।
