所以,我是这个网站的新手,我是编程新手。我在我的第一本书,我的父亲做了一个“功课”,他不知道做这个的代码,但我想做。所以这就是我想做的事情: 我想创建一个像计算器的程序,你输入一个值A和一个值B,然后程序显示A + B的结果。我已经这样做了,问题是如果我输入一个字符,程序会继续读取其他代码。这是我写的,也许你会更好地理解。
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
void main(void)
{
int val_a;
int val_b;
int result;
printf("Write a number A=");
scanf("%d", &val_a);
if(isdigit(val_a))
{
printf("\nWrite a number B=");
scanf("%d", &val_b);
}
else
printf("\nI said number.\n");
result = val_a + val_b;
printf("%d + %d = %d", val_a, val_b, result);
getch();
printf("\033[2J"); \\ to clear the screen
}
所以我想要的是程序将回到我必须输入数字A的地方。 我在google上找到了关于标签的内容,但我什么都不懂:D。也许有人可以发布我想要的例子,以便我可以研究它。
我应该写我的名字吗?也许下次:P
PS:我希望有人会在我写的内容中找到NOOB错误并告诉我。 :祈祷:答案 0 :(得分:2)
#include <stdio.h>
#include <conio.h>
所以你正在使用Windows。
#include <ctype.h>
void main(void)
main()
的返回类型应为int
,即使您发现了许多相反的例子。
{
int val_a;
int val_b;
int result;
printf("Write a number A=");
scanf("%d", &val_a);
您应该测试scanf()
的返回值,看它是否能够读取数字。
if (isdigit(val_a))
此测试&#39;工作&#39;但它会检查输入的数字是否为48..57范围内的值(ASCII,CP1252,Unicode,ISO 8859-1等代码数字'0'
到'9'
)。这可能不是你的想法。
{
printf("\nWrite a number B=");
scanf("%d", &val_b);
用户输入了换行符,因此不需要printf()
格式字符串前面的换行符,尽管它也没有害处。关于检查scanf()
的相同评论也适用于此。
}
else
printf("\nI said number.\n");
做错误检查很好。但是,即使您检测到错误,也会继续向前。你真的需要停下来。
result = val_a + val_b;
printf("%d + %d = %d", val_a, val_b, result);
总的来说,最好用换行符结束行。它将数据刷新到文件或屏幕。
getch();
printf("\033[2J"); \\ to clear the screen
printf()
格式字符串不可移植。鉴于您包含<conio.h>
,您应该使用clrscr()
(可能会将该转义序列或等效项发送到终端)。我不相信有必要在程序结束时清除屏幕,但我主要在Unix系统上工作,而不是在Windows上工作。
}
鉴于MSVC仍然是C89编译器,您应该在程序结束时包含return 0;
以返回成功状态。
添加所有更改后,您最终会:
#include <stdio.h>
#include <conio.h>
int main(void)
{
int val_a;
int val_b;
int result;
printf("Write a number A=");
if (scanf("%d", &val_a) != 1)
{
printf("I said number.\n");
getch();
clrscr();
return(1);
}
printf("\nWrite a number B=");
if (scanf("%d", &val_b) != 1)
{
printf("I said number.\n");
getch();
clrscr();
return(1);
}
result = val_a + val_b;
printf("%d + %d = %d\n", val_a, val_b, result);
getch();
clrscr();
return(0);
}
当您了解编写函数时,可以将其压缩为:
#include <stdio.h>
#include <conio.h>
static int get_a_number(const char *prompt)
{
int value;
printf(prompt);
if (scanf("%d", &value) != 1)
{
printf("I said number.\n");
getch();
clrscr();
exit(1);
}
return value;
}
int main(void)
{
int val_a = get_a_number("Write a number A=");
int val_b = get_a_number("Write a number B=");
int result = val_a + val_b;
printf("%d + %d = %d\n", val_a, val_b, result);
getch();
clrscr();
return(0);
}
get_a_number()
函数不是通用函数,但它在此上下文中很有用,因为它封装了一段共同的代码。
- 子程序调用允许我们总结参数列表中的违规行为。
- 子程序本身总结了代码的规则性。
这是Kernighan&amp; amp; Plauger,&#34;编程风格的元素&#34;。
atexit()
上面的代码已更新为在所有退出路径中包含getch()
和clrscr()
(并删除#include <ctype.h>
,因为其中的所有功能都不再使用)。重复写出两个函数调用是一件麻烦事。避免该问题的另一种方法是编写一个在程序退出时调用的函数;您使用atexit()
函数注册它,该函数在<stdlib.h>
:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
static void wait_at_exit(void)
{
getch();
clrscr();
}
static int get_a_number(const char *prompt)
{
int value;
printf(prompt);
if (scanf("%d", &value) != 1)
{
printf("I said number.\n");
exit(1);
}
return value;
}
int main(void)
{
atexit(wait_at_exit);
int val_a = get_a_number("Write a number A=");
int val_b = get_a_number("Write a number B=");
int result = val_a + val_b;
printf("%d + %d = %d\n", val_a, val_b, result);
return(0);
}
main()
中的代码假定您可以任意混合语句(例如atexit()
)和声明(例如int val_a
)。这是标准C的当前(2011)和旧版本(1999)允许的,但标准C的原始(1989)版本不允许这样做。我相信MSVC遵守原始标准。如果是这样,您可能需要将main()
写为:
int main(void)
{
atexit(wait_at_exit);
{
int val_a = get_a_number("Write a number A=");
int val_b = get_a_number("Write a number B=");
int result = val_a + val_b;
printf("%d + %d = %d\n", val_a, val_b, result);
}
return(0);
}
内部块(内部大括号)内的代码是否应该缩进一个额外的级别是一个很好的讨论点。您始终可以在括号中包含的代码块的开头声明变量,这样我就可以将调用写入atexit()
,然后定义并使用这些变量。
如果你读到敏捷编程,你会发现其中一个咒语是:
上面重写以避免重复getscr()
次调用可被视为该咒语的应用。与get_a_number()
函数类似;它适用于DRY口头禅。
如果您希望程序返回并在用户输入错误时再次提示,则需要修改get_a_number()
功能。并且,因为函数变得更加复杂,所以肯定需要为作业使用函数。您还遇到scanf()
的问题;它不允许你每行强制执行一个数字。如果您在响应第一个提示时键入1 2
,则第一次调用get_a_number()
将读取一个空白,停止解析(并将空白放回以供重用),并返回值1 。对get_a_number()
的第二次调用将输出提示,但返回值为2,而用户不再输入任何内容。如果这不是您想要的行为,那么您必须安排阅读整个第一行并扫描该数字,然后丢弃其余部分。令人担忧的另一个原因。如果用户键入a
而不是1
,则scanf()
将永远不会读取任何内容;它将进入循环,发现a
无效为数字,返回0转换完成,您的代码可能会以无限循环结束,提示输入并读取a
。这类问题是许多人(特别是我)避免使用scanf()
的原因。
避免上述大多数问题的最简单方法是fgets()
和sscanf()
:
enum { MAX_LINELENGTH = 4096 };
enum { MAX_ATTEMPTS = 10 };
static int get_a_number(const char *prompt)
{
int value;
char line[MAX_LINELENGTH];
int count = 0;
while (fputs(prompt, stdout) != EOF &&
fgets(line, sizeof(line), stdin) != 0)
{
if (sscanf(line, "%d", &value) == 1)
return value;
if (count++ > MAX_ATTEMPTS)
{
printf("I give in; I don't understand what you're typing\n");
exit(1);
}
printf("I said please enter a number.\n");
}
printf("Oops: I got EOF or an error; goodbye!\n");
exit(1);
}
这涵盖了很多问题。通常,回显错误的数据是个好主意。你可以这样做:
printf("I didn't understand what you meant when you typed:\n%s\n"
"I said please enter a number.\n", line);
这使用&#39;相邻字符串连接&#39;,并向用户显示程序收到的内容,这通常可以帮助用户理解错误。
我使用fputs(prompt, stdout)
代替printf(prompt)
来输出提示。两者都可以使用(printf(prompt) != 0
将是测试),但fputs()
略有优势,因为如果有人设法颠覆您的程序并在提示中获得%
,{ {1}}将尝试处理未传递的参数,而printf()
根本不解释其参数字符串。在这里,差异可以忽略不计;我可以合理地认为我过于复杂化了。但是程序的安全性也是你最终学习的东西,并且诸如&#34;之类的技术不会使用fputs()
&#34;可以帮助您的程序更具弹性。 (实际上,复杂性是解释;代码非常简单。)
如果在printf(variable)
之后和fflush()
之前有fputs()
,那么另一个详细的讨论点是什么?&#39;可以添加额外的条件&#39; fgets()
到循环控件,但在实践中通常是不必要的。如果标准输入来自终端之外的其他东西并且标准输出转到文件,那么它只会产生影响。所以,我把它留了出来。
循环中的计数器可防止出现严重错误 - 程序退出而不是永远停留,令无法正确输入数据的用户感到沮丧。你有没有一个程序弹出一个对话框,你只能在其中点击“确定”。按钮(即使它不正常),然后再次使用同一个盒子,一遍又一遍地回来?我希望不是为了你。我有;当它发生时它会让我感到沮丧。
你可以看到为什么在fflush(stdout) == 0 &&
中只用一次而不是两次写代码是有利的;这将是很多重复。
答案 1 :(得分:1)
您需要检查scanf()
是否已成功读取应阅读的输入。通常,您应该在阅读后确认读取成功。 scanf()
返回成功读取的输入数,这些输入基本上映射到它可以成功读取的格式说明符的数量。例如,你应该检查
if (scanf("%d, &val_a) == 1)) {
...
}
读取的值可能是或不是“数字”。通常,根据isdigit()
,它可能不是数字,因为此函数仅对字符'0'
,'1'
,...,'9'
的整数值返回true。测试scanf()
是否可以读取所有格式说明符应避免此问题。
如果scanf()
失败,您可以阅读一个字符(使用例如fgetc()
)并再次重试或阅读整行(不使用gets()
但使用{ {1}})。您可能还希望打印输入不符合预期的消息。
答案 2 :(得分:0)
你的isdigit
功能都错了。它意味着接收一个char参数,但在你的情况下,int会被转换,你可能会说降级。
该功能基于字母的ASCII码link here。你可以尝试这样看看。
char c = '1';
if(isdigit(c))
printf("digit");
此外,您需要的是do{ /* something */ } while(boolean);
答案 3 :(得分:0)
你误解了isdigit函数的使用。它确定字符是否是诸如“0”,“1”,“2”等数字。但是,您已经使用scanf函数将输入转换为整数。因此,只需删除对isdigit的调用,然后检查scanf的返回代码,它将告诉您用户是否输入了有效数字。