Exercises — Safe alternatives — strncpy, snprintf, strlcpy
5.1.21 · D4· Coding › C Programming › Safe alternatives — strncpy, snprintf, strlcpy
Poore note mein, ek single mental picture yaad rakho jo sab kuch govern karti hai: ek buffer ek numbered boxes ki row hai. char buf[8] aath boxes hain, numbered 0 se 7 tak. C string tab hi valid string hoti hai jab un boxes mein se ek mein byte '\0' ho (the "null terminator" — dekho C strings and the null terminator); woh byte woh fence hai jo har reader ko batata hai "text yahan khatam hota hai." Overflow matlab hai kisi aisi box mein likhna jo exist hi nahi karti (box 8 aur uske aage).

Level 1 — Recognition
(Kya tum functions ko sirf unke contract se alag kar sakte ho?)
Exercise L1.1
Har function ko uske boundary par hone wale behaviour se match karo (jab source itni lambi ho ki fit na ho):
- (a) exactly
nbytes copy karta hai, koi'\0'nahi chodta - (b) total
sizebytes likhta hai maximum aur hamesha ek'\0'chodta hai - (c) buffer ke end ke past koi check kiye bina likhta hai
Functions: strcpy, strncpy, snprintf.
Recall Solution
strcpy→ (c). Yeh sirf source ke apne'\0'par rukta hai; yeh kabhi destination size nahi dekhta. Yeh woh unsafe function hai strcpy and sprintf (unsafe) se.strncpy→ (a).npar cap hai, lekin ek full/overflowing source par yeh exactlynbytes likhta hai aur koi terminator nahi add karta — woh trap.snprintf→ (b). Total bytes written ≤size, aur yeh'\0'ke liye last box reserve karta hai, isliye result hamesha ek valid string hota hai jabsize > 0ho.
Exercise L1.2
Har function ke liye, return value ka kya matlab hai?
strncpy, snprintf, strlcpy.
Recall Solution
strncpydestreturn karta hai (woh pointer jo tumne pass kiya) — truncation detect karne ke liye useless.snprintfun characters ki count return karta hai jo yeh likhta,'\0'exclude karke. Truncation tab hua jabreturn >= size.strlcpystrlen(src)return karta hai — woh full length jise yeh copy karne ki koshish kar raha tha. Truncation tab hua jabreturn >= size.
Pattern: snprintf aur strlcpy dono tumhe ek number dete hain jise tum size se compare kar sako. strncpy kuch bhi useful nahi deta.
Level 2 — Application
(Ab exact bytes compute karo. Boxes draw karo.)
Exercise L2.1
char buf[6];
strncpy(buf, "abc", sizeof(buf));buf ke saare 6 bytes likhko. Kya yeh ek valid C string hai?
Recall Solution
sizeof(buf) 6 hai (chhe boxes — dekho sizeof vs strlen yeh samajhne ke liye ki sizeof array ki box count kyun deta hai, text length nahi). Source "abc" 3 visible chars plus apna '\0' = 4 bytes hai, jo n = 6 se choti hai.
strncpy a b c \0 copy karta hai, phir baaki boxes ko '\0' se pad karta hai:
Valid string? Haan — box 3 mein '\0' hai, isliye strlen(buf) == 3. Yahan safe hai purely isliye kyunki source choti thi.
Exercise L2.2
char buf[6];
strncpy(buf, "abcdef", sizeof(buf));Saare 6 bytes likhko. Kya yeh valid C string hai? Fix kya hai?
Recall Solution
"abcdef" 6 visible chars hai. n = 6. strncpy exactly 6 bytes content copy karta hai:
Kahi bhi '\0' nahi — source ne poora byte budget fill kar diya, isliye fence ke liye koi box nahi bachi.
Valid? Nahi. strlen(buf) box 5 se adjacent memory mein run off kar deta (undefined behaviour — dekho Memory safety and undefined behavior).
Fix:
strncpy(buf, "abcdef", sizeof(buf) - 1); // cap at 5
buf[sizeof(buf) - 1] = '\0'; // box 5 = fenceAb buf = a b c d e '\0', jo truncated string "abcde" deta hai (strlen == 5).
Exercise L2.3
char buf[6];
int r = snprintf(buf, sizeof(buf), "val=%d", 42);buf mein kya hai? r kya hai? Kya truncation hua?
Recall Solution
"val=42" 6 visible chars hai, jise 7 bytes chahiye (6 + '\0'). Sirf 6 boxes hain, aur snprintf hamesha last box reserve karta hai '\0' ke liye. Isliye yeh 5 content chars + terminator likhta hai:
giving buf = "val=4".
r woh length hai jo yeh produce karta = strlen("val=42") = 6.
Truncation check: → true, truncation hua. (Dekho Format strings and printf family yeh samajhne ke liye ki %d kaise expand hota hai.)
Level 3 — Analysis
(Subtle cases: zero, exact-fit, ek hi input par tools compare karna.)
Exercise L3.1
char buf[8];
size_t r = strlcpy(buf, "0123456789", sizeof(buf));buf aur r do. Phir compare karo: strncpy(buf, "0123456789", sizeof(buf)) ki jagah kya chodta?
Recall Solution
strlcpy content ko size - 1 = 7 par cap karta hai aur hamesha terminate karta hai:
isliye buf = "0123456". Yeh strlen(src) = 10 return karta hai (woh full length jise yeh try kiya). → truncation detected, ek line mein, free.
Contrast karo strncpy se same call ke saath: yeh exactly 8 content bytes 0 1 2 3 4 5 6 7 copy karta hai bina terminator ke — ek invalid string. Woh single difference (fence vs no fence) hi puri wajah hai ki strlcpy ko "woh strncpy jo hona chahiye tha" kaha jaata hai.
Exercise L3.2 (exact-fit boundary)
char buf[6];
int r = snprintf(buf, sizeof(buf), "%s", "hello");"hello" exactly 5 chars hai. Kya yeh fit hota hai? buf, r, aur truncation check fires ya nahi, do.
Recall Solution
5 content chars + 1 terminator = 6 bytes, jo exactly sizeof(buf) = 6 hai. Perfect fit:
buf = "hello". Return r = 5.
Truncation check: → false. Koi truncation nahi — sahi, kyunki sab kuch (fence samajhkar) fit hua. Yeh important boundary hai: r == size - 1 sabse bada value hai jiska matlab "sab kuch fit hua."
Exercise L3.3 (degenerate: size 0)
char buf[8];
buf[0] = 'X';
int r = snprintf(buf, 0, "hi");buf[0] ka kya hota hai? r kya hai?
Recall Solution
Jab size == 0 ho, snprintf ko koi bhi byte likhna forbidden hai — ek '\0' bhi nahi. Isliye buf[0] 'X' rehta hai; buffer untouched hai.
Lekin yeh phir bhi compute karta hai ki yeh kya likhta aur woh return karta hai: strlen("hi") = 2.
Yeh ek common idiom hai — pehle snprintf(NULL, 0, fmt, ...) call karo needed length measure karne ke liye, phir exactly r + 1 bytes allocate karo aur dobara call karo. Measure-then-write pattern is rule par rely karta hai.
Level 4 — Synthesis
(Scratch se sahi code likhna.)
Exercise L4.1
Ek function copy_safe(char *dst, size_t dstsize, const char *src) likhna sirf strncpy use karke jo strlcpy ki tarah behave kare: kabhi overflow nahi karta, hamesha terminate karta hai. (Return value required nahi.)
Recall Solution
void copy_safe(char *dst, size_t dstsize, const char *src) {
if (dstsize == 0) return; // fence ke liye bhi jagah nahi
strncpy(dst, src, dstsize - 1); // content ko C-1 par cap karo
dst[dstsize - 1] = '\0'; // fence ko last box mein force karo
}Har line kyun hai:
dstsize == 0guard: zero boxes ke saath hum ek terminator bhi nahi likh sakte;dst[-1]likhna ek out-of-bounds write hoga (Buffer overflow and stack smashing).strncpy(..., dstsize - 1): last box reserve karta hai, isliyestrncpykabhi boxdstsize - 1touch nahi kar sakta.dst[dstsize - 1] = '\0': unconditionally fence place karta hai. Agar source lambi thi, toh yeh truncate karta hai; agar choti thi, toh yeh box already padding se'\0'tha — dono cases mein sahi hai.
Exercise L4.2
String "user=<name>" ko char out[16] mein build karo, aur ek flag truncated set karo agar name fit nahi hua. snprintf use karo.
Recall Solution
char out[16];
const char *name = "alexandra"; // 9 chars
int r = snprintf(out, sizeof(out), "user=%s", name);
int truncated = (r >= (int)sizeof(out));"user=alexandra" 5 + 9 = 14 chars hai, jise 15 bytes chahiye. sizeof(out) = 16, isliye spare room ke saath fit hota hai:
truncated = (14 >= 16) = false (0). Sahi — koi data nahi gaya.
Note karo (int) cast: sizeof ek unsigned size_t yield karta hai; unsigned r ke against signed comparison ke bina cast ke misbehave kar sakta hai agar r kabhi negative ho (encoding error). Cast comparison ko honest banata hai.
Level 5 — Mastery
(Sab kuch combine karo, portability aur measurement idioms samajhkar.)
Exercise L5.1
Tumhe do strings a = "hello" aur b = "world" ko char out[9] mein "hello-world" (11 chars) ki tarah join karna hai. snprintf measure-then-detect idiom use karo. r kya hai, out mein kya hai, aur ek sahi buffer ko kitne bytes chahiye?
Recall Solution
char out[9];
int r = snprintf(out, sizeof(out), "%s-%s", "hello", "world");Full result "hello-world" 5 + 1 + 5 = 11 chars hai, jise 12 bytes chahiye. Sirf 9 boxes hain, aur snprintf last ek '\0' ke liye reserve karta hai, isliye yeh 8 content chars + fence likhta hai:
out = "hello-wo". Return r = 11 (woh wanted length). Truncation: → true.
Ek sahi buffer ko r + 1 = 12 bytes chahiye. Yahi measure trick hai: r tumhe exactly batata hai agali baar kitna bada banana hai.
Exercise L5.2 (portability + full pipeline)
Portable code likhna jo src ko heap buffer mein copy kare, exactly sahi size ka, terminated, strlcpy par kabhi rely kiye bina (jo missing ho sakti hai — glibc ne ise sirf 2.38 mein ship kiya). Maano src aur malloc succeed karte hain.
Recall Solution
size_t need = strlen(src) + 1; // +1 '\0' fence ke liye
char *dst = malloc(need);
memcpy(dst, src, need); // content AUR terminator copy karoYeh bulletproof kyun hai:
strlen(src)visible chars count karta hai (srcke apne'\0'par rukta hai), isliyeneedexactly content + fence hai.malloc(need)precisely utne hi boxes allocate karta hai — koi overflow possible nahi kyunki buffer data se size kiya gaya tha.memcpy(dst, src, need)needbytes copy karta hai, aur kyunkisrcka boxneed - 1uska'\0'hai, fence bhi copy ho jaata hai. Koi manual termination needed nahi.- Sirf standard functions use karta hai → har jagah portable, koi
strlcpydependency nahi. Yeh "cup ko paani ke hisaab se size karo" strategy hai — "fixed cup mein daalo" ka inverse, aur yeh kabhi truncate nahi karta.
Exercise L5.3 (interaction quiz)
char b[8] aur source "1234567" (7 chars) ke liye, yeh table fill karo — exact b contents aur har function ke liye return/validity.
| Call | b bytes |
Valid string? | Return |
|---|---|---|---|
strncpy(b, "1234567", 8) |
? | ? | — |
snprintf(b, 8, "%s", "1234567") |
? | ? | ? |
strlcpy(b, "1234567", 8) |
? | ? | ? |
Recall Solution
Source "1234567" 7 content chars hai, jise total 8 bytes chahiye (7 + fence). b mein exactly 8 boxes hain — ek exact fit.
| Call | b bytes |
Valid? | Return |
|---|---|---|---|
strncpy(b, "1234567", 8) |
1 2 3 4 5 6 7 \0 |
Haan | b (ptr) |
snprintf(b, 8, "%s", "1234567") |
1 2 3 4 5 6 7 \0 |
Haan | 7 |
strlcpy(b, "1234567", 8) |
1 2 3 4 5 6 7 \0 |
Haan | 7 |
Subtle point: yahan even strncpy ek valid string produce karta hai! Source "1234567" 7 chars hai; strncpy 7 content bytes copy karta hai aur uske paas 1 byte bachi hai, jise woh source ke apne '\0' se fill karta hai, phir pad karta hai (pad karne ke liye kuch nahi baca). Yeh sirf isliye succeed karta hai kyunki content n - 1 bytes thi, n nahi. Source ko 8 chars tak push karo aur strncpy break kar jaata hai jabki dono aur safe rehte hain. snprintf/strlcpy 7 return karte hain; kyunki , koi truncation flag nahi hua — sahi, sab kuch fit hua.
Recall Master mnemonic recap
"n fence bhool jaata hai; printf aur l hamesha baandhte hain." Ek extra argument — destination size — poori safety ki kahaani hai. Size jawaab deta hai "cup kitna bada hai?" Ise kabhi skip mat karo. Aur fence rule: content ≤ capacity − 1, hamesha.
Connections
- Parent: Safe alternatives overview
- 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