代码 1:strncpy(arr, "0123456789", sizeof(arr));
int main(int argc, char *argv[])
{
char arr[10];
strncpy(arr, "0123456789", sizeof(arr));
printf("%s\n", arr);
}
问题是什么?What’s wrong?
EN:
arr has size 10. strncpy copies 10 bytes from "0123456789".
But C strings need one extra byte for '\0'. No null terminator is added.
printf("%s", arr) keeps reading memory past arr until it randomly finds a '\0'.
CN:
arr 长度是 10,而 "0123456789" 正好 10 个字符。strncpy 会复制满 10 个字节,没地方放 '\0'。
printf("%s", arr) 就会从 arr 开始一直往后读内存,直到碰到某个巧合出现的 0 为止,可能打印垃圾。
比喻:
你有 10 个格子的名字表,全写满了,但忘了画“结束线”;阅读的人会继续往后把别的内容也当名字读出来。
代码 2:引入第二个数组,演示串联输出
int main(int argc, char *argv[])
{
char arr[10];
char arr2[10];
strncpy(arr, "0123456789", sizeof(arr));
strncpy(arr2, "987654321\0", sizeof(arr2));
printf("%s\n", arr);
}
为什么会输出 0123456789987654321?
EN:
arris not null-terminated (same bug as before).arr2is null-terminated.- When printing
arr,printfstarts atarr, prints0123456789,
then keeps reading into the memory wherearr2lives, prints987654321,
finally stops atarr2’s'\0'.
CN:
arr依然没有'\0'。arr2有'\0'。printf("%s", arr)从arr开始打印0123456789,停不下来,就继续读到紧挨着的arr2,把987654321也当成arr的一部分输出,直到遇到arr2的'\0'才停。
比喻:
名单 A 没有写“结束线”,后面紧接名单 B,于是阅读时把两份名单拼成了一份。
这是典型 Null-Termination 错误 + 邻接栈变量被意外曝光。
代码 3:理论总结:当源长度 ≥ 目标长度
“Where the length of source string is the same or greater than target string:
- source gets truncated
- target may not be properly null-terminated”
EN:
If source length ≥ destination capacity, using strncpy(dest, src, sizeof(dest)) is dangerous:
- The copied content fills the buffer.
- No
'\0'is guaranteed. - Printing / using as C-string is unsafe.
CN:
当源串长度和目标数组一样甚至更长时,如果直接 strncpy(dest, src, sizeof(dest)):
- 内容会被截断;
- 可能没有
'\0'; - 后续当作字符串使用非常危险。
核心点:一定要给 '\0' 预留一个位置。
代码 4:修复版本:手动添加 '\0'
int main(int argc, char *argv[])
{
char arr[10];
strncpy(arr, "0123456789", sizeof(arr) - 1);
arr[sizeof(arr) - 1] = '\0';
printf("%s\n", arr);
}
为什么这个是安全的?
EN:
- Only 9 characters are copied.
- The last byte
arr[9]is set to'\0'. printfstops correctly at the terminator.
CN:
- 只复制 9 个字符,留出最后一格;
- 手动把
arr[9]设成'\0'; printf知道在哪停,不会串出边界。
比喻:
名单最后画了“结束线”,后面再有别的内容也不会被误读。
代码 5:fgets 示例一(有坑版本)
void main()
{
char username[8];
puts("Please enter your username:");
fgets(username, 8, stdin);
printf("Your username is %s\n", username);
}
这里要注意什么?
EN (based on slides idea):
fgets(buf, n, ...)reads at mostn-1chars, then adds'\0'.- Here
usernamehas size 8,n = 8→ OK if你真的分配了8个字节。 - 真正的坑往往是:写错参数(比如 n 大于数组大小,或数组太小,逻辑搞混),就会导致潜在问题。
CN:
一般安全,只要:
- 第二个参数 ≤ 数组长度;
- 理解
fgets会保留\n(有时要自己去掉)。
有些材料会故意问 “Is this code ok?” 用来提醒你:要保证“数组长度、第二个参数、终止符空间”三者对应正确。
代码 6:fgets 改进版(更明确)
void main()
{
char username[9];
puts("Please enter your username:");
fgets(username, 9, stdin);
printf("Your username is %s\n", username);
}
EN:
Now:
- Buffer size = 9
fgetsreads up to 8 characters + 1 for'\0'
Safer and clearly leaves room.
CN:
缓冲区 9 字节:8 个可见字符 + 1 个 '\0',语义清晰,风险更低。
比喻:
杯子容量和刻度统一写清楚,不会搞混。
🧩 统一例题(基于上述代码 & 概念)
下面这 10 题是围绕 null-termination、strncpy、fgets 安全用法,每题都有中英文解释,可直接当题库用。
选择题(5 道)
Q1
char buf[10];
strncpy(buf, "0123456789", sizeof(buf));
printf("%s\n", buf);
What is the main problem?
A. sizeof(buf) is wrong
B. strncpy cannot copy numbers
C. buf may not be null-terminated ✅
D. printf cannot print digits
答案解释:
- EN:
strncpycopies 10 chars, no space for'\0'. - CN: 填满数组,没有终止符,
printf会读穿。 - A/B/D 都与真实错误无关。
Q2
char a[5];
strncpy(a, "hello", sizeof(a)-1);
a[4] = '\0';
Is this safe as a C string?
A. Yes ✅
B. No
解释:
只复制4个字符 hell,再手动加 '\0',长度合法安全。
Q3
Which is the best way to safely copy into char dest[20];?
A. strcpy(dest, src);
B. strncpy(dest, src, sizeof(dest) - 1); dest[19] = '\0'; ✅
C. gets(dest);
D. scanf("%s", dest);
解释:
- B 同时限制长度 + 手动补
'\0'。 - A/C/D 都可能溢出。
Q4
About fgets(buf, n, stdin) which is true?
A. It may write up to n chars plus '\0'
B. It writes at most n-1 chars and then '\0' ✅
C. It never writes '\0'
D. It is identical to gets()
解释:
- 正确行为是
n-1+'\0'。 - C/D 完全错误。
Q5
Why does the program sometimes print 0123456789987654321?
A. printf bug
B. First array not null-terminated, so printf continues into arr2 ✅
C. Compiler optimization
D. Because strncpy reverses strings
解释:
核心是:arr 没有 '\0',打印串连下一个数组。
简答题(5 道)
S1
Q: What is a null-terminated string in C?
A (EN): A sequence of characters ending with '\0'.
A (CN): 以空字符 '\0' 作为结束标记的字符数组。
S2
Q: Why is strncpy(dest, src, sizeof(dest)) dangerous when src is long?
A:
EN: It may fill the entire buffer and not append '\0', so dest is not a valid C string.
CN: 会把数组塞满而不补终止符,后续 printf("%s") 等操作就会读穿。
S3
Q: How to correctly use strncpy with char arr[10];?
A:
strncpy(arr, src, sizeof(arr) - 1);
arr[sizeof(arr) - 1] = '\0';
EN: Reserve last byte for '\0'.
CN: 永远留一格给终止符。
S4
Q: What is one advantage of fgets() over gets()?
A:
EN: fgets() limits the number of characters read and ensures space for '\0'.
CN: fgets() 有长度限制,更不容易溢出。
S5
Q: When you see unexpected extra data printed after a string, what should you suspect?
A:
EN: Missing null terminator or buffer overflow.
CN: 优先怀疑:字符串没 '\0' 或越界写把终止符覆盖了。
&spm=1001.2101.3001.5002&articleId=154527742&d=1&t=3&u=3d043aa29b334591936e9921562c9a1c)
219

被折叠的 条评论
为什么被折叠?



