5.1.21 · D2 · HinglishC Programming

Visual walkthroughSafe alternatives — strncpy, snprintf, strlcpy

2,515 words11 min read↑ Read in English

5.1.21 · D2 · Coding › C Programming › Safe alternatives — strncpy, snprintf, strlcpy


Step 1 — Buffer actually kya hota hai: boxes ki ek fixed row

KYA. C mein, char buf[8] ek "string" nahi hai. Yeh exactly 8 numbered boxes ki ek wall hai, har ek mein ek byte (ek character) hota hai. Boxes 0, 1, 2, 3, 4, 5, 6, 7 — 0 se shuru hote hain, isliye aakhri box number 7 hai, 8 nahi.

KYU. Safe-vs-unsafe ka har sawaal asliyat mein yeh hai: "humne kaunse box mein likha?" Agar humne kabhi box 8 mein likha, toh woh box hamara nahi hai — woh us variable ka hai jise compiler ne aage park kiya. Wahan likhna wahi buffer overflow hai jis poore topic ke baare mein baat ho rahi hai. Toh kuch bhi karne se pehle, hum boxes draw karte hain aur cliff edge mark karte hain.

PICTURE. Aath boxes. Box 7 aakhri legal box hai (red). Box 8 aur uske baad cliff hai — humara nahi.

Figure — Safe alternatives — strncpy, snprintf, strlcpy

Step 2 — Boxes ki ek row ko string kya banata hai: null terminator

KYA. Bytes ki ek row tab hi C string banti hai jab kisi box mein special byte '\0' ho (value zero, "null terminator"). strlen aur printf jaise reading functions left-to-right chalte hain aur jis instant '\0' milta hai, ruk jaate hain. Woh box end-of-string sign hai.

KYU hum is ek byte ki itni parwah karte hain? Kyunki kuch aur nahi batata ki string kahan khatam hoti hai. Kahi koi hidden length store nahi hoti. Agar '\0' missing hai, toh reader box 7 par nahi rukta — woh box 8, 9, 10... mein chalte rehta hai, unrelated memory mein koi zero byte randomly milne tak garbage read karta rehta hai. Toh '\0' decoration nahi hai; yeh brake hai. (sizeof vs strlen dekho: sizeof boxes count karta hai, strlen brake se pehle characters count karta hai.)

PICTURE. Word hi boxes mein stored: box 0 mein 'h', box 1 mein 'i', aur box 2 mein red '\0' brake. Ek reader arrow andar aata hai aur red box par cheekhte hue ruk jaata hai.

Figure — Safe alternatives — strncpy, snprintf, strlcpy

Step 3 — Unsafe baseline: strcpy wall ko kabhi nahi dekhta

KYA. strcpy(dest, src) characters ko src se dest mein, box by box copy karta hai, aur tabhi rukta hai jab woh source ka apna '\0' copy karta hai. Yeh kabhi check nahi karta. Yeh nahi jaanta, aur poochta bhi nahi, ki dest ke paas kitne boxes hain.

KYU villain ko pehle dikhayein? Kyunki har "safe" function usi se define hota hai jo woh is behaviour mein add karta hai. Fix dekhne ke liye, tumhe pehle crime hote dekhna hoga.

PICTURE. strcpy(buf, "hello world") — source 11 characters + ek '\0' = 12 bytes — 8 boxes mein daala gaya. Pour boxes 0–7 bharti hai, phir cliff ke paas box 8, 9, 10, 11 mein chalti rehti hai — memory jo hamari nahi hai.

Figure — Safe alternatives — strncpy, snprintf, strlcpy

Step 4 — strncpy: n boxes ke baad ruko — lekin brake watch karo

KYA. strncpy(dest, src, n) zyada se zyada n boxes copy karta hai aur phir count karna band kar deta hai. Do outcomes:

  • Agar source (apne '\0' ke saath) n se chhota hai: sab copy karta hai, phir baaki boxes ko '\0' se fill karta hai (zero-padding).
  • Agar source n boxes ya zyada hai: exactly n characters likhta hai aur ruk jaata hai — bina koi '\0' add kiye.

