我的简单登录程序代码遇到了问题。我面临的问题是,当我使用开关盒或if语句(以管理员或用户身份登录)时,用户名的输入将被跳过并直接输入密码,无论我输入什么,它都会给我我的错误讯息。相反,我希望它先接收我的用户名,然后再接收密码。如果只有“管理员”或“用户”的代码,而只有一个,而没有多个代码,则它不能单独工作。请帮忙。注意:我正在为管理员和用户使用相同的功能,只是为了检查它是否有效。图为输出,我是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;
}
output
最佳答案
您正在使用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()
正在1。除非出现错误,否则您应该return
0。而且,如果选择无效,我会看到您return
main
。也许您是要在这里return
1?看来您忘记了#include <string.h>
功能。最后,我不明白为什么
strcmp()
,username
和pass
是全局变量。这是一个坏习惯。这些应该在choice
中声明,并根据需要传递给函数。 main()
全局常量#define
和MAXNAME
而不是硬编码数组维是一个好主意。开始时,我并不打算将其作为全面的代码审查,但这就是它的结果。这是程序的修订版本,可实现建议的更改:
#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
MAXPASS
在Visual Studio中引起了问题。显然,Visual Studio尝试强制使用scanf()
。此功能的问题不在于它本身是不好的,还在于它是非标准的。一种解决方案可能是使用已经添加到代码中的scanf_s()
函数将用户选择读入字符缓冲区,然后使用s_gets()
提取输入。这样做的优点是,无需在sscanf()
之后调用clear_stream()
函数,因为s_gets()
会在其自身之后清除,因此现在可以将s_gets()
函数从程序中完全删除。只需在clear_stream()
中进行少量更改即可完成: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();
}
main()
最多读取用户输入到s_gets()
的一行的前9个字符(在这种情况下),该数组将容纳choice_buffer
s(char
中的空间超出了所需的空间)按住一个数字和一个choice_buffer
)。如果存在错误,则'\0'
返回s_gets()
指针,否则返回指向NULL
的第一个char
的指针。如果choice_buffer
的返回值不是-s_gets()
,则NULL
将缓冲区中存储的第一个sscanf()
分配给int
。如果在字符串中未找到choice
,则int
返回值0,从而导致条件测试失败。
关于c - 跳过第一个输入,直接转到下一个输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41158761/