提示是:我应该为客户管理系统编写一个用于注册客户的程序(用C编程语言)。
该方案应允许注册管理成员:
(注:如果用户输入“男性或女性”以外的性别,程序应显示错误信息“无效输入!(性别必须为男性或女性)”,并强制用户输入正确的性别。)
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
int n_r=0;
struct customer // using a struct will be better than an array since it
{ // can store several data types unlike an array
int id;
char firstname[20];
char lastname[20];
int age;
char gender[6];
char city[20];
};
void displayMainMenu() // print menu
{
printf("\n -------------------------------------------------------------\n");
printf("\n -------------Customer Management System ---------------------\n");
printf("\n ------------------------* MAIN MENU *----------------------------\n");
printf("\n |A/a:Enter A or a for Adding a Customer ");
printf("\n |D/d:Enter D or d for Printing Customer Details ");
printf("\n |E/e:Enter E or e for Exiting the Program |------------------\n");
}
char inputAndCheck()
{
char ch;
while(1)
{
displayMainMenu();
printf("\n Please enter your choice: ");
scanf("%c",&ch);
if(ch=='A'||ch=='a'||ch=='D'||ch=='d'||ch=='E'||ch=='e')
break;
else
{
printf("\n > Invalid selection! Please try again ");
}
}
return ch;
}
int readCustomerAge()
{
int age;
while(1)
{
printf("\n Enter age: ");
scanf("%d",&age);
if(age>=15 && age<=90)
break;
else
{
printf("\n > Invalid selection! (Age must be between 15 and 90) ");
}
}
return age;
}
int readCustomerGender()
{
char ch1[6];
while(1)
{
printf("\n Enter gender: ");
scanf("%s",ch1);
if((strcmp(ch1,"male")==0)||(strcmp(ch1,"MALE")==0))
{
return 0;
}
else if((strcmp(ch1,"female")==0)||(strcmp(ch1,"FEMALE")==0))
{
return 1;
}
else{
printf("\n > Invalid selection! (Gender must be male or female) ");
}
}
}
char* readCustomerCity()
{
char c[20];
printf("\n Enter city: ");
scanf("%s",c);
return c;
}
void displayCustomerDetails()
{
FILE *fp;
struct customer c;
fp=fopen("customer.txt","r");
if(fp==NULL)
{
printf("\n Error in opening a file.");
exit(1);
}
while(fread(&c,sizeof(struct customer),1,fp))
printf("\n Id:%d \n Name:%s %s \n Age=%d \n Gender=%s \n City=%s",c.id,c.firstname,c.lastname,c.age,c.gender,c.city);
fclose(fp);
}
void addCustomerDetails()
{
FILE *fp;
struct customer c;
char* gen;
//char cit[30];
if(n_r==0)
{
fp=fopen("customer.txt","w");
if(fp==NULL)
{
printf("\n Error in opening a file.");
exit(1);
}
}
else
{
fp=fopen("customer.txt","a");
if(fp==NULL)
{
printf("\n Error in opening a file.");
exit(1);
}
}
printf("\n Enter customer ID: ");
scanf("%d",&c.id);
printf("\n Enter customer first name: ");
scanf("%s",&c.firstname);
printf("\n Enter customer last name: ");
scanf("%s",&c.lastname);
c.age=readCustomerAge();
if(readCustomerGender())
{
strcpy(c.gender,"Female");
}
else
{
strcpy(c.gender,"Male");
}
printf("\n Enter customer city: ");
scanf("%s",&c.city);
fwrite(&c,sizeof(struct customer),1,fp);
fclose(fp);
}
int main()
{
int year;
char ch;
printf("\n -------------------------------------------------------------\n");
printf("\n -------------Welcome to Customer Management System ---------------------\n");
printf("\n > Please Enter Customer registration year (ex:2017):");
scanf("%d",&year);
printf("\n > How many customers do you want register in the year %d:",year);
scanf("%d",&n_r);
while(1)
{
ch=inputAndCheck();
switch(ch)
{
case 'A':
case 'a':
addCustomerDetails();
n_r++;
break;
case 'D':
case 'd':
displayCustomerDetails();
break;
case 'E':
case 'e':
printf("\n > Thank you for using Customer Management System!\n");
printf("\n > Good Bye. \n");
exit(0);
}
}
return 0;
}请注意,我还没有完成为程序的评论,但将继续写在我收到反馈意见。
发布于 2021-04-12 21:28:16
而不是
char gender[6];如果你想限制两个性别,你最好做一个enum。然而,这样做通常是一个糟糕的选择;相反,只需要接受一个自由字符串,而不必为M/F编写逻辑。
n_r目前唯一有用的角色似乎是决定数据库文件的写入模式。您可以完全摆脱它,并根据I/O操作自动排序写入模式。
在命令行接口中,更典型的做法是
printf("Foo\n");比
printf("\nFoo");因为--从程序的一开始--我们就假设得到一个空行,所以做第二行是没有意义的。另一个原因是,某些缓存逻辑依赖后缀换行符,而不是前缀换行符,以知道何时写入流。
您基本上是一次检查这个逻辑,一次检查有效的选择字符,另一次实际注意选择。这样做一次而不是tolower(),这样您只需要检查一个值。
scanf已经..。很多问题。例如,它污染了stdin缓冲区,因此很难从错误(例如,有人输入文本而不是整数)中恢复。
一个常见的解决方法是用fgets/sscanf对替换它。
displayCustomerDetails实际上做了两件事--从文件中读取,并显示给stdout。你应该把这个分开。同样适用于addCustomerDetails。
您要求--而且完全忽略--注册年份的输入;而n_r的输入既令人困惑,也没有正确地使用。你可以把这两样都处理掉。
当扫描到固定缓冲区中的字符串时,关键是要告诉输入函数缓冲区大小,这样就不会出现溢出。C特别容易受到缓冲区溢出崩溃和安全漏洞的影响。
|E/e在格式化方面有点奇怪。熟悉命令行接口的用户将管道理解为两个选项之间的“或”;因此,在这里将其视为可视分隔符有点令人不快。EBNF建议使用E|e。
此代码提供了一种处理(大部分)上述问题的方法:
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int n_r = 0;
typedef enum {
MALE = 0,
FEMALE = 1
} gender;
typedef struct tag_customer
{
unsigned id;
char firstname[20];
char lastname[20];
unsigned age;
gender gender;
char city[20];
} customer;
static void displayMainMenu()
{
puts(
"-------------------------------------------------------------"
"\n-------------Customer Management System ---------------------"
"\n------------------------* MAIN MENU *------------------------"
"\n A|a: Add a Customer"
"\n D|d: Print Customer Details"
"\n E|e: Exit"
);
}
static void scanLoop(const char *prompt, const char *fmt, void *dest)
{
char buffer[80];
int fields;
do
{
printf(prompt);
if (!fgets(buffer, sizeof(buffer), stdin))
{
perror("I/O error on stdin");
exit(1);
}
fields = sscanf(buffer, fmt, dest);
} while (fields != 1);
}
static char menuChoice()
{
displayMainMenu();
char choice;
scanLoop("Please enter your choice: ", "%c", &choice);
return tolower(choice);
}
static unsigned readCustomerAge()
{
while (true)
{
unsigned age;
scanLoop("Enter age: ", "%u", &age);
if (age >= 15 && age <= 90)
return age;
puts("Invalid selection! (Age must be between 15 and 90)");
}
}
static gender readCustomerGender()
{
char buffer[10];
while (true)
{
scanLoop("Enter gender (male|female): ", "%9s", buffer);
for (char *p = buffer; *p; p++)
*p = tolower(*p);
if (!strcmp(buffer, "male"))
return MALE;
if (!strcmp(buffer, "female"))
return FEMALE;
puts("Invalid selection!");
}
}
static void displayCustomer(const customer *c)
{
printf(
"Id: %u"
"\nName: %s %s"
"\nAge: %u"
"\nGender: %s"
"\nCity: %s"
"\n",
c->id, c->firstname, c->lastname, c->age,
c->gender == MALE ? "male" : "female",
c->city
);
}
static void readCustomers(const char *filename)
{
FILE *fp;
customer c;
fp = fopen(filename, "r");
if (fp == NULL)
{
perror("Error opening file for customer display");
exit(1);
}
while (fread(&c, sizeof(customer), 1, fp))
displayCustomer(&c);
fclose(fp);
}
static void scanCustomer(customer *c)
{
scanLoop("Enter customer ID: ", "%u", &c->id);
scanLoop("Enter customer first name: ", "%20s", c->firstname);
scanLoop("Enter customer last name: ", "%20s", c->lastname);
c->age = readCustomerAge();
c->gender = readCustomerGender();
scanLoop("Enter city: ", "%20s", c->city);
}
static void addCustomer(const char *filename)
{
const char *mode;
if (n_r == 0)
mode = "w";
else mode = "a";
FILE *fp = fopen(filename, mode);
if (fp == NULL)
{
perror("Error in opening customer file for writing");
exit(1);
}
customer c;
scanCustomer(&c);
fwrite(&c, sizeof(customer), 1, fp);
fclose(fp);
}
static unsigned readYear()
{
unsigned year;
while (true)
{
scanLoop("Please Enter Customer registration year (ex:2017): ", "%u", &year);
if (year >= 2000 && year <= 2500)
return year;
puts("Year out of range");
}
}
int main()
{
printf(
"------------------------------------------------------------------------"
"\n-------------Welcome to Customer Management System ---------------------"
"\n"
"\n"
);
readYear();
while (true)
{
switch (menuChoice())
{
case 'a':
addCustomer("customer.txt");
n_r++;
break;
case 'd':
readCustomers("customer.txt");
break;
case 'e':
puts(
"Thank you for using Customer Management System!"
"\nGoodbye."
);
return 0;
default:
puts("Invalid selection! Please try again.");
}
}
}https://codereview.stackexchange.com/questions/259376
复制相似问题