KYU yahan yeh matter karta hai? strncpy ne overflow theek kar diya (woh kabhi box n-1 se aage nahi likhta), lekin doosre outcome mein woh brake bhool jaata hai. Humne sahi jagah likhna band kiya, phir bhi hum koi end-of-string sign nahi chhor rahe. Row overflow se safe hai lekin valid string nahi hai.

PICTURE. Do rows, same buffer, same n = 8:

  • Top row: strncpy(buf, "hi", 8)'h' 'i' phir chhe red '\0' pads. Valid string (luck se — source chhota tha).
  • Bottom row: strncpy(buf, "0123456789", 8) → boxes 0–7 mein 0..7 hain, aur box 7 red hai kyunki woh aakhri box hai bina kisi brake ke. Ek reader arrow box 7 se seedha cliff mein uda jaata hai.
Figure — Safe alternatives — strncpy, snprintf, strlcpy

Call ko term-by-term padhna:


Step 5 — snprintf: brake ke liye hamesha aakhri box reserve karo

KYA. snprintf(dest, size, fmt, ...) text format karta hai (jaise printf, dekho Format strings and printf family) lekin zyada se zyada size bytes likhta hai total, aur woh total '\0' include karta hai. Jab tak size > 0 ho, yeh hamesha brake stamp karta hai. Isse guarantee karne ke liye, woh visible text ko happily cut kar dega taaki brake aakhri box mein fit ho sake.

KYU yeh woh behaviour hai jo strncpy ko hona chahiye tha? strncpy ka n sirf characters count karta tha aur brake ko crowd out kar sakta tha. snprintf ka size poori row including brake count karta hai — toh brake pehle carved out hoti hai, aur text ko jo bacha woh milta hai: zyada se zyada characters. Overflow AND missing-brake problem dono ek baar mein chale jaate hain.

PICTURE. snprintf(buf, 8, "id=%d", 12345). Poora text id=12345 8 characters chahta hai (9 boxes chahiye). Sirf 8 boxes hain, toh snprintf boxes 0–6 mein id=1234 likhta hai aur box 7 mein red '\0' dalta hai. Truncated 5 cliff ke baad greyed-out dikhaya gaya hai — woh likhna chahta tha.

Figure — Safe alternatives — strncpy, snprintf, strlcpy

Step 6 — strlcpy: time par ruko, hamesha brake karo, wasteful padding nahi

KYA. strlcpy(dest, src, size) zyada se zyada size - 1 characters copy karta hai, phir hamesha '\0' stamp karta hai — aur, strncpy ke unlike, woh baaki boxes ko zero-pad nahi karta. Yeh strlen(src) return karta hai: woh length jo usne copy karne ki koshish ki.

KYU yeh "best behaved" earn karta hai? Steps 4–6 line up karo:

  • Yeh kabhi overflow nahi karta ( par cap) — strncpy ka acha wala half.
  • Yeh hamesha brake lagata haisnprintf ka acha wala half.
  • Yeh pointless padding skip karta haistrncpy se sasta.

Yeh strncpy hai jisme trap hata diya gaya hai. (Parent se caveat: non-standard hai — BSD/macOS, aur glibc sirf 2.38 se — isliye portable code hamesha iss par rely nahi kar sakta.)

PICTURE. strlcpy(buf, "0123456789", 8). characters par cap → boxes 0–6 mein 0123456 hai, box 7 ko red brake milti hai. Return value (poori source length) upar float karti hai, 10 ≥ 8 lost data flag karta hua.

Figure — Safe alternatives — strncpy, snprintf, strlcpy


Step 7 — Degenerate cases jo koi draw nahi karta (lekin tumhe karne chahiye)

Upar har function ne assume kiya size > 0 aur ek sane buffer. Edges par kya hota hai.

Case A — size == 0. Likhne ke liye zero boxes hain. snprintf aur strlcpy bilkul kuch nahi likhte (woh brake bhi nahi rakh sakte — koi box nahi hai). snprintf phir bhi would-be length return karta hai; strlcpy phir bhi strlen(src) return karta hai. Lesson: "hamesha null-terminate karta hai" ka promise fine print hai "agar size > 0 ho". Bina boxes ke brake nahi hai.

