关于 fgets() 函数字符限制的 C 编程?
C programming on fgets() function characters limitation?
示例代码:
int i;
char word [10][15];
for (i = 0; i < 10; i++){
fgets(word[i], 16, stdin);
}
所以我(最多)接收 10 个字符串用户输入,每个字符串的长度不能超过 15 个字符(因此 16,因为 \n
存储在fgets()
方法,对吧?)。
我的问题是当我想打印出单词数组中的单词时。发生这种情况:
输入:
abcdefghijklmnopqrstuvwxyz
输出:
abcdefghijklmnopqrstuvwxyz
pqrstuvwxyz
我不知道为什么会这样。似乎 fgets()
在输入 15 个字符后不会停止。
编辑:
int j;
for (j = 0; j < 10; j++){
printf("%s", word[j]);
}
请记住,在 C 编程语言中,每个字符串都以尾随 [=13=]
字节结尾。 fgets
函数读取的字符最多比您允许它写入缓冲区的字符少一个,因此它可以用 [=13=]
字节终止缓冲区中的字符串。现在,在您的代码中,您允许 fgets
比 word
中的每个 char[15]
多写入一个字节到 word
。最初,word
数组如下所示:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ...
^ ^ ^
word[0] word[1] word[2]
其中 ?
代表一个未定义的值。在你的代码第一次调用 fgets
之后,words
看起来像这样:
a b c d e f g h i j k l m n o [=11=]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ...
^ ^ ^
word[0] word[1] word[2]
观察到fgets
比words[0]
中的space多写了一个字节,所以写入了属于word[1]
的space。然而,如果你要用 printf
打印出 word[0]
的内容,字符串 abcdefghijklmno
将被打印为 printf
直到遇到 [=13=]
字节.现在看看在第二次调用 fgets
:
之后 word
的样子
a b c d e f g h i j k l m n o p q r s t u v w x y z \n[=12=]? ? ? ? ? ? ...
^ ^ ^
word[0] word[1] word[2]
在此调用中,fgets
不会写入超出 word[1]
的末尾,因为它之前遇到了一个换行符 (\n
) 字节。观察 word[0]
中字符串的尾随 [=13=]
字节已被覆盖,因为该字符串进入了 word[1]
.
占用的内存区域
现在如果你打印会发生什么?第一次调用 printf
从 a
开始打印,直到遇到 [=13=]
字符。这导致字符串 abcdefghijklmnopqrstuvwxyz\n
被打印出来,因为 o
后面没有 [=13=]
字节。 printf
的第二次调用从 word[1]
开始的地方开始,在 p
直到它看到 [=13=]
,导致打印 pqrstuvwxyz\n
。
现在你如何解决这个问题?要么让数组中的每个字符串更长,要么让 fgets
只读取 15
而不是 16
个字符。
示例代码:
int i;
char word [10][15];
for (i = 0; i < 10; i++){
fgets(word[i], 16, stdin);
}
所以我(最多)接收 10 个字符串用户输入,每个字符串的长度不能超过 15 个字符(因此 16,因为 \n
存储在fgets()
方法,对吧?)。
我的问题是当我想打印出单词数组中的单词时。发生这种情况:
输入:
abcdefghijklmnopqrstuvwxyz
输出:
abcdefghijklmnopqrstuvwxyz
pqrstuvwxyz
我不知道为什么会这样。似乎 fgets()
在输入 15 个字符后不会停止。
编辑:
int j;
for (j = 0; j < 10; j++){
printf("%s", word[j]);
}
请记住,在 C 编程语言中,每个字符串都以尾随 [=13=]
字节结尾。 fgets
函数读取的字符最多比您允许它写入缓冲区的字符少一个,因此它可以用 [=13=]
字节终止缓冲区中的字符串。现在,在您的代码中,您允许 fgets
比 word
中的每个 char[15]
多写入一个字节到 word
。最初,word
数组如下所示:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ...
^ ^ ^
word[0] word[1] word[2]
其中 ?
代表一个未定义的值。在你的代码第一次调用 fgets
之后,words
看起来像这样:
a b c d e f g h i j k l m n o [=11=]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ...
^ ^ ^
word[0] word[1] word[2]
观察到fgets
比words[0]
中的space多写了一个字节,所以写入了属于word[1]
的space。然而,如果你要用 printf
打印出 word[0]
的内容,字符串 abcdefghijklmno
将被打印为 printf
直到遇到 [=13=]
字节.现在看看在第二次调用 fgets
:
word
的样子
a b c d e f g h i j k l m n o p q r s t u v w x y z \n[=12=]? ? ? ? ? ? ...
^ ^ ^
word[0] word[1] word[2]
在此调用中,fgets
不会写入超出 word[1]
的末尾,因为它之前遇到了一个换行符 (\n
) 字节。观察 word[0]
中字符串的尾随 [=13=]
字节已被覆盖,因为该字符串进入了 word[1]
.
现在如果你打印会发生什么?第一次调用 printf
从 a
开始打印,直到遇到 [=13=]
字符。这导致字符串 abcdefghijklmnopqrstuvwxyz\n
被打印出来,因为 o
后面没有 [=13=]
字节。 printf
的第二次调用从 word[1]
开始的地方开始,在 p
直到它看到 [=13=]
,导致打印 pqrstuvwxyz\n
。
现在你如何解决这个问题?要么让数组中的每个字符串更长,要么让 fgets
只读取 15
而不是 16
个字符。