c语言菜单选择如何用字符形式,[C语言] 实现简单的菜单式互动程序2

0.前言

在上一篇文章《[C语言] 实现简单的菜单式互动程序》中,已经讲述了如何使用c语言实现一个简单的菜单式互动程序(一个模拟ATM机的小程序)

正如上一篇文章的总结所说,所有的代码全部放入main函数中,会导致:

①代码冗杂; ②不利于阅读; ③不利于移植

因此,本文在对上一篇文章的代码进行一定改进的同时,也着重于分享介绍:应该如何将main函数中冗杂的代码,按照模块化的思想,通过自定义函数,让整个程序更加干净整洁

1.程序编写目的

1.1练习函数的定义以及使用

1.2通过训练培养代码的模块化思想

1.3训练程序编写逻辑

2.实现该程序所需要的技术

2.1自定义函数

自定义函数格式:

函数返回值类型 函数名(参数,参数....){

}

实际的例子:

int add(int a,int b){//a和b是形式参数

int result = 0;

result = a + b;

return result;//返回值

}

2.2输入检测判断

使用该技术的原因:当按照菜单提示进行操作的选择时,用户可能会不小心输入错误,(如输入字母、1至5以外的数字等)因此需要加入输入检测判断的功能,具体如图所示:

e9cc05926449

输入不合法.png

2.3主函数的编写方式

如果代码全部塞入主函数中,就会导致主函数过于的冗杂,那是不是让主函数尽可能简单就是好的函数呢?

答案是否定的。

void main(){

login();

showMenu();

choice();

}

这么写确实主函数含简洁,但是别人看到这个主函数并不知道这个程序的目的和意义。

这种写法除了欠缺注释以外,还缺少逻辑结构的展现

主函数的编写,主要是要做到:

能够让阅读主函数的人基本清楚程序的目的

明确每一个步骤的意义

3.技术的使用方式

程序的主要思路可以参考上一篇文章《如何用c实现简单的菜单式互动程序》

地址:https://www.jianshu.com/p/c78e8feaf426

这篇文章会以该地址中给出的代码(后文会称为“旧代码”)为基础进行改进,主要阐述如何使用函数、主函数如何编写、以及一些细节优化问题

3.1如何将不同模块更改为函数

函数的特点在于可以反复调用

因此,一般需要函数化的代码,就是那些需要重复使用的代码

3.1.1重复使用的代码要要编写成函数

遇到要重复使用的代码优先考虑将其定义在函数中,然后只需要调用该函数即可,

例如,在“旧代码”中,会有:

printf("***********************************\n");

printf("**** 1.取款 2.存款 ******\n");

printf("**** 3.显示余额 ******\n");

printf("**** 4.设置密码 5.退出 ******\n");

printf("***********************************\n");

“旧代码”中这个菜单只会显示一次,如果用户输入内容过多,可能会出现用户看不到菜单的情况,因此在这次的改进中,会多次显示这个菜单,而且每次操作完成后会对控制台进行清屏重新显示,以保证用户界面的整洁。

而这个重复多次显示,则需要用到自定义函数

void showMenu() {

printf("***********************************\n");

printf("**** 1.取款 2.存款 ******\n");//开始存、取款

printf("**** 3.显示余额 ******\n");

printf("**** 4.设置密码 5.退出 ******\n");//请输入原始、新密码

printf("***********************************\n");

}

由于是简单的显示,因此不需要返回值,也不需要参数,这种函数应该属于最简单的函数

3.1.2比较复杂的操作要编写成函数

在“旧代码”中,出现了:

while (flag == 'Y') {

printf("请输入取款金额!\n");//取款成功,当前余额为

scanf_s("%d", &money);

if (money > remains) {

printf("余额不足,是否重新输入?(Y/N)\n");

while ((ch = getchar()) != '\n');//清空缓存区

scanf_s("%c", &flag);

} else {

remains = remains - money;

printf("取款成功!\n");

flag = 'N';

}

}

这一大段代码负责实现取款功能,这么一大段代码放在switch语句中的一个case里,本身就显得很臃肿,而switch又在main里面,那这个main函数就会变得很难看了

像这种一大段代码完成一个(复杂)操作的情况,就可以把这一大段代码编写成一个函数

void withdraw() {

int outMoney = 0;

while (1) {

printf("请输入取款金额:");

scanf_s("%d", &outMoney);

if (outMoney > 0 && outMoney <= totalMoney) {

totalMoney -= outMoney;

printf("取款成功,余额为:%d", totalMoney);

//提示是否继续

if (!ifContinue()) {//不继续

return;

}

}

else {

printf("余额不足,");

if (!ifContinue()) {

return;

}

}

}

}

而switch语句中,则会变成:

case 1:

withdraw();//取款

break;

可见会变得十分简洁

大家可以对比一下使用函数与不使用函数二者的观感:

case 1:

while (flag == 'Y') {

printf("请输入取款金额!\n");//取款成功,当前余额为

scanf_s("%d", &money);

if (money > remains) {

printf("余额不足,是否重新输入?(Y/N)\n");

while ((ch = getchar()) != '\n');//清空缓存区

scanf_s("%c", &flag);

}

else {

remains = remains - money;

printf("取款成功!\n");

flag = 'N';

//while ((ch = getchar()) != '\n');//清空缓存区

}

}

//存款成功,当前余额为20->余额不足,是否继续Y/N

break;

case 2:

printf("请输入存款金额!\n");

scanf_s("%d", &money);

remains = remains + money;

//while ((ch = getchar()) != '\n');//清空缓存区

