C scope, storage duration और allocated ownership
उद्देश्य और भाषा contract
Name visibility को object lifetime से अलग करें, struct pointers trace करें, allocation failure में ownership न खोएँ और dangling aliases पहचानें। पूर्वज्ञान basic C functions और pointers है। ISO C11/C17 उपयोग करते हैं; pointer width, struct padding या allocator address reuse नहीं मानते। Code में <stdlib.h> और आवश्यकतानुसार <stddef.h>/<stdint.h> उपलब्ध हैं। Execution single-threaded है। Removal examples में अलग live nodes की acyclic list है; next, NULL या अगले live node को point करता है।
1. Scope declaration चुनता है; duration lifetime बताता है
Block scope बताता है कि local identifier कहाँ उपयोग हो सकता है। Automatic object सामान्यतः block छोड़ने तक जीवित है। Static storage duration पूरे program execution तक रहती है, भले name block-scoped हो। Allocated storage successful allocation से deallocation तक है; address रखने वाले pointer variable के scope से स्वतंत्र। Linkage अलग प्रश्न है: अलग declarations एक ही entity को refer करते हैं या नहीं।
Trace: int next(void) { static int count; int step=2; count+=step; return count; }. तीन calls 2,4,6 देती हैं। count एक बार zero initialize होता है और बचा रहता है; हर call में step नया initialized automatic object है। static int count को int count=0 करने पर हर call 2 देगा। Uninitialized automatic int अपने-आप zero नहीं है; उसकी indeterminate value पढ़कर deterministic trace नहीं बना सकते, और undefined behavior संभव है। Static arithmetic objects zero होते हैं; static pointers null pointer बनते हैं, जरूरी नहीं कि उनकी सभी bytes zero हों।
Shadowing केवल name lookup बदलता है, hidden object की lifetime नहीं। int x=5; { int x=9; x++; } के बाद outer x अभी 5 है। Inner x block exit पर समाप्त है। Ordinary automatic local का address return करने से lifetime नहीं बढ़ती; caller उस dangling result को dereference नहीं कर सकता। Block-static object का pointer function return के बाद valid रह सकता है, पर आगे के calls उसी shared object को बदल सकते हैं।
2. Struct value और struct pointer
struct Node { int value; struct Node next; }; के valid pointer p के लिए p->value का अर्थ (p).value है। Parentheses आवश्यक हैं क्योंकि . की precedence unary * से अधिक है। Null या dangling pointer से member access invalid है। Alignment padding के कारण sizeof(struct Node), sizeof(int)+sizeof(pointer) से अलग हो सकता है; इस sum से field offsets न निकालें।
Struct assignment member values copy करता है, reachable structure का deep copy नहीं। struct Node a का next, t को point करे और struct Node b=a हो, तो a तथा b अलग struct objects हैं, लेकिन उनके next pointers t को alias करते हैं। b.value बदलने से a.value नहीं बदलेगा। b.next->value बदलने से t बदलता है और a.next से भी बदलाव दिखता है। यह shallow copy है। इससे उसी allocation को free करने का दूसरा ownership अधिकार नहीं बनता।
3. नया node publish करने से पहले allocate करें
सुरक्षित constructor:
struct Node *make(int value, struct Node *next) { struct Node *p = malloc(sizeof *p); if (p == NULL) return NULL; p->value = value; p->next = next; return p; }
इस non-VLA type के लिए sizeof *p, p evaluate किए बिना struct size देता है। Initializer के समय p initialized नहीं, फिर भी यह access/dereference नहीं है। malloc uninitialized storage देता है; fields पढ़ने या pointer publish करने से पहले initialize करें। C में malloc declaration visible हो तो void cast आवश्यक नहीं। calloc bytes zero करता है; हर pointer member को portable null pointer बनाने की guarantee न मानें, pointer fields explicitly assign करें।
Safe prepend में p=make(7,head) लें। केवल p!=NULL पर head=p करें। Failure में head unchanged रखकर error दें। Potentially failing allocation result सीधे head में रखने से पुरानी storage की अकेली path खो सकती है। n objects allocate करते समय malloc(n*sizeof *p) से पहले n<=SIZE_MAX/sizeof *p जाँचें। Byte count wrap हुआ तो loop की अपेक्षा से छोटा buffer मिल सकता है। यहाँ zero-size allocations शामिल नहीं हैं; उनके return/free नियम किसी element access की अनुमति नहीं देते।
4. Ownership, aliases और free
Ownership algorithm का contract है, C type qualifier नहीं: कौन allocation को ठीक एक बार free करेगा, स्पष्ट रखें। Borrowed pointer live object access कर सकता है, लेकिन object से अधिक जीवित नहीं रह सकता और ownership transfer बिना free नहीं करेगा। free(NULL) valid no-op है। free को NULL या compatible allocator से मिला live allocation base चाहिए। Stack object address, interior pointer या पहले freed allocation नहीं।
Safe removal: head पहला allocated node own करता हो तो struct Node *old=head बचाएँ। old!=NULL पर पहले head=old->next, फिर free(old)। next को free से पहले पढ़ना जरूरी है; बाद का old->next use-after-free है। old का अलग observer alias भी dangling हो जाता है। free के बाद old=NULL केवल old बदलता है, दूसरे aliases नहीं। Portable traces में lifetime समाप्त होने के बाद stale pointer values को read, compare या dereference न करें। Allocator पुराना address दोबारा नहीं देगा, ऐसा अनुमान गलत है।
Positive new size के realloc में temporary लें: tmp=realloc(p,newbytes)। tmp==NULL पर p की पुरानी allocation जीवित तथा unchanged है; success पर p=tmp करें और returned pointer उपयोग करें। Success में old allocation की lifetime समाप्त है, भले address संख्या समान दिखे; aliases दोबारा जाँचें। Direct p=realloc(p,newbytes) failure पर अकेला owning pointer खो सकता है। Outer struct free करने से अलग allocated children अपने-आप free नहीं होते। Ownership graph follow करें; shared nodes दो बार free न हों।
Reasoning checklist
हर name का declaration/scope लिखें। हर object की duration, initialization, owner और live aliases लिखें। return/free/realloc पर अगली access से पहले lifetime update करें। Leak में owned storage deallocation बिना unreachable होती है; dangling pointer अपने object से अधिक जीता है। दोनों अलग bugs हैं और साथ हो सकते हैं।
मौलिक अभ्यास: छह single-correct MCQs
ये मौलिक शिक्षण प्रश्न हैं, previous-year questions नहीं। एक विकल्प चुनें।
P01. Function में static int c; फिर c+=2; return c; है। पहली तीन calls?
A. 2,2,2 B. 2,4,6 C. Indeterminate values D. 0,2,4
उत्तर: B
A: यह fresh zero-initialized automatic c का व्यवहार है।
B: c एक बार zero होता है और calls के बीच बचता है।
C: Static c की zero initialization defined है।
D: हर return से पहले increment है।
P02. struct Node b=a और a.next live t को point करता है। क्या guaranteed है?
A. b.next नया cloned t बताता है B. b और a वही struct object हैं C. b.next और a.next शुरू में वही t बताते हैं D. दोनों को अलग-अलग t free करने का अधिकार है
उत्तर: C
A: Struct assignment reachable allocations clone नहीं करता।
B: अलग object में values copy होती हैं।
C: Pointer values copy होकर aliases बनते हैं।
D: Shallow copy ownership दोहरा नहीं करता।
P03. malloc(sizeof *p) के NULL लौटाने पर constructor क्या करे?
A. Check से पहले p->value लिखे B. Caller की पुरानी list हमेशा free करे C. NULL को allocated empty node माने D. p dereference किए बिना failure बताए
उत्तर: D
A: NULL member access invalid है।
B: Failure पर पुराना state मिटाना उचित नहीं।
C: यहाँ NULL failure है, object नहीं।
D: Fields access से पहले result जाँचें।
P04. free के लिए valid argument कौन है?
A. NULL B. Automatic local int का address C. Live malloc allocation के भीतर एक element आगे pointer D. पहले deallocate हुई allocation का nonnull pointer
उत्तर: A
A: free(NULL) defined no-op है।
B: Automatic storage allocator से नहीं मिली।
C: Interior pointer allocation base नहीं।
D: Double free undefined behavior है।
P05. Positive size में tmp=realloc(p,n), NULL लौटाकर fail हुआ। Original allocation का क्या हुआ?
A. हमेशा free हो गई B. p से live और unchanged है C. Zero-filled हो गई D. Size निश्चित n हो गया
उत्तर: B
A: Failure original allocation बचाता है।
B: Temporary से p recovery/free के लिए बचा है।
C: Failure पुराने contents initialize नहीं करता।
D: Resize सफल नहीं हुआ।
P06. Nonnull allocated head node को सुरक्षित हटाने का क्रम?
A. free(head); head=head->next; B. old=head; free(old); head=old->next; C. old=head; head=old->next; free(old); D. head=head->next; free(head);
उत्तर: C
A: Freed node पढ़ता है।
B: यह भी free के बाद old->next पढ़ता है।
C: Lifetime समाप्त होने से पहले link बचाएँ।
D: पुराना node खोता है; nonnull successor को free करता है, या NULL होने पर no-op है।
स्रोत और दायरा
GATE CS 2026 के मौजूदा आधार-पाठों का सीमित विस्तार। पूरे विषय की पूर्णता का दावा नहीं। उदाहरण और प्रश्न मौलिक हैं।
प्रगति सहेजने के लिए साइन इन करें। साइन इन