提问人:mortenlund 提问时间:11/7/2023 最后编辑:Andrew Henlemortenlund 更新时间:11/8/2023 访问量:1133
调用 fgets() 两次
Calling fgets() twice
问:
我是初学者。两次使用该函数时,我真的很难使用 fgets()。我在带有 VS Code 和 C++ 扩展的 Windows 上。我的测试程序正在工作,但恕我直言,对于如此简单的任务来说,它冗长而复杂。此外,我读过,使用 goto 是一种不好的做法。有没有更简单的解决方案?
#include <iostream>
#include <string.h>
using namespace std;
#define max 5
void killNL(char *str) {
int i = 0;
while (*(str+i) != EOF){
if (*(str+i) == '\n'){
*(str+i) = '\0';
*(str+i+1) = EOF;
}
i++;
}
}
int main()
{
size_t len = 0;
char string[5] = {0};
int c = 0;
begin:
printf("Enter string: ");
fgets(string, max, stdin);
killNL(string); //Is used only for the len count when length is 1 less
//than max. It depends on the space that is left for
//'\n' AND '\0' which raises the count to when the
//(getchar()) != gets activated. Which needs a leftover
//'\n' in the buffer to not go into endless loop.
len = strlen(string);
for (int i = 0 ; i <= len ; i++) {
if (string[i] == '\n'){ printf("\\n \n");}
else if (string[i] == '\0'){ printf("\\0 \n");}
else { printf("%c \n", string[i]);}
}
askAgain:
if (len >= max - 1) {
while (c = (getchar()) != '\n' && c != EOF) {}
}
printf("Continue? 'y'/'n' :");
fgets(string , 3, stdin);
if (*(string) == 'y'){
goto begin;
} else if (*(string) == 'n') {
goto end;
} else {
printf("\nWrong answer!\n");
goto askAgain;
}
end:
printf("END!\n");
return 0;
}
我一直在这里搜索,在 Youtube 上,然后在一本书中我找到了 killNL 函数,它最终确实使它起作用了。 这个问题在 Stack Overflow 上有很多变体,与 sscanf 结合使用,与读取文件等结合使用。但不是这个变体,这就是为什么我发布它的原因,尽管它是一个旧主题。
答:
好吧,对于初学者来说,你真的想决定你是用 C 还是 C++ 编码。你,但没有使用任何 iostream 函数(大概你考虑过使用或类似的东西)。您还可以指定 ,但这在 C 中无效。 规则:仅包含代码中使用的函数的必要标头。#include <iostream>
std::cout
using namespace std;
我们假设你想用 C 语言编写代码,给定你选择的输入和输出函数。如果没有,请发表评论,我也很乐意帮助C++。通过代码工作:
max 5
-- 不要在缓冲区大小上吝啬。虽然你会使用 if 用 C++ 编写,但在声明数组以保存 C 中的输入时,不要吝啬。虽然只会尝试写入字符数(减去为 nul 终止字符提供空间),但除其他外,您使用的目的是一次读取一整行输入,而不会在输入流中留下无关的字符。您可以通过提供足够大小的缓冲区来实现此目的。std::string
fgets()
size
1
fgets()
- 在接受输入时,如果输入失败流错误或手动(由用户按下(或在 Windows 上)生成),或者收到成功的输入,或者满足您的退出条件之一(例如,用户单独按下字符串表示他们已经完成了输入),您通常会连续循环,然后中断读取循环
EOF
Ctrl + dCtrl + zEnter - 在 C 语言中,要从字符串末尾开始修剪 (例如 ),然后您只需调用有效地覆盖 用 nul 终止字符(这只是 ASCII
'\n'
fgets()
fgets (string, MAXC, stdin)
string[strcspn (string, "\n")] = 0;
'\n'
'\0'
0
) - 在需要变量的范围内声明变量,以及
- 使用得当绝对没有错。这是在单个表达式中打破嵌套循环的唯一方法,等等。
goto
以此为背景,您可以简化和清理代码,如下所示。许多选择都取决于您,但这是一种通用的方法
- 读取输入,
- 检查输入是否有效,
- 检查用户是否生成了 ,
EOF
- 检查用户是否完成了输入,
- 检查输入是否与所需的字符串匹配,最后
- 如果输入不是需要的,则再次循环。
(粗略解释一下你想做什么)
代码(带有附加注释)可以是:
// #include <iostream> /* only include needed headers for functions used */
#include <stdio.h> /* or <cstdio> for modern C++ */
#include <string.h> /* or <cstring> for modern C++ */
// using namespace std; /* using nothing from std:: namespace */
#define MAXC 1024 /* don't SKIMP on buffer size, UPPERCASE defines */
#define ANS "guess"
int main()
{
char string[MAXC] = {0}; /* declare string */
/* read-loop continually, break on condition of your choice */
while (1) {
fputs ("\nEnter string: ", stdout); /* no conversion, fputs is fine */
/* validate EVERY input based on return of read function */
if (!fgets (string, MAXC, stdin)) {
puts ("(user generated manual EOF)");
return 0;
}
/* trim '\n' from string */
string[strcspn (string, "\n")] = 0;
/* exit if empty-string (user just pressed [Enter], or any condition) */
if (*string == '\0') {
puts ("(all done)");
break;
}
/* check if correct answer ANS given */
if (strcmp (string, ANS) == 0) {
puts ("(correct!)");
break;
}
puts ("(answer didn't match)"); /* otherwise, loop again */
}
puts ("(That's All Folks!)");
}
示例使用/输出
$ ./bin/read-loop
Enter string: my dog has fleas
(answer didn't match)
Enter string: why?
(answer didn't match)
Enter string: what if I guess?
(answer didn't match)
Enter string: guess
(correct!)
(That's All Folks!)
或使用以下命令取消:Ctrl + d
$ ./bin/read-loop
Enter string: (user generated manual EOF)
或者使用用户的退出条件,只需在提示符下单独按下,表明他们已经完成了猜测:Enter
$ ./bin/read-loop
Enter string: next we will just press Enter when prompted, to quit input
(answer didn't match)
Enter string:
(all done)
(That's All Folks!)
您可以根据需要添加(或删除)任意数量的读取循环退出条件。关键要点是:
- 持续循环,直到用户提供所需的输入,
- 总是在返回读取函数时退出读取循环,
- 验证每个用户输入,
- 提供所需的退出条件来控制读取循环的退出,以及
- 根据需要处理发生的任何错误。
如果这是您需要的,请告诉我。如果没有,我很乐意为您提供进一步的帮助。
评论
char string[MAXC] = {0};
*string
getchar()
'\n'
'\0'
0
这是 DavidC.Rankin 的代码,对溢出进行了修改。
#include <stdio.h>
#include <string.h>
#define MAXC 6 //test with minimum storage
#define ANS "guess"
int c = 8;
int d = 9;
int e = 0;
int len = 0;
int main()
{
char string[MAXC] = {0};
/* read-loop continually, break on condition of your choice */
while (1) {
fputs ("\nEnter string: ", stdout);
/* validate EVERY input based on return of read function */
if (c = !fgets (string, MAXC, stdin)) { //c = 1 when EOF is entered, else 0.
puts ("(user generated manual EOF)"); //ctrl + 'z' (manual EOF)
return 0;
}
/* trim '\n' from string */
string[strcspn (string, "\n")] = 0; //compares string with \n and counts position.
len = strlen(string); //needed when input is overflowing
if (len >= (MAXC - 1)) { //ditto
while ((d = getchar()) != '\n' && d != '\0') {}
}
/* exit if empty-string (user just pressed [Enter], or any condition) */
if (*string == '\0') {
puts ("(all done)");
break;
}
/* check if correct answer ANS given */
if (d = strcmp (string, ANS) == 0) {
puts ("(correct!)");
break;
}
puts ("(answer didn't match)"); /* otherwise, loop again */
}
puts ("(That's All Folks!)");
return 0;
}
评论
\n
strcspn()
string[(len = strcspn (string, "\n"))] = 0;
len
string
'\n'
:)
(...)
string[(...)]...
len
上一个:清除 fgets 缓冲区
下一个:Fread 功能是否阻塞?
评论
killNL()
EOF
killNL()
fgets()
while (*(str+i) != EOF){
str[i]
*(str+i)
'\0'
-1
char
char
while (c = (getchar()) != '\n' && c != EOF)
肯定是错的。第二个是放错地方的。应该是(你看到区别了吗?(
while ((c = getchar()) != '\n' && c != EOF)
killNL()
char
EOF
int
[]