我遇到了一个简单登录程序代码的问题。我面临的问题是当我使用switch case或if语句作为Admin或User登录的选项时,会跳过username的输入并直接转到密码,无论我输入什么给我我的错误信息。相反,我希望它先接收我的用户名然后再输入密码。如果管理员或用户只有一个代码,只有一个代码,但是当有多个代码时,它可以自行运行。请帮忙。注意:我为管理员和用户使用相同的功能只是为了检查它是否有效。图为输出。我是C新手,也许是最小的行话?代码如下:
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
char username[18];
char pass[16];
void arequest()
{
printf("\nPlease Enter username:");
fflush(stdin);
gets(username);
printf("\nPlease Enter Password:");
fflush(stdin);
gets(pass);
}
void averify()
{
if (strcmp(username, "admin") == 0)
{
if (strcmp(pass, "apass") == 0)
{
printf("Successful Login");
_getch();
}
else
{
printf("Invalid Password");
_getch;
}
}
else
{
printf("Invalid Username");
_getch();
}
}
int choice;
int main()
{
printf("Welcome to Railway Reservation System");
printf("\n1.Admin \n2.User");
printf("\nPlease Enter your selection:");
scanf_s("%d", &choice);
if (choice == 1)
{
arequest();
averify();
}
else if (choice == 2)
{
arequest();
averify();
}
else
{
printf("Invalid Choice");
_getch();
return main;
}
return 1;
}
答案 0 :(得分:0)
您正在使用fflush()
刷新输入流。在大多数情况下,fflush(stdin)
是未定义的行为,并且最多依赖于实现。要清除输入流中的额外字符,请考虑编写一个这样的小函数:
void clear_stream(void)
{
int c;
while ((c = _getch()) != '\n' && c != EOF)
continue;
}
移除对fflush()
的来电。由于gets(username)
丢弃换行符,因此您无需在gets()
之后清除该流。在clear_stream()
中的这一行之后添加对main()
的电话:
scanf_s("%d", &choice);
在调用scanf_s()
之后,输入流中可能会有额外的字符,包括换行符,并且在尝试再次读取用户输入之前需要删除这些字符。在某些情况下,scanf()_s
(和scanf()
)会跳过阅读输入中的初始空格,但_getch()
和getchar()
则不会。这说明了使用scanf()
的危险之一。
printf("\nPlease Enter your selection:");
scanf("%d", &choice);
clear_stream();
此外,gets()
被认为是如此危险,以至于根本没有理由将其用于任何事情。请改用fgets()
。 fgets()
确实保留换行符,其中gets()
丢弃了换行符,因此我经常使用gets()
编写我自己的fgets()
版本,这是安全的:
char * s_gets(char *st, int n)
{
char *ret;
int ch;
ret = fgets(st, n, stdin);
if (ret) {
while (*st != '\n' && *st != '\0')
++st;
if (*st)
*st = '\0';
else {
while ((ch = getchar()) != '\n' && ch != EOF)
continue; // discard extra characters
}
}
return ret;
}
库conio.h
是非标准的,函数_getch()
和scanf_s()
也是如此。您应该使用stdio.h
函数getchar()
和scanf()
。 scanf()
返回的值是成功分配的数量,您应该检查这一点以确保输入符合预期。在您的程序中,如果用户在选择提示符处输入了一个字母,则不会进行任何分配,并且choice
的值仍未初始化。代码继续而不处理此问题。 choice
可以初始化为某个合理的值,例如int choice = -1;
。或者,您可以检查scanf()
的返回值,看看是否已完成作业,然后继续进行。
我注意到你return
来自main()
。除非出现错误,否则您应该return
0。并且,如果选择无效,我会看到您return
main
。也许你的意思是return
1?您似乎忘记了#include <string.h>
功能的strcmp()
。
最后,我不明白为什么username
,pass
和choice
是全局变量。这是一种不好的做法。这些应该在main()
中声明,并根据需要传递给函数。对于#define
全局常量MAXNAME
和MAXPASS
而言 是个好主意,而不是对数组维度进行硬编码。
当我开始时,我并不打算将其作为全面的代码审查,但这就是它的结果。以下是您的程序的修订版本,它实现了建议的更改:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNAME 18
#define MAXPASS 16
void clear_stream(void)
{
int c;
while ((c = getchar()) != '\n' && c != EOF)
continue;
}
char * s_gets(char *st, int n)
{
char *ret;
int ch;
ret = fgets(st, n, stdin);
if (ret) {
while (*st != '\n' && *st != '\0')
++st;
if (*st)
*st = '\0';
else {
while ((ch = getchar()) != '\n' && ch != EOF)
continue; // discard extra characters
}
}
return ret;
}
void arequest(char username[MAXNAME], char pass[MAXPASS])
{
printf("\nPlease Enter username:");
s_gets(username, MAXNAME);
printf("\nPlease Enter Password:");
s_gets(pass, MAXPASS);
}
void averify(char username[MAXNAME], char pass[MAXPASS])
{
if (strcmp(username, "admin") == 0)
{
if (strcmp(pass, "apass") == 0)
{
printf("Successful Login");
getchar();
}
else
{
printf("Invalid Password");
getchar();
}
}
else
{
printf("Invalid Username");
getchar();
}
}
int main(void)
{
char username[MAXNAME];
char pass[MAXPASS];
int choice;
printf("Welcome to Railway Reservation System");
printf("\n1.Admin \n2.User");
printf("\nPlease Enter your selection: ");
if (scanf("%d", &choice) == 1) {
clear_stream();
if (choice == 1)
{
arequest(username, pass);
averify(username, pass);
}
else if (choice == 2)
{
arequest(username, pass);
averify(username, pass);
}
else
{
printf("Invalid Choice: %d\n", choice);
getchar();
return 1;
}
} else {
clear_stream(); // stream has not yet been cleared
printf("Nonnumeric input");
getchar();
}
return 0;
}
评论中提到的OP scanf()
导致Visual Studio出现问题。显然Visual Studio试图强制使用scanf_s()
。这个函数的问题并不在于它本质上是坏的,只是它是非标准的。一种解决方案可能是使用已添加到代码中的s_gets()
函数将用户选择读入字符缓冲区,然后使用sscanf()
提取输入。这样做的好处在于,clear_stream()
之后无需调用s_gets()
函数,因为s_gets()
会自行清除,因此clear_stream()
函数现在可以完全删除来自该计划。这可以通过main()
:
char choice_buffer[10];
int choice;
...
if (s_gets(choice_buffer, sizeof(choice_buffer)) &&
sscanf(choice_buffer, "%d", &choice) == 1) {
if (choice == 1)
...
} else {
printf("Nonnumeric input");
getchar();
}
s_gets()
将用户输入行的前9个字符(在本例中)读取到choice_buffer
,这是一个将保存char
的数组(还有更多) choice_buffer
中的空格比保持单个数字选择和'\0'
所需的空间大。如果出现错误,s_gets()
将返回NULL
指针,否则返回指向char
的第一个choice_buffer
的指针。如果s_gets()
的返回值为非NULL
,则sscanf()
会将缓冲区中存储的第一个int
分配给choice
。如果在字符串中找不到int
,则sscanf()
返回值0,未通过条件测试。