gpt4 book ai didi

c - 使用 "fgets"读取文件名并检查字符串名称是否长于 20 个字符,使用户重新输入

转载 作者:行者123 更新时间:2023-11-30 14:37:53 28 4
gpt4 key购买 nike

我正在尝试使用 fgets()stdin 上获取用户的输入。如果用户输入超过 20 个字符,我会使用 fgets() 再次读取它。但第二次它只是不读入,而是重复 fgets 之前的 print 语句,然后继续执行下面的代码。我尝试过刷新缓冲区,但不起作用。

整个程序在检查后从文件中读取,然后翻转这些位并将其写入另一个文件中。那部分工作正常。我有一个 while 循环检查文件是否不存在,并要求用户使用 fgets 再次输入,效果也很好。

FILE *fp,*fp1;
char name[20];

printf("File name please\n");
fgets(name,200,stdin);
while (strlen(name) > 19) {
name[0] = '\0';
printf ("Too long please change\n");
fgets(name,200,stdin);
}

// posting the other check statement that works fine
while (fp == NULL){
printf("Re-enter the file name\n");
fgets(name,2000,stdin);
for (i = 0;i < 200; i++){
if (name[i] == '\n'){
name[i] = '\0';
break;
}
}

我期望第一个 while 循环检查字符串的长度是否超过 19 并再次获取用户的输入,但它在第二个循环之前打印 printf 语句,然后继续。

最佳答案

如果用户输入超过 18 个字符并按 Enter,您的代码将调用未定义行为。为什么?您声明char name[20];意味着总共只能存储20个字符(包括nul终止字符)。但是,您随后可以使用 fgets(name,200,stdin); 告诉 fgets 读取最多 200 个字符。

fgets 将按照您的指示执行操作。如果您的用户输入 19 个字符fgets 将尝试将 21 个字符 写入 name,写入超出name 的边界并调用未定义的行为

如果用户只输入 19 个字符,为什么要使用 21 个字符

回想一下当用户按 Enter 表示输入结束时会发生什么。 fgets(事实上,所有面向行的输入函数,包括 POSIX getline)都将包含 '\n'缓冲区已满(前提是有足够的空间)——并且您已告诉 fgets200 个字符 可用。但是,name总共只有20,例如

        20 characters total

first +---+---+---+---+---+
15 ... | . | . | x | \n| \0|
characters +---+---+---+---+---+

要解决您的问题,您必须始终确保您的存储空间等于或超过您告诉fgets 读取的字符数。根据经验,不要吝惜缓冲区大小。如果您计划将 20 个字符 读取为名称,则提供的缓冲区至少是您能找到的最长名称长度的两倍。我宁愿 10,000 字节太长,1 字节太短......

要获取输入,您可以通过输入函数的返回来控制输入循环(无论是在循环条件中,还是作为循环内的条件),该函数将处理 EOF、空输入、以及长度太长。

当您希望用户输入满足某些条件时,不断循环直到用户输入适当的输入(或使用 EOF 取消)通常是一个好方法,例如

#define MAXC 256    /* if you need a constant, #define one (or more) */
...
for (;;) { /* loop continually until good input or user cancels */
fputs ("enter name: ", stdout); /* prompt */
if (!fgets (name, MAXC, stdin)) { /* handle manual EOF */
fputs ("(user canceled)\n", stdout);
return 1;
}
...
}

在循环中,您只需使用 strlen 检查 name 的长度,并从缓冲区末尾修剪 '\n' 。如果长度超过19个字符,只需处理错误并继续提示输入另一个条目。

总而言之,你可以做类似的事情:

#include <stdio.h>
#include <string.h>

#define MAXC 256 /* if you need a constant, #define one (or more) */
#define MAXN 20

int main (void) {

char name[MAXC] = {0};
size_t len = 0;

for (;;) { /* loop continually until good input or user cancels */
fputs ("enter name: ", stdout); /* prompt */
if (!fgets (name, MAXC, stdin)) { /* handle manual EOF */
fputs ("(user canceled)\n", stdout);
return 1;
}
len = strlen (name); /* get length of name */
if (len > MAXN || *name == '\n') { /* exceeds length or empty */
fputs (" error: name exceeds 20 char or empty\n", stderr);
continue;
}
else { /* good name, trim \n, break loop */
if (len && name[len - 1] == '\n') /* check last char '\n' */
name[--len] = 0; /* overwrite '\n' with \0 */
break;
}
}

printf ("\nname: %s (%zu chars)\n", name, len);

return 0;
}

(注意:如果用户使用 Ctrl+dCtrl+z 生成手动 EOF在 Windows 上,读取停止并退出程序。如果长度超过所需长度,或者用户只是按 Enter 导致缓冲区仅包含 '\n' [下面的空字符串],会生成错误并要求用户重新输入名称。)

示例使用/输出

练习输入例程,输入 20 个字符,然后单独输入 Enter,最后输入有效的 19 个字符的字符串。

$ ./bin/namelen
enter name: 12345678901234567890
error: name exceeds 20 char or empty
enter name:
error: name exceeds 20 char or empty
enter name: 1234567890123456789

name: 1234567890123456789 (19 chars)

您可以根据需要调整长度。

如果用户在任何时候取消,退出前会显示以下内容:

$ ./bin/namelen
enter name: (user canceled)

作为调用 strlen 然后手动检查 '\n' 是否包含在缓冲区中的替代方法,您可以使用 strcspn 获取长度并修剪尾部 '\n',例如:

    for (;;) {  /* loop continually until good input or user cancels */
fputs ("enter name: ", stdout); /* prompt */
if (!fgets (name, MAXC, stdin)) { /* handle manual EOF */
fputs ("(user canceled)\n", stdout);
return 1;
}
name[(len = strcspn (name, "\n"))] = 0; /* save len, trim '\n' */
if (len > MAXN - 1 || !*name) { /* exceeds length/empty */
fputs (" error: name exceeds 20 char or empty\n", stderr);
continue;
}
else /* good name, break loop */
break;
}

如果您有疑问,请告诉我。经验法则 - 不要吝惜缓冲区大小!

关于c - 使用 "fgets"读取文件名并检查字符串名称是否长于 20 个字符,使用户重新输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56962081/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com