5.1.21 · D3 · Coding › C Programming › Safe alternatives — strncpy, snprintf, strlcpy
Intuition Yeh page kya hai
Parent note par tumne rules seekhe the. Yahan hum har rule ko har case ke against stress-test karte hain : short source, exact-fit source, oversized source, empty source, size = 0, ek real-world path-join, aur ek exam trap. Is page ke end tak tum har function ko har boundary par behave karte hue dekh chuke hoge — koi bhi scenario unseen nahi rahega.
Shuru karne se pehle, ek choti si picture jo har example mein kaam aati hai. C capacity wala char array bas C numbered boxes hota hai. Ek valid C string ek box invisible end-marker '\0' (the "knot") ke liye use karta hai. Toh sabse zyada visible characters jo tum store kar sakte ho woh C − 1 hai. Dekho C strings and the null terminator .
Har woh case jo ek copy function ko hit kar sakta hai, inhi cells mein se ek hai. Har column source text aur destination capacity C ke beech ek length relationship hai; har degenerate row ek edge input hai.
Cell
Situation
Kya hona chahiye
Kaunsa example
A
src, C − 1 se chota hai
fully copies + terminate karta hai; spare room
Ex 1
B
src ki length exactly C − 1
bilkul fit hota hai, terminate karta hai, koi truncation nahi
Ex 2
C
src ki length exactly C
the trap — strncpy knot drop kar deta hai
Ex 3
D
src, C se bahut lamba
truncation, usse detect karo
Ex 4
E
src empty ("")
sirf '\0' likhta hai
Ex 5
F
size = 0 pass kiya
function ko kuch bhi touch nahi karna chahiye
Ex 6
G
real-world: ek path banao, overflow detect karo
snprintf + return check
Ex 7
H
exam twist: chained copies, off-by-one
knot ke baare mein reason karo
Ex 8
Hum char buf[8] (C = 8 ) almost har jagah use karte hain, isliye index 7 last box hai aur C − 1 = 7 hamara content cap hai.
char buf [ 8 ];
strncpy (buf, "hi" , sizeof (buf)); // src = "hi", 2 chars
Forecast: aage padhne se pehle buf ke 8 bytes guess karo. '\0' kahan land karega?
Step 1 — 2 real characters copy karo. 'h' → box 0, 'i' → box 1.
Yeh step kyun? strncpy src se tab tak copy karta hai jab tak ya toh src khatam ho jaye ya n bytes ho jaayein. src pehle khatam ho jaata hai (2 < 8).
Step 2 — baaki sab '\0' se pad karo. Boxes 2–7 sab '\0' ban jaate hain.
Yeh step kyun? Yeh strncpy ka special short-source behaviour hai: yeh poora n zeros se fill karta hai. Isliye yahan hum lucky hain — ek valid, terminated string bina kisi manual fix ke.
Result bytes: 'h' 'i' '\0' '\0' '\0' '\0' '\0' '\0'.
Verify: strlen(buf) boxes mein pehle '\0' tak chalta hai → box 2 par rukta hai → length 2 . printf("%s", buf) hi print karta hai. Terminated, safe. Dekho sizeof vs strlen ki kyun strlen knot tak count karta hai, capacity tak nahi.
char buf [ 8 ];
strncpy (buf, "1234567" , sizeof (buf)); // 7 chars, C-1 = 7
Forecast: box 7 mein ek real character hai ya '\0'?
Step 1 — saare 7 characters copy karo. '1'..'7' → boxes 0–6.
Yeh step kyun? 7 chars exactly n-1 hai, toh saare pehle 7 boxes ke andar fit ho jaate hain aur box 7 abhi bhi free rahta hai.
Step 2 — ek padding byte. Sirf box 7 bachta hai, toh strncpy wahan '\0' likhta hai.
Yeh step kyun? Source (7) abhi bhi n (8) se chota hai, toh padding ek bache hue box ke liye kick in karti hai. Result ek baar phir lucky se terminated hai — source exactly C − 1 tha, C nahi.
Result: "1234567" + '\0', exactly 8 bytes.
Verify: strlen(buf) == 7, sizeof(buf) == 8. Yeh sabse bada source hai jise strncpy khud se terminate karta hai. Ek character aur (Ex 3) ise tod deta hai.
char buf [ 8 ];
strncpy (buf, "01234567" , sizeof (buf)); // 8 chars, exactly C
Forecast: is line ke baad buf mein kitne '\0' bytes hain? (Jawab shock kar sakta hai.)
Step 1 — exactly n = 8 characters copy karo. '0'..'7' boxes 0–7 fill karte hain. Yeh saare 8 boxes use ho gaye .
Yeh step kyun? strncpy at most n copy karta hai; yahan src 8 supply karta hai aur n bhi 8 hai, toh yeh saare 8 copy karta hai aur ruk jaata hai. Koi leftover box nahi hai.
Step 2 — koi padding nahi, toh koi '\0' nahi. Kyunki n boxes mein se har ek ko ek real character mila, padding rule kabhi fire nahi hua.
Yeh step kyun important hai: buf ab string nahi hai — iske paas koi end-marker nahi hai. strlen(buf) box 7 se aage neighboring memory mein chala jaata hai (undefined behaviour, dekho Memory safety and undefined behavior aur Buffer overflow and stack smashing ).
Step 3 — mandatory fix.
buf [ sizeof (buf) - 1 ] = ' \0 ' ; // buf[7] = '\0'
Yeh step kyun? Hum knot lagane ke liye box 7 ka '7' sacrifice karte hain, garbage ko ek valid, truncated string "0123456" mein badal dete hain.
Verify: fix se pehle, buf[7] == '7' ('\0' nahi). Fix ke baad, strlen(buf) == 7 aur last char '6' hai. '7' kho gaya — yeh truncation ki kimat hai, lekin program ab safe hai.
char a [ 8 ], b [ 8 ], c [ 8 ];
strncpy (a, "0123456789" , sizeof (a)); // 10 chars
a [ 7 ] = ' \0 ' ; // manual fix
int rb = snprintf (b, sizeof (b), " %s " , "0123456789" );
size_t rc = strlcpy (c, "0123456789" , sizeof (c)); // BSD/glibc>=2.38
Forecast: teen buffers, teen return values. a, b, c ka content aur numbers rb, rc predict karo.
Step 1 — strncpy path. Boxes 0–7 = "01234567" copy karta hai, koi knot nahi; manual a[7]='\0' se "0123456" milta hai.
Kyun? Ex 3 jaisa hi trap, aur humne fix already apply kar diya.
Step 2 — snprintf path. Yeh '\0' ke liye last byte pehle se reserve kar leta hai, toh 7 chars "0123456" + '\0' likhta hai, phir woh length return karta hai jo use chahiye tha : strlen("0123456789") == 10, toh rb == 10.
Yeh step kyun? snprintf content ko box 7 touch nahi karne deta — woh box knot ke liye pre-booked hai. Dekho Format strings and printf family .
Step 3 — strlcpy path. size-1 = 7 chars "0123456" tak copy karta hai, hamesha terminate karta hai, strlen(src) == 10 return karta hai, toh rc == 10.
Kyun? snprintf jaisa hi "always tie the knot" contract, lekin koi format string nahi.
Verify — teeno destinations identical strings hain "0123456" (7 chars):
strlen(a) == strlen(b) == strlen(c) == 7.
Truncation detection: rb (10) >= sizeof(b) (8) ✔ aur rc (10) >= sizeof(c) (8) ✔.
strncpy koi built-in truncation flag nahi deta — isliye exactly yahi reason hai ki ise babysitting ki zaroorat hai.
char buf [ 8 ];
strlcpy (buf, "" , sizeof (buf)); // src = "" (0 visible chars)
Forecast: kitne bytes likhe jaate hain aur strlcpy kya return karta hai?
Step 1 — zero characters copy karo. src ke '\0' se pehle kuch nahi hai, toh koi real char copy nahi hota.
Kyun? Copy loop pehle byte par hi immediately khatam ho jaata hai, jo already '\0' hai.
Step 2 — terminate karo. strlcpy phir bhi box 0 mein '\0' likhta hai (uska "always terminate" promise, kyunki size = 8 > 0).
Yeh step kyun? Empty result bhi ek valid string honi chahiye; strlen 0 padhe isliye box 0 mein knot hona zaroori hai.
Verify: strlen(buf) == 0, return value == strlen("") == 0. Aur 0 >= 8 false hai → koi truncation nahi, correctly.
char buf [ 8 ];
buf [ 0 ] = 'X' ; // sentinel jo hum watch kar sakte hain
int r = snprintf (buf, 0 , "hello" ); // size = 0!
Forecast: kya buf[0] change hota hai? r kya hai?
Step 1 — size = 0 ke saath, kuch bhi mat likho. Contract kehta hai "'\0' including at most size bytes". size = 0 ke saath knot ke liye bhi room nahi hai, toh snprintf koi memory touch nahi karta .
Yeh step kyun? Yahi guard hai jo tumhe pehle snprintf(NULL, 0, fmt, ...) call karne deta hai sirf needed length measure karne ke liye — ek bahut common two-pass trick.
Step 2 — phir bhi would-be length report karo. Yeh strlen("hello") == 5 return karta hai.
Kyun? Return value independent hai ki kitna fit hua; yeh hamesha woh report karta hai jo ek full write ko chahiye hota .
Verify: buf[0] abhi bhi 'X' hai (untouched), aur r == 5. Note: strncpy(dest, src, 0) bhi kuch copy nahi karta aur, dangerously, kuch terminate bhi nahi karta — kabhi mat maan lo ki n=0 tumhe ek valid string deta hai.
Ek program ek fixed buffer mein filename "<dir>/<name>" build karta hai aur agar woh truncate hota toh use proceed karne se refuse karna chahiye.
char path [ 16 ];
int r = snprintf (path, sizeof (path), " %s / %s " , "logs" , "output.txt" );
if (r >= ( int ) sizeof (path)) {
/* truncated — error handle karo, path use mat karo */
}
Forecast: "logs/output.txt" — iske characters gino. Kya yeh 16 boxes mein fit hota hai? r kya hai, aur kya if fire karta hai?
Step 1 — intended text compute karo. "logs" (4) + "/" (1) + "output.txt" (10) = 15 visible chars .
Yeh step kyun? Hume knot ke baare mein reason karne ke liye content length chahiye: 15 content chars ko 16 bytes chahiye (15 + 1). Dekho C strings and the null terminator .
Step 2 — kya yeh fit hota hai? Capacity 16 hai, needed 16 hai → yeh exactly fit hota hai. snprintf saare 15 chars boxes 0–14 mein aur '\0' box 15 mein likhta hai.
Kyun? snprintf ki cap size hai including the knot; 15 + 1 = 16 = size , sabse tightest possible fit.
Step 3 — return value aur guard. r == 15 (would-be length, '\0' excluding). Test r >= sizeof(path) hai 15 >= 16 → false , toh if fire nahi karta: koi truncation nahi, path use karo.
Yeh step kyun? Yeh professional pattern hai — banao, phir result trust karne se pehle overflow catch karne ke liye return ko capacity se compare karo.
Verify: strlen(path) == 15; path equals "logs/output.txt"; 15 >= 16 false hai. Agar directory mein ek aur character hota ("logs2"), toh needed hota 16 content + 1 = 17 > 16, toh r == 16, 16 >= 16 true, guard fire karta — use mentally ek mini-drill ki tarah try karo.
Exam prompt: "Yeh run hone ke baad, printf("%s", buf) kya print karta hai, aur line 3 kyun essential hai?"
char buf [ 5 ];
strncpy (buf, "abcde" , sizeof (buf)); // 1: 5 chars into C=5
buf [ sizeof (buf) - 1 ] = ' \0 ' ; // 2
strncpy (buf, "ab" , sizeof (buf)); // 3
Forecast: abhi compute mat karo — final visible string guess karo.
Step 1 — line 1 phir se Cell C hai. 5 chars 5 boxes mein = "abcde", koi '\0' nahi (trap).
Kyun? Source length n ke equal hai, padding kabhi fire nahi hoti. (Yeh exactly Ex 3 hai C = 5 par.)
Step 2 — line 2 knot lagata hai. buf[4] = '\0' → "abcd" ('e' overwrite ho jaata hai).
Kyun? Iske bina, buf ek string nahi hai. Iske baad, strlen == 4.
Step 3 — line 3 short source ke saath overwrite karta hai. "ab" 2 chars hai < n = 5, toh strncpy 'a','b' copy karta hai phir boxes 2,3,4 ko '\0' se pad karta hai .
Yeh kyun matter karta hai: padding pehle ke leftover 'c','d' ko wipe kar deta hai — ek short source clean up karta hai kyunki yeh n tak zero-fill karta hai. Toh final buffer bina kisi additional manual fix ke fully re-terminated hai.
Verify: final bytes 'a' 'b' '\0' '\0' '\0'; strlen(buf) == 2; printf ab print karta hai. Line 2 sirf intermediate state ke liye essential hai — lekin agar line 1 aur 3 ke beech mein kisi code ne line 1 ka trailing garbage padha hota, toh woh undefined behaviour hota, isliye tum kabhi bhi ek strncpy ko momentarily bhi un-terminated nahi chhodte.
Recall Har cell ka ek-line summary
Short src safely pad karta hai; exact-C-1 fit hota hai aur terminate karta hai; exact-C trap hai (strncpy knot drop kar deta hai); oversized truncate karta hai (r >= size se detect karo); empty sirf ek knot likhta hai; size=0 kuch touch nahi karta; real code return ko capacity se compare karta hai; aur ek short source re-copy zero-fill karke purana garbage saaf kar deta hai.
Kaun sa cell hai jo silently ek unterminated string produce karta hai? Cell C — source length exactly capacity C ke equal hai, toh strncpy saare C bytes copy karta hai aur koi '\0' add nahi karta.
Ex 7 mein, guard r >= sizeof(path) fire kyun nahi karta? Intended text 15 chars hai jise 16 bytes chahiye, capacity 16 hai, toh yeh exactly fit hota hai; r == 15 aur 15 >= 16 false hai.
Ex 8 mein, line 3 bina manual fix ke termination kyun restore kar deta hai? "ab" n se chota hai, toh strncpy boxes 2–4 ko '\0' se pad karta hai, pehle ka content clean up karke automatically terminate kar deta hai.
Parent · Safe alternatives
C strings and the null terminator
Buffer overflow and stack smashing
strcpy and sprintf (unsafe)
sizeof vs strlen
Format strings and printf family
Memory safety and undefined behavior