printf("存款成功!\n");

break;

case 3:

printf("您的余额为:%d\n", remains);

break;

case 4:

printf("请输入新密码\n");

scanf_s("%d",&password);

printf("设置成功!\n");

break;

case 5:

break;

default:

break;

}

以上为“旧代码”中的写法,不使用函数,下面是使用函数的写法

case '1':

withdraw();//取款

printf("取款结束\n");

break;

case '2':

deposit();//存款

printf("存款结束\n");

break;

case '3':

showRemains();//显示余额

break;

case '4':

setPassword();//修改密码

printf("修改密码成功!\n");

break;

default:

exitATM(EXIT_SUCCESS);

break;

}

对比结果一目了然,这样就能明白使用函数的原因

3.2如何编写主函数

这里就不放出“旧代码”了,“旧代码”把代码全不写在主函数中,十分臃肿,那么将每个模块函数化后,主函数应该得剩下些什么?写些什么呢?

void main() {

//欢迎界面

showWelcome();

//输入密码

bool result = loginATM();

if (result == false) {

exitATM(EXIT_FAILURE);

}

//主要操作

while (1) {

showMenu();

//接收用户的选择

char choice = getChoice();//获取操作

switch (choice)

{

case '1':

withdraw();//取款

system("cls");

printf("取款结束\n");

break;

case '2':

deposit();

system("cls");

printf("存款结束\n");

break;

case '3':

system("cls");

showRemains();

break;

case '4':

setPassword();

system("cls");

printf("修改密码成功!\n");

break;

default:

exitATM(EXIT_SUCCESS);

break;

}

}

}

这就是进行修改之后的主函数,我们可以清晰地看到每一部分的作用,另外,除了添加的注释外,换行(就是空白行)也很好地起到了将各个模块分开的任务

虽然看上去没有想象中的短,但实际上,我们可以根据主函数,得出整个程序的运行思路,这个是十分关键的

3.3如何进行输入检测

上文提到了输入检测,也有图片显示效果,那么这里先讲一下实现思路:

(1)将输入的内容放到一个char类型的数组中(每个字符一个元素)

(2)通过strlen函数判断字符串长度

(3)如果字符串长度大于1,证明输入了一长串内容,不符合要求

(4)如果字符串等于1,说明只有一个字符,判断其ASCII码即可

具体做法:

(1)先定义一个数组ch[20](20是假设最多输入了20个字符)

(2)用scanf_s("%s",ch,20);来把输入的字符串放入这个数组

(3)引入头文件stdlib.h(#include),使用strlen()函数计算字符串长度

(4)用一个int变量count来接收strlen的返回值,并判断count是否大于1,大于,则用while让其重新输入,等于1,则判断该字符串的第一个元素(ch[0])的ASCII码是否在49到53之间(‘1’的ASCII为49)

4.实际应用

将主函数分为几部分:

(1)欢迎界面

(2)密码检测

(3)主要操作

欢迎界面、密码检测需要作为一个函数,而主要操作则是将结构留在主函数中,着重将具体的操作进行函数化

void showMenu() {

printf("***********************************\n");

printf("**** 1.取款 2.存款 ******\n");//开始存、取款

printf("**** 3.显示余额 ******\n");

printf("**** 4.设置密码 5.退出 ******\n");//请输入原始、新密码

printf("***********************************\n");

}

密码检测也要作为一个函数loginATM(),不过该函数只需要负责密码的输入以及检测是否正确

而密码正确或是错误对应的操作包含在主函数而非loginATM()中

原因在主函数中对密码正确、错误的操作进行反应,能够让人更清楚程序结构

同理,switch函数依然保留在主函数中,原因同上(保留主要操作的结构)

而那些要多次实行的操作,如输出菜单、接受用户操作、询问是否继续,这些不影响程序结构,而是注重于实际操作的代码,都需要单独写一个函数

bool ifContinue() {//询问是否继续

printf("是否继续?(y/n):\n");

char chTemp;

while ((chTemp = getchar()) != '\n');//这两句话用来清空缓存区

char ch = getchar();

if (ch != 'n') {

//继续

return true;

}

else {

//退出

return false;

}

}

char getChoice() {//获取用户想要执行的操作的编号

char temp[20] = {};

//将输入的所有字符串全部从缓存中读取出来

while (1) {

printf("请选择操作:");

char chTemp;

while ((chTemp = getchar()) != '\n');//这两句话用来清空缓存区

scanf_s("%s", temp, 20);//不用&,因为是数组

int count = strlen(temp);

if (count != 1) {

printf("输入不合法,请重新");

}

else {//还得判断该字符正确与否

char ch = temp[0];

if (ch >= 49 && ch <= 53) {

return ch;

}

else {

printf("输入不合法,请重新");

}

}

}

}

可见,实际上很多函数化就是将“旧代码”中对应的部分取出来放到函数中,然后做适当的修改,其他地方也是同理,就布全部贴出了

因此,在做基础训练的时候,就应该有意识地去按照模块化的思维去编写,即要以一个模块解决一个问题为目标去编写,而不是程序能运行就好

5.总结

(1)这次用编写函数的方式来完成这个程序,让我更加明白现实情况中是如何编写代码的。经过多次训练后,也逐渐掌握了哪些代码应该函数化,应该如何函数化

(2)还有一点很重要的是,这些练习让我第一次认识到应该如何在编写函数的情况下,更好地完成主函数(如何处理好主函数中的结构关系),主函数的结构的编写也是我觉得最困难的地方,需要更多地去练习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值