सी, पायथन, जावास्क्रिप्ट, गो, रस्ट, सॉलिडिटी जैसी भाषाओं और कंप्यूटर साइंस के बुनियादी और गणित के उन्नत सिद्धांतों को हिंदी में पढ़ने के लिए संपर्क करें। हम वेबसाइट और सॉफ्टवेयर भी बनाते हैं।
+91 9996865069 हमारा मोर्चा
सफेदपोश मरभुक्खों अर्थात नाममात्र के वेतन पर खटने वाले बौद्धिक-जनों की भी पीड़ा को स्वर देने का मंच
© 2026 Kamta Prasad. सर्वाधिकार सुरक्षित।
वेबसाइट · मोबाइल ऐप बनवाने के लिए Nishant Softwares
C की मूल पुस्तक का संक्षिप्त हिंदी संस्करण | हमारा मोर्चा
programmers
C की मूल पुस्तक का संक्षिप्त हिंदी संस्करण C प्रोग्रामिंग भाषा के हिंदी नोट्स (K&R,
प्रोग्राम की बनावट
c
#include <stdio.h> int main(void) { printf("hello, world\n"); return 0; }
#include जेएस के import जैसा है। यह बाहरी लाइब्रेरी की जानकारी लाता है। प्रोग्राम main से शुरू होता है, जैसे पीएचपी में ऊपर से स्क्रिप्ट चलती है। printf कभी अपने आप नई लाइन नहीं लगाता। \n खुद लिखना पड़ता है। \t टैब है, \\ बैकस्लैश है, \" दोहरा उद्धरण चिह्न है।
वेरिएबल और टाइप
सारे वेरिएबल इस्तेमाल से पहले टाइप के साथ घोषित करने होते हैं (जेएस के let की जगह int x;)। मुख्य टाइप: int (पूर्णांक), float (दशमलव), double (ज्यादा सटीक दशमलव), char (एक अक्षर, असल में छोटा पूर्णांक), short, long। पूर्णांक भाग देने पर दशमलव हिस्सा कट जाता है: 5/9 का मान 0 आता है। इसलिए 5.0/9.0 लिखो।
printf के फॉर्मेट
फॉर्मेट
मतलब
%d
पूर्णांक
%f
दशमलव
%.2f
दशमलव के बाद 2 अंक
%c
यह पायथन के "%d" फॉर्मेटिंग जैसा है।
while (fahr <= upper) { ... } for (i = 0; i < 10; ++i) { ... }
जेएस जैसा ही है। for में तीन हिस्से होते हैं: शुरुआत; शर्त; बढ़ाना।
यह कंपाइल से पहले टेक्स्ट बदल देता है। अंत में सेमीकोलन नहीं लगता। जेएस के const जैसा समझो, पर यह वेरिएबल नहीं है।
getchar() कीबोर्ड या इनपुट से एक अक्षर पढ़ता है। putchar(c) एक अक्षर लिखता है। इनपुट खत्म होने पर getchar EOF लौटाता है। इसलिए अक्षर रखने वाला वेरिएबल int होना चाहिए, char नहीं। int c; while ((c = getchar()) != EOF) putchar(c);
असाइनमेंट भी एक एक्सप्रेशन है और उसका मान होता है। इसलिए ऊपर की लाइन में कोष्ठक जरूरी हैं। == बराबरी जाँचता है और = मान डालता है। जेएस वाली वही गलती यहाँ भी होती है। && और || शॉर्ट-सर्किट करते हैं, यानी जवाब मिलते ही आगे नहीं जाते। int ndigit[10]; /* इंडेक्स 0 से 9 */
आकार तय होता है, बाद में बढ़ता नहीं। जेएस की push वाली सुविधा नहीं है। ऐरे की सीमा से बाहर जाने पर कोई एरर नहीं आता, सीधा कचरा या क्रैश होता है। int power(int base, int n) { int p = 1; for (int i = 1; i <= n; ++i) p = p * base; return p; }
फंक्शन का रिटर्न टाइप और पैरामीटर के टाइप लिखने पड़ते हैं। जो फंक्शन कुछ नहीं लौटाता, उसका टाइप void होता है। फंक्शन को पहले से घोषित (प्रोटोटाइप) करना अच्छी आदत है: int power(int, int); फंक्शन को मान की कॉपी मिलती है, असली वेरिएबल नहीं। अंदर बदलने से बाहर का वेरिएबल नहीं बदलता। ऐरे इसका अपवाद है। ऐरे का नाम देने पर उसका पता (शुरुआती जगह) जाता है, इसलिए फंक्शन असली ऐरे बदल सकता है। जेएस में ऑब्जेक्ट रेफरेंस से ऐसा ही होता है। स्ट्रिंग = अक्षरों का ऐरे
स्ट्रिंग के अंत में छिपा हुआ अक्षर '\0' (शून्य अक्षर) होता है, जो अंत का निशान है। "hello" असल में 6 खाने लेता है। स्ट्रिंग की लंबाई जानने के लिए इस '\0' तक गिनना पड़ता है। फंक्शन के बाहर घोषित वेरिएबल सब फंक्शन देख सकते हैं। ज्यादा ग्लोबल रखना बुरी आदत है, क्योंकि पता नहीं चलता कौन उन्हें बदल रहा है। दूसरी फाइल के ग्लोबल को देखने के लिए extern लिखते हैं। परिभाषा (definition) में मेमोरी बनती है, घोषणा (declaration) में सिर्फ बताया जाता है कि यह है।
अध्याय 2: टाइप, ऑपरेटर, एक्सप्रेशन नाम अक्षर, अंक और _ से बनता है, और अक्षर या _ से शुरू होता है। बड़े और छोटे अक्षर अलग माने जाते हैं। कीवर्ड (if, int वगैरह) नाम नहीं हो सकते। short, long, signed, unsigned टाइप को बदलते हैं। unsigned में ऋणात्मक संख्या नहीं होती। आकार मशीन पर निर्भर है। असली सीमा <limits.h> से देखो। 0 से शुरू होने वाली संख्या अष्टाधारी है (037), और 0x से शुरू होने वाली षोडशाधारी है (0x1f)। 'x' एक अक्षर है, यानी उसका संख्यात्मक मान। "x" स्ट्रिंग है (अक्षर + '\0'), दोनों अलग हैं। enum नाम वाले स्थिर पूर्णांकों की सूची बनाता है: enum boolean { NO, YES }; /* NO=0, YES=1 */
घोषणा के साथ शुरुआती मान दे सकते हो: int i = 0; ग्लोबल और static वेरिएबल अपने आप 0 हो जाते हैं। लोकल वेरिएबल में कचरा होता है। const का मतलब है कि मान बदला नहीं जाएगा। + - * / % में % शेष निकालता है और दशमलव पर नहीं चलता। तुलना के लिए > >= < <= == != हैं। ! उलटा करता है। सच और झूठ: शून्य झूठ है और बाकी हर मान सच है। छोटा टाइप बड़े में अपने आप बदल जाता है (int से float)। बड़े से छोटे में जाने पर डेटा कट सकता है। जबरदस्ती बदलने के लिए cast लिखते हैं: (double) n char असल में छोटा पूर्णांक है, इसलिए c - '0' से अंक का मान निकलता है। x = n++; /* पहले x में n का मान, फिर n बढ़ता है */ x = ++n; /* पहले n बढ़ता है, फिर x में */
& से बिट छाँटते हैं और | से बिट चालू करते हैं। x << 2 का मतलब 4 से गुणा है। i += 2; /* i = i + 2 */ x *= y + 1; /* x = x * (y + 1) */
ऑपरेटरों की वरीयता तय है, पर कौन-सा हिस्सा पहले गणना होगा यह तय नहीं। इसलिए a[i] = i++; और printf("%d %d", ++n, power(2,n)); जैसी चीजें मत लिखो। नतीजा कंपाइलर पर निर्भर है। शक हो तो कोष्ठक लगाओ।
अध्याय 3: नियंत्रण प्रवाह एक्सप्रेशन के बाद ; लगने से स्टेटमेंट बनता है। { } में कई स्टेटमेंट का ब्लॉक बनता है। if-else और else if जेएस जैसे हैं। लटकते else से बचने के लिए हमेशा { } लगाओ। switch switch (c) { case '0': case '1': count++; break; default: other++; break; }
break न लगाओ तो अगले केस में अपने आप चला जाता है (fall-through)। जेएस में भी यही होता है। case में सिर्फ पूर्णांक या अक्षर के स्थिर मान चलते हैं। while और for जेएस जैसे हैं। for (;;) अनंत लूप है। कॉमा ऑपरेटर एक for में दो वेरिएबल चलाने के काम आता है: for (i = 0, j = n; i < j; i++, j--) do { } while (शर्त); शर्त बाद में जाँचता है, इसलिए कम से कम एक बार जरूर चलता है। break सबसे अंदर वाले लूप या switch से बाहर निकालता है। continue अगली बार पर कूद जाता है। goto लगभग कभी जरूरी नहीं। सिर्फ गहरे नेस्टेड लूप से बाहर निकलने में कभी-कभी काम आता है।
अध्याय 4: फंक्शन और प्रोग्राम की बनावट प्रोग्राम को छोटे फंक्शनों में तोड़ो। हर फंक्शन एक काम करे। return से मान लौटता है। रिटर्न टाइप लिखना न भूलो। बाहरी वेरिएबल: फंक्शन के बाहर घोषित वेरिएबल पूरी फाइल में दिखता है। दूसरी फाइल से इस्तेमाल के लिए वहाँ extern int sp; लिखना पड़ता है। हेडर फाइल (.h): साझा घोषणाएँ एक फाइल में रखकर #include "calc.h" से सब फाइलों में खींचते हैं। यह जेएस के export और import जैसा है।static बाहरी वेरिएबल या फंक्शन पर static लगाने से वह सिर्फ उसी फाइल में दिखता है, यानी निजी बन जाता है। फंक्शन के अंदर static वेरिएबल कॉल के बीच अपना मान याद रखता है। register: कंपाइलर को सुझाव है कि वेरिएबल तेज जगह रखो। आजकल इसका खास मतलब नहीं।ब्लॉक स्कोप: { } के अंदर घोषित वेरिएबल बाहर नहीं दिखता, और बाहर के उसी नाम को ढक देता है।शुरुआती मान: ऐरे में सूची से भर सकते हो: int days[] = {31, 28, 31};रिकर्शन: फंक्शन खुद को बुला सकता है, जैसे पायथन में। हर कॉल के लोकल वेरिएबल अलग होते हैं।प्रीप्रोसेसर (कंपाइल से पहले टेक्स्ट बदलने वाला टूल)
#include: फाइल का टेक्स्ट वहीं चिपका देता है। #define: नाम की जगह टेक्स्ट बदलता है। आर्गुमेंट वाला मैक्रो: #define max(A, B) ((A) > (B) ? (A) : (B))
मैक्रो में आर्गुमेंट दो बार गणना होता है, इसलिए max(i++, j++) गलत है। हर आर्गुमेंट को कोष्ठक में रखो। शर्तों वाला कंपाइल: #ifndef HDR #define HDR /* हेडर की सामग्री */ #endif
यह हेडर के दोबारा जुड़ने से बचाता है।
अध्याय 5: पॉइंटर और ऐरे यह किताब का सबसे जरूरी अध्याय है।
पॉइंटर वह वेरिएबल है जिसमें किसी दूसरे वेरिएबल का पता रहता है। &x का मतलब x का पता है। *p का मतलब p जिस जगह को दिखा रहा है वहाँ का मान है। int x = 1; int *ip; ip = &x; /* ip अब x को दिखा रहा है */ *ip = 5; /* x अब 5 है */
यह वैसा है जैसे जेएस में ऑब्जेक्ट का रेफरेंस होता है, पर यहाँ हर चीज का पता निकल सकता है। पॉइंटर से फंक्शन में मान बदलना
void swap(int *px, int *py) { int temp = *px; *px = *py; *py = temp; } swap(&a, &b);
कॉल बाय वैल्यू में सीधे बदलाव नहीं हो सकता। इसलिए पता भेजते हैं, और scanf("%d", &n) में भी इसीलिए & लगता है।
ऐरे का नाम उसके पहले तत्व का पता है। a[i] और *(a+i) बिल्कुल एक ही चीज हैं। p + 1 अगले तत्व को दिखाता है। पॉइंटर के टाइप के आकार के हिसाब से अपने आप कदम बनता है। फर्क: पॉइंटर वेरिएबल है (p++ चलेगा), पर ऐरे का नाम वेरिएबल नहीं (a++ गलत)। फंक्शन के पैरामीटर में char s[] और char *s एक ही हैं। एक ही ऐरे के दो पॉइंटर की तुलना और घटाना। पॉइंटर में पूर्णांक जोड़ना या घटाना। शून्य (NULL) से तुलना। दो पॉइंटर जोड़ना, गुणा या भाग गलत है। char amessage[] = "now is the time"; /* ऐरे: अक्षर बदल सकते हो */ char *pmessage = "now is the time"; /* पॉइंटर: स्ट्रिंग का अक्षर बदलना मना */
अक्षर कॉपी करने वाली मशहूर लाइन: अलग-अलग लंबाई की स्ट्रिंग संभालने के लिए char *lineptr[MAXLINES] बनाते हैं। छँटाई में सिर्फ पॉइंटर की अदला-बदली होती है, टेक्स्ट नहीं हिलता। int a[10][20]; /* असली 200 खानों वाली आयताकार तालिका */ int *b[10]; /* सिर्फ 10 पॉइंटर, हर पंक्ति अलग लंबाई की हो सकती है */
int main(int argc, char *argv[])
argc आर्गुमेंट की गिनती है। argv[0] प्रोग्राम का नाम है। यह नोड के process.argv और पायथन के sys.argv जैसा है। int (*comp)(void *, void *)
फंक्शन को आर्गुमेंट की तरह दे सकते हो, जैसे जेएस में कॉलबैक। छँटाई में तुलना का तरीका इसी से बदलते हैं। int *f(); का मतलब है कि f फंक्शन है जो int का पॉइंटर लौटाता है। int (*pf)(); का मतलब है कि pf फंक्शन का पॉइंटर है। कोष्ठक से बाहर की तरफ पढ़ो और जरूरत पड़े तो typedef से तोड़ो।
अध्याय 6: स्ट्रक्चर स्ट्रक्चर अलग-अलग टाइप के वेरिएबलों का समूह है। यह जेएस के ऑब्जेक्ट या पायथन की क्लास के डेटा जैसा है, पर इसमें मेथड नहीं होते।
struct point { int x; int y; }; struct point pt = {320, 200}; printf("%d,%d", pt.x, pt.y);
सदस्य को . से पाते हैं। स्ट्रक्चर का पॉइंटर हो तो -> लगाते हैं: pp->x स्ट्रक्चर को कॉपी, असाइन, फंक्शन को देना या लौटाना हो सकता है, पर == से तुलना नहीं हो सकती। बड़े स्ट्रक्चर के लिए पॉइंटर भेजना बेहतर है। स्ट्रक्चर के अंदर दूसरा स्ट्रक्चर आ सकता है। स्ट्रक्चर का ऐरे बनाकर तालिका बना सकते हो। sizeof बताता है कि कोई चीज कितने बाइट की है। ऐरे के तत्वों की गिनती sizeof arr / sizeof arr[0] से निकलती है। स्ट्रक्चर का आकार सदस्यों के योग से ज्यादा हो सकता है, क्योंकि बीच में खाली जगह (padding) आ जाती है। स्वयं को दिखाने वाला स्ट्रक्चर (लिंक्ड लिस्ट और पेड़)
struct tnode { char *word; int count; struct tnode *left; struct tnode *right; };
अपने अंदर अपना स्ट्रक्चर नहीं रख सकते, पर अपना पॉइंटर रख सकते हो। इसी से बाइनरी ट्री बनता है। malloc(n) n बाइट मेमोरी माँगता है और पता लौटाता है। न मिले तो NULL देता है। free(p) मेमोरी वापस करता है। free के बाद उस पॉइंटर को इस्तेमाल मत करो। नाम से एक छोटी संख्या निकालते हैं और उसी खाने की सूची में खोजते हैं। यह पायथन की डिक्शनरी जैसा है। यह किसी मौजूदा टाइप को नया नाम देता है। नया टाइप नहीं बनता।
एक ही जगह में अलग-अलग समय पर अलग-अलग टाइप का मान रहता है। जगह सबसे बड़े सदस्य जितनी लगती है। अभी कौन-सा टाइप रखा है, यह खुद याद रखना पड़ता है। एक शब्द के अंदर कुछ बिट को अलग नाम देकर रखते हैं। struct { unsigned int is_keyword : 1; unsigned int is_extern : 1; } flags;
यह मशीन पर निर्भर है, इसलिए पोर्टेबल कोड में कम इस्तेमाल करो।
अध्याय 7: इनपुट और आउटपुट इनपुट और आउटपुट C की भाषा का हिस्सा नहीं, स्टैंडर्ड लाइब्रेरी (<stdio.h>) का हिस्सा है। stdin कीबोर्ड है, stdout स्क्रीन है और stderr गलती संदेश की जगह है। शेल में < से इनपुट फाइल से आता है, > से आउटपुट फाइल में जाता है और | से एक प्रोग्राम का आउटपुट दूसरे को मिलता है। फॉर्मेट में चौड़ाई, सटीकता और दिशा भी दे सकते हो: %-10s, %6.2f, %.*s sprintf आउटपुट को स्ट्रिंग में रखता है। printf(s) खतरनाक है। हमेशा printf("%s", s) लिखो। बदलती संख्या के आर्गुमेंट
<stdarg.h> से ... वाले फंक्शन बनते हैं, जैसे जेएस के ...args या पायथन के *args। पैरामीटर हमेशा पॉइंटर होने चाहिए: scanf("%d", &n) & भूल गए तो कंपाइलर अक्सर नहीं पकड़ता। रिटर्न मान बताता है कि कितने मान सफलता से पढ़े गए। लाइन-दर-लाइन पढ़कर sscanf से तोड़ना ज्यादा सुरक्षित तरीका है। FILE *fp = fopen("name.txt", "r"); /* "r" पढ़ना, "w" लिखना, "a" जोड़ना */ if (fp == NULL) { /* खुली नहीं */ } int c = getc(fp); putc(c, fp2); fclose(fp);
fprintf, fscanf फाइल वाले printf, scanf हैं। fgets(line, max, fp) एक लाइन पढ़ता है। fputs स्ट्रिंग लिखता है। गलती संदेश fprintf(stderr, ...) से भेजो, ताकि आउटपुट फाइल में न मिले। exit(1) प्रोग्राम तुरंत बंद करता है। 0 का मतलब सफलता है और बाकी हर मान गड़बड़ी है। ferror और feof गलती और फाइल-अंत जाँचते हैं। स्ट्रिंग: strlen, strcpy, strcat, strcmp, strchr, strstr (<string.h>) अक्षर जाँच: isalpha, isdigit, isspace, toupper, tolower (<ctype.h>) गणित: sqrt, pow, sin, cos, exp, log, fabs (<math.h>) रैंडम: rand(), srand(seed) (<stdlib.h>) system("date") से ऑपरेटिंग सिस्टम की कमांड चलती है। ungetc एक अक्षर वापस इनपुट में डाल देता है।
अध्याय 8: यूनिक्स सिस्टम इंटरफेस इस अध्याय में बताया गया है कि स्टैंडर्ड लाइब्रेरी नीचे ऑपरेटिंग सिस्टम की किस सुविधा पर टिकी है।
फाइल डिस्क्रिप्टर एक छोटा पूर्णांक है जो खुली फाइल की पहचान है। 0 इनपुट, 1 आउटपुट और 2 गलती संदेश है।read(fd, buf, n) और write(fd, buf, n) सीधे बाइट पढ़ते और लिखते हैं। वापस गिनती देते हैं, और 0 का मतलब फाइल खत्म है। open, creat, close और unlink फाइल खोलते, बनाते, बंद करते और मिटाते हैं। lseek फाइल में किसी भी जगह कूदने देता है। FILE असल में एक स्ट्रक्चर है, जिसमें बफर, गिनती, अगली जगह और डिस्क्रिप्टर रखे होते हैं। getc एक मैक्रो है जो बफर खाली होने पर ही read बुलाता है। इससे बार-बार ऑपरेटिंग सिस्टम को नहीं पुकारना पड़ता और काम तेज होता है। डायरेक्टरी सूची: stat फाइल की जानकारी (साइज, प्रकार, अनुमतियाँ) देता है।malloc का सिद्धांत: खाली ब्लॉकों की सूची रखी जाती है, और हर ब्लॉक के आगे आकार का हेडर होता है। माँग आने पर सूची में पहला इतना बड़ा ब्लॉक ढूँढा जाता है। बड़ा हो तो काटकर हिस्सा दे दिया जाता है। free के समय पास के खाली ब्लॉक जोड़ दिए जाते हैं। मेमोरी की सही सीमा बनाए रखने के लिए union से अलाइनमेंट पक्का किया जाता है।
परिशिष्ट (संदर्भ) परिशिष्ट A C भाषा के नियमों की पूरी सूची है।परिशिष्ट B स्टैंडर्ड लाइब्रेरी के हर फंक्शन की सूची है। किसी फंक्शन की जानकारी चाहिए तो यहीं देखो।परिशिष्ट C पहले संस्करण से आए बदलावों का सार है।
याद रखने की 10 बातें सारे वेरिएबल टाइप के साथ घोषित करने पड़ते हैं। पूर्णांक भाग में दशमलव कट जाता है। स्ट्रिंग के अंत में '\0' होता है। फंक्शन को हमेशा कॉपी मिलती है। असली बदलाव के लिए पॉइंटर भेजो। a[i] का मतलब *(a+i) है। = असाइन करता है और == तुलना करता है। switch में break न लगाओ तो अगले केस में गिर जाता है। ऐरे की सीमा कोई नहीं जाँचता, यह तुम्हारी जिम्मेदारी है। malloc का NULL जाँचो और हर malloc के लिए free करो। मैक्रो में आर्गुमेंट को कोष्ठक में रखो।