输入验证和菜单浏览

一、输入验证
1.在实际应用中,用户不一定会按照程序的指令行事。用户的输入和程序期望的输入不匹配时常发生,这会导致程序运行失败。作为程序员,除了完成编程的本职工作,还要事先预料一些可能的输入错误,这样才能编写出能检测并处理这些问题的程序。
(1)例如,假设你编写了一个处理非负数整数的循环,但是用户很可能输入一个负数。你可以使用关系表达式来排除这种情况:
long n;
scanf("%ld",&n);//获取第1个值
while(n>=0)//检测不在范围内的值
{
//处理n
scanf("%ld",&n);//获取下一个值
}
(2)另一类潜在的陷阱是,用户可能输入错误类型的值,如字符q。排除这
种情况的一种方法是,检查scanf()的返回值。回忆一下,scanf()返回成功读
取项的个数。因此,下面的表达式当且仅当用户输入一个整数时才为真:
scanf("%ld",&n)1
结合上面的while循环,可改进为:
long n;
while(scanf("%ld",&n)
1&&n>=0)
{
//处理n
}
while循环条件可以描述为“当输入是一个整数且该整数为正时”。对于最后的例子,当用户输入错误类型的值时,程序结束。然而,也可以让程序友好些,提示用户再次输入正确类型的值。在这种情况下,要处理
有问题的输入。如果scanf()没有成功读取,就会将其留在输入队列中。这里
要明确,输入实际上是字符流。可以使用getchar()函数逐字符地读取输入,
甚至可以把这些想法都结合在一个函数中,如下所示:
longget_long(void)
{
longinput;
charch;
while(scanf("%ld",&input)!=1)
{
while((ch=getchar())!='\n')
putchar(ch);//处理错误的输入
printf("isnotaninteger.\nPleaseenteran");
printf("integervalue,suchas25,-178,or3:");
}returninput;
}
2.假设程序中包含了stdbool.h头文件。如果当前系统不允许使用_Bool,
把bool替换成int,把true替换成1,把false替换成0即可。注意,如果输入
无效,该函数返回true,所以函数名为bad_limits():
bool bad_limits(long begin, long end,long low,long high)
{
bool not_good=false;
if(begin>end)
{
printf("%ld isn't smaller than %ld \n", begin, end);
not_good=true;
if(begin < low || end<low)
{
printf("Values must be %ld or greater.\n",low);
not_good=true;
}
if(begin>high || end>high)
{
printf("Values must be %ld or less.\n",high);
not_good true;
}
return not_good;
}
3.输入流和数字
函数 scanf() 是从标准输入流stdio (标准输入设备,一般指向键盘)中读内容的通用子程序,可以说明的格式读入多个字符,并保存在对应地址的变量中。
函数的第一个参数是格式字符串,它指定了输入的格式,并按照格式说明符解析输入对应位置的信息并存储于可变参数列表中对应的指针所指位置。每一个指针要求非空,并且与字符串中的格式符一一顺次对应。
返回值:scanf函数返回成功读入的数据项数,读入数据时遇到了“文件结束”则返回EOF。
如:
scanf("%d %d",&a,&b);
1
函数返回值为int型。如果a和b都被成功读入,那么scanf的返回值就是2;
如果只有a被成功读入,返回值为1;
如果a和b都未被成功读入,返回值为0;
如果遇到错误或遇到end of file,返回值为EOF。end of file为Ctrl+z 或者Ctrl+d。
使用scanf输入数据:

include <stdio.h>

int main(void)
{
int a,b,c;
printf("Give me the value of a,b,c seperated with whitespaces:\n");
scanf("%d%d%d",&a,&b,&c);
printf("a=%d,b=%d,c=%d\n",a,b,c);
return 0;
}
&a,&b,&c中的&是寻址操作符,&a表示对象a在内存中的地址 [2] ,是一个右值。变量a,b,c的地址是在编译阶段分配的(存储顺序由编译器决定)。
这里注意:如果scanf中%d是连着写的如“%d%d%d”,在输入数据时,数据之间不可以用逗号分隔,只能用空白字符(空格或tab键或者回车键)分隔——“2 (空格)3(tab) 4” 或 “2(tab)3(回车)4”等。若是“%d,%d,%d”,则在输入数据时需要加“,”,如“2,3,4”。
二、菜单浏览
许多计算机程序都把菜单作为用户界面的一部分。菜单给用户提供方便
的同时,却给程序员带来了一些麻烦。我们看看其中涉及了哪些问题。
菜单给用户提供了一份响应程序的选项。假设有下面一个例子:
Enter the letter of your choice:
a.advice b.bell
c.count q.quit
理想状态是,用户输入程序所列选项之一,然后程序根据用户所选项完
成任务。作为一名程序员,自然希望这一过程能顺利进行。因此,第1个目
标是:当用户遵循指令时程序顺利运行;第2个目标是:当用户没有遵循指
令时,程序也能顺利运行。显而易见,要实现第2个目标难度较大,因为很
难预料用户在使用程序时的所有错误情况。
1.任务
我们来更具体地分析一个菜单程序需要执行哪些任务。它要获取用户的响应,根据响应选择要执行的动作。另外,程序应该提供返回菜单的选项。
C的switch语句是根据选项决定行为的好工具,用户的每个选择都可以对应一个特定的case标签。使用while语句可以实现重复访问菜单的功能。因此,我们写出以下伪代码:
获取选项
当选项不是'q'时
转至相应的选项并执行
获取下一个选项
2.混合字符和数值输入
voidcount(void)
{
intn,i;
printf("Count how far?Enter an integer:\n");
scanf("%d",&n);
for(i=1;i<=n;i++)
printf("%d\n",i);
}
如果输入3作为响应,scanf()会读取3并把换行符留在输入队列中。下次
调用
get_choice()将导致get_first()返回这个换行符,从而导致我们不希望出现的行为。
重写
get_first(),使其返回下一个非空白字符而不仅仅是下一个字符,
即可修复这个问题。我们把这个任务留给读者作为练习。另一种方法是,在
count()函数中清理换行符,如下所示:
void count(void)
{
int n,i;
printf("Count how far?Enter an integer:\n");
n=get_int();
for(i=1;i<=n;i++)
printf("%d\n",i);
while(getchar()!='\n')
continue;
}
四、void函数
1.简介
void 中文翻译为"无类型",有的也叫"空类型"。常用在程序中对定义函数的参数类型、返回值、函数中指针类型进行声明。
2.用法
首先应该注意一点的是void类型是不同于其他常见类型的,即void 类型不能够用来申明变量和常量。因为我们申明变量的时候需要明确告诉编译器,该变量是什么类型,比如说是int 或 char类型,这样编译才好为这个变量去分配存储空间,但你不能告诉编译器说我这是一个"空类型",这样的话编译器肯定不会干的,自然你编译的时候会报错: "illegal use of type 'void'"。
3.void函数的实例
(2)示例一:交换两个整型变量数值的函数

include

using namespace std;
void swap(int& a, int&b)
{
if(a == b)
{
return;//若两值相等,无需比较,即让函数停止运行
}
int temp;
temp = a;
a = b;
b = temp;
}

int main()
{
int a=3, b=4;
cout<<"交换前a=3, b=4"<<endl;
swap(a,b);
cout<<"交换后a="<<a<<", b="<<b<<endl;
system("pause");
return 0;
}
=>交换前a=3, b=4
交换后a=4, b=3
这个函数首先检查两个值是否相等,如果相等则退出函数;如果不相等,则交换这两个值,隐式的return发生在最后一个赋值语句后。
(2)void 的函数,可以返回另一个返回类型同样是void的函数的调用结果

include

using namespace std;

void do_swap(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}

void swap(int& a, int&b)
{
if(a == b)
{
//return false;//编译失败,提示"error C2562: “swap”:“void”函数返回值"
return;//编译成功,不带返回值的return语句只能用于返回类型为void的函数
}
return do_swap(a, b);//编译成功,void 的函数,可以返回另一个返回类型同样是void的函数的调用结果
}

int main()
{
int a=3, b=4;
cout<<"交换前a=3, b=4"<<endl;
swap(a,b);
cout<<"交换后a="<<a<<", b="<<b<<endl;
system("pause");
return 0;
}
=>交换前a=3, b=4
交换后a=4, b=3
返回任何其他表达式的尝试都会导致编译时的错误。
4.总结
(1)如果函数没有返回值那么应声明为void 类型
C语言中有一个规则,凡是不加返回值限定的函数,就会被编译器作为整型值(int)处理。但是许多人却误以为其为void类型。
(2)如果函数无参数,那么应该声明其参数为void
如果我们所写的函数不接受任何参数,那么一定要指明其参数为void。
(3)如果函数的参数可以是任意类型指针,那么应声明其参数为void *
(4)void 不能代表一个真实的数据类型
这个前面提到过,因为void在C语言中解释为空,或者无类型,所以它当然无法代表一个真实的数据类型了。不过我们可以对其进行类型转换,这样它又可以变成各种各样的数据类型,所以我们可以将其理解成一个"抽象数据类型"。

posted @ 2022-01-30 19:35  Saph  阅读(116)  评论(0)    收藏  举报