Case B — source exactly tak fill karta hai. e.g. 8-box buffer mein 7-character source. strncpy(buf, "1234567", 8) 7 chars copy karta hai aur — kyunki 7 < 8 — box 7 ko '\0' se pad karta hai. Yahan strncpy brake lagata hai, purely isliye kyunki source trouble se ek char chhota tha. strlcpy/snprintf bhi brake lagate hain. Charon sirf is lucky-fit case mein agree karte hain — yahi wajah hai ki strncpy ka trap casual testing mein itni aasaani se miss ho jaata hai.

Case C — empty source "". Teeno box 0 mein ek '\0' likhte hain aur ruk jaate hain. Perfectly valid empty string. snprintf 0 return karta hai, strlcpy 0 return karta hai. Koi truncation nahi ().

PICTURE. Teen mini-rows stacked: (A) size 0 — ek empty greyed row, arrow box 0 par red mein block; (B) exact-fit — 7 chars + ek brake jo fit ho jaati hai; (C) empty source — box 0 mein akela red brake.

Figure — Safe alternatives — strncpy, snprintf, strlcpy

Ek-picture summary

Ek hi wall of boxes par sab kuch. Same buffer char buf[8] (), same oversized source "0123456789", chaar functions, chaar rows. Sirf box 7 aur cliff dekho:

  • strcpy — cliff ke past pour karta hai (red overflow). ✗
  • strncpy — box 7 par rukta hai, koi brake nahi (red missing-brake). ✗ jab tak tum add na karo.
  • snprintf — text 7 chars tak cut, box 7 mein brake (red brake). ✓
  • strlcpy — same safe result, box 7 mein brake, poori length return karta hai. ✓
Figure — Safe alternatives — strncpy, snprintf, strlcpy
Recall Feynman retelling — plain words mein poora walkthrough

Buffer bas ek chhoti shelf hai numbered boxes ki; char buf[8] hume boxes 0 through 7 deta hai aur kuch nahi (Step 1). Boxes ki ek row tabhi "string" count hoti hai jab ek box mein ek stop sign ho jise '\0' kehte hain — readers shelf walk karte hain aur sign par ruk jaate hain, aur agar sign nahi hai toh woh shelf ke end se march karte hue strangers ke boxes mein chale jaate hain (Step 2). strcpy laaparwah hai: woh tab tak copy karta rehta hai jab tak source ka stop sign nahi milta, yeh ignore karte hue ki hamari shelf mein actually kitne boxes hain, isliye lamba source shelf se spill ho jaata hai — yahi overflow hai (Step 3). strncpy kehta hai "main zyada se zyada n boxes copy karunga" — yeh spill rok deta hai — lekin agar source lamba ho toh woh sare n boxes use kar leta hai aur stop sign chhodna bhool jaata hai, isliye hume ek ko aakhri box mein khud dalna padta hai aur copy sirf tak karni padti hai taaki woh fit ho (Step 4). snprintf samajhdaar hai: uska size poori shelf including stop sign count karta hai, isliye woh pehle aakhri box stop sign ke liye reserve karta hai aur text ko fit hone ke liye chhota karta hai — yeh hamesha valid string chhorta hai aur apne return value ke through batata hai ki text kitna lamba hona chahta tha taaki tum r ≥ size se truncation spot kar sako (Step 5). strlcpy polite wala hai: par cap, hamesha sign chhordta hai, padding mein time waste nahi karta, aur source ki sachi length return karta hai (Step 6). Edges par: size 0 ke saath sign ke liye ek bhi box nahi, isliye "hamesha terminate karta hai" quietly fail ho jaata hai; jab source ek box spare ke saath exactly fit ho jaata hai, tab bhi strncpy theek lagta hai — yahi trap hai; aur empty source bas box 0 mein ek akela stop sign plant karta hai (Step 7). Ek number jo poora show chalata hai woh hai : capacity minus woh ek box jo stop sign ke liye reserved hai.


Connections

  • ← Back to the topic note
  • 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