arrays - ANSI C:你如何从用户那里获取输入然后反向打印?
问题描述
我正在尝试编写一个程序(用于类),该程序允许用户输入一个字符串,然后反向输出该字符串,直到用户输入“完成”、“完成”或“d”。
这是我当前的代码:
#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 50
int main(void) {
char userText[BUFFER_SIZE];
int i;
int len;
do
{
fgets(userText, BUFFER_SIZE, stdin);
userText[(len = strcspn (userText, "\n"))] = 0;
for ( i = len - 1; i >= 0; i-- )
{
printf("%c", userText[i]);
}
printf("\n");
} while ( ( strcmp(userText, "Done") != 0 ) && ( strcmp(userText, "done") != 0 ) && ( strcmp(userText, "d") != 0 ) );
return 0;
}
如您所见,我使用 fgets 是因为我必须允许用户输入一个包含空格的字符串,然后我还清除了缓冲区以避免换行。这是我必须回答的问题:
解决方案
你让自己的事情变得有点困难。一旦你有了长度,你可以简单地循环多次,从结尾输出字符到开头,然后输出换行符。只需将所有内容都包含在一个循环中,以不断获取输入并检查您的'd'
,"Done"
或"done"
中断循环。
(注意:,您可以简单地测试len == 1 & *userText == 'd'
以处理'd'
案例退出,而无需调用strcmp()
- 由您决定)
在查看解决方案之前,您应该避免在代码中使用幻数(例如50
)。反而:
...
#define MAXC 50 /* if you need a constant, #define one (or more) */
int main(void) {
char userText[MAXC];
...
if (!fgets (userText, MAXC, stdin)) /* validate EVERY user-input */
return 1;
这样,如果您需要更改字符串的长度,您就有一个方便的位置来调整长度,而无需选择所有函数调用或循环限制来进行更改。
验证每个输入
无论您使用什么输入功能,除非您检查返回以确定输入是成功还是失败,否则您无法正确使用它。您在fgets()
这里使用(对您有好处!),但您仍然需要检查退货。将在成功或流错误fgets()
时返回指向已填充缓冲区的指针。因此,您只需要确保返回不是验证字符是否保存在 中,例如NULL
EOF
NULL
userText
if (!fgets (userText, MAXC, stdin)) /* validate EVERY user-input */
return 1;
您在第一次迭代中调用未定义的行为len-1
:
int len;
...
userText[len-1] = '\0';
在第一次迭代中,len
未初始化,并且任何尝试使用具有自动存储持续时间的变量的值而其值不确定会导致未定义的行为。具体来说:
C11 标准 - 6.7.9 初始化(p10) “如果具有自动存储持续时间的对象未显式初始化,则其值是不确定的。” 和C11 标准 - J.2 未定义行为 “具有自动存储持续时间的对象的值在不确定时使用(6.2.4、6.7.9、6.8)。”
fgets() 包括'\n'
在缓冲区中填充
当您尝试strcmp()
使用"d"
,"Done"
和"done"
时,您将永远无法匹配"d"
,"Done"
和"done"
因为缓冲区中实际包含的是"d\n"
,"Done\n"
和"done\n"
。删除 的一种简单而可靠的方法'\n'
是使用strcspn()
,例如
userText[strcspn (userText, "\n")] = 0; /* trim \n */
'\n'
您可以通过简单地保存返回来获得不带 的行的长度strcspn()
,例如
size_t len = 0;
...
userText[(len = strcspn (userText, "\n"))] = 0; /* trim \n, save len */
现在您的strcmp()
支票将匹配。
要反向输出用户输入,只需循环len
输出从最后一个字符开始到第一个字符的时间。while 循环提供了一种简单的迭代方式,例如
while (len--) /* loop len times */
putchar (userText[len]); /* output char (end-to-start) */
putchar ('\n'); /* tidy up with newline */
(注意:不需要printf ("%c", ...
单个字符,即 what putchar()
or fputc()
is for。一个好的编译器通常会为您进行优化,但最好展示对输出如何发生的理解)
把它放在一起并"user str: "
为用户输入提供可选提示,以及"reversed: "
为输出提供可选前缀(比让用户看着闪烁的光标想知道你的程序是否挂起更好),你可以这样做:
#include <stdio.h>
#include <string.h>
#define MAXC 50 /* if you need a constant, #define one (or more) */
int main(void) {
char userText[MAXC];
size_t len = 0;
for (;;) { /* loop continually */
fputs ("\nuser str: ", stdout); /* prompt for input (optional) */
if (!fgets (userText, MAXC, stdin)) /* validate EVERY user-input */
return 1;
userText[(len = strcspn (userText, "\n"))] = 0; /* trim \n, save len */
if ((len == 1 && *userText == 'd') || /* check for 'd' alone */
strcmp(userText, "Done") == 0 || /* check for "Done" */
strcmp(userText, "done") == 0) { /* check for "done" */
return 0;
}
fputs ("reversed: ", stdout); /* prefix for output (optional) */
while (len--) /* loop len times */
putchar (userText[len]); /* output char (end-to-start) */
putchar ('\n'); /* tidy up with newline */
}
return 0;
}
(注意: return 0;
是 C99 转发的默认设置,但由于您指定 C89,因此它是必需的)
示例使用/输出
$ ./bin/outputrev
user str: Hello there
reversed: ereht olleH
user str: Hey
reversed: yeH
user str: done
或者:
$ ./bin/outputrev
user str: My
reversed: yM
user str: dog
reversed: god
user str: has
reversed: sah
user str: fleas
reversed: saelf
user str: d
如果您有任何其他问题,请仔细查看并告诉我。
推荐阅读
- python - Python Selenium - 如何动态单击“加载更多”直到它消失?
- ios - 自 2020 年 4 月 30 日起,Apple 将不再接受使用 UIWebView 的新应用提交
- c++ - 坚持使用 C++ 元编程
- c++ - 如何在 C++ 或 C 中创建和编写索引 png 图像
- elasticsearch - 从 Kibana elasticsearch 嵌入地图
- sql - 查找总和的最大值的子查询
- ios - 从表格视图中的另一个视图控制器播放某些歌曲时遇到问题
- javascript - 使用 VueJS Devtools Chrome Extension 调试另一个 Chrome 扩展
- javascript - 如何使用 var 作为键名从 Json String Node JS 中检索键?
- azure - 返回 Blob 文件 URI 的 Python 脚本