使用fgets在C中阅读字符串

gopyfrb3  于 2022-12-03  发布在  其他
关注(0)|答案(2)|浏览(123)

我尝试使用以下代码从用户读取字符串

char array[4];
fgets(array , 5, stdin);

我之所以使用fgets命令,是因为scanf会读取整个字符串,而不管数组的大小,如果它不适合数组,它会自动更改数组的大小,以使字符串适合数组。我希望总是读取最大长度为4的字符串,这就是我使用fgets的原因。因为fgets将始终获取您要求它获取的字符,而不管来自用户的字符串有多长。
我的问题是,正如你所看到的,我声明了大小为4的数组,但是在fgets里面我必须写5,因为它比数字少读一个字符。为什么它会这样做?为什么它比数字少读一个字符?我做错了什么吗?

6mzjoqzu

6mzjoqzu1#

C语言中的字符串是包括终止零字符'\0'的字符序列。
所以这个数组

char array[4];

可以包含一个字符串,除了终止零字符'\0'之外,最多还有三个字符。
如果要输入三个以上的字符,则至少需要声明如下数组:

char array[5];

然后你就可以写

fgets(array , sizeof( array ), stdin);

在这种情况下,与按下的Enter键相对应的新行字符'\n'将不会存储在数组中,而将留在输入缓冲区中。
因此,如果您在此之后再调用一个fgets,则将读取仅包含新行字符'\n'(如果不计算终止零字符'\0')的字符串。
因此,最好像下面这样声明数组

char array[6];

若要从数组中移除换行字符,您可以写入

array[ strcspn( array, "\n" ) ] = '\0';

至于这通电话

fgets(array , 5, stdin);

则如果您尝试输入四个字符,它将调用未定义的行为,因为终止零字符'\0'将由该函数写入数组外部的内存中。
至于函数scanf,则可以按以下方式使用它

char array[5];
scanf( "%4s", array );

char array[5];
scanf( " %4[^\n]", array );

注意格式字符串中的前导空格。它允许跳过白色字符,例如新的行字符'\n',它可以在前面调用scanf后存储在缓冲区中。

lf5gs5x2

lf5gs5x22#

编写防呆的输入例程是 * 困难的。* 许多传统的 *nix程序在遇到不寻常或极端的输入(例如,非常长的行)时都会失败。
不幸的是,初学者的问题经常处理手动输入。我看到以下策略,取决于用例(eidogg.,确切的赋值)。
1.忽略所有的输入问题,不要处理任何错误。假设没有一个单词超过x字节,没有一行超过y字节,没有一个文件超过z字节。即使你相当确定你的手动输入不会违反你的任意假设,这也是不推荐的:约束被遗忘,例程被重新使用,不可避免地,你会有一个程序以这样或那样的方式出现故障。
1.做一些明智的错误检查。这是传统的 nix程序在黑客攻击成为问题之前所做的。处理最常见的错误(找不到文件)和最有可能导致问题的约束(行长度),并在超过这些时失败。你的程序在某些情况下仍然可能失败,而且它很容易受到攻击。
1.让你的程序防呆。这是相对困难的,即使是对于简单的程序,并且倾向于通过错误检查和处理来模糊实际的控制流和目的。另一方面,你可以确信当你的例程是plugged into the software for the next bigger rocket时,它会触发一个Assert,否则会优雅地失败。
在您的情况下,您必须:
1.确保例程读取的字符数不超过缓冲区中的可用空间,Vlad已经为您提供了相关信息。
1.想想你是如何发现过长的单词或行的。
1.
妥善处理 * 检测到的情况。
顺便说一句,scanf("%5s", buf)也将读取最多5个字符,并且在这些字符之后存储一个空字符,因此缓冲区数组必须是6个字符大。

相关问题