使用scanf时意外地执行C程序无限循环
我到处检查,浪费了大约3个小时寻找解决方案。我的程序只是无限循环本身。这是我的C程序:使用scanf时意外地执行C程序无限循环,c,scanf,infinite-loop,C,Scanf,Infinite Loop,我到处检查,浪费了大约3个小时寻找解决方案。我的程序只是无限循环本身。这是我的C程序: #include <stdio.h> #include <string.h> int main (void) { int attempts = 0; char password[10]; do { printf("Enter your password:\n"); scanf("%[^\n]s", password)
#include <stdio.h>
#include <string.h>
int main (void)
{
int attempts = 0;
char password[10];
do
{
printf("Enter your password:\n");
scanf("%[^\n]s", password);
printf("\n");
attempts++;
} while (strcmp(password, "awesome 123 ok"));
printf("You entered a correct password in %d attempts!", attempts);
return 0;
}
#包括
#包括
内部主(空)
{
int=0;
字符密码[10];
做
{
printf(“输入密码:\n”);
scanf(“%[^\n]s”,密码);
printf(“\n”);
尝试++;
}而(strcmp(密码,“ok”);
printf(“您在%d次尝试中输入了正确的密码!”,次尝试);
返回0;
}
我尝试了
scanf(“%[A-Za-z0-9]s”,password)”
,这样它可以将所有字符和数字(包括空格)作为输入,但它只是循环。我也尝试了使用getchar()
,但即使我输入了正确的密码,它也会一次又一次地要求输入密码。我们将感谢您的帮助。您声明char password[10]
但您可以将其与包含更多字符的进行比较。您可以声明字符密码[10];
但您可以将其与具有更多字符的awesome 123 ok
进行比较。awesome 123 ok
的大小为15,包括\0
。但是您正在为10个字节分配内存。这会导致未定义的行为
当您使用%[^\n]
格式说明符时,无需使用s
,它也会自动扫描空格
尝试以下更改-
int main (void)
{
int attempts = 0;
char password[20]; // Fix 1
do
{
printf("Enter your password:\n");
scanf("%[^\n]", password); // Fix 2
printf("\n");
attempts++;
} while (strcmp(password, "awesome 123 ok"));
printf("You entered a correct password in %d attempts!", attempts);
return 0;
}
ok
的大小为15,包括\0
。但您正在为10个字节分配内存。这会导致未定义的行为
当您使用%[^\n]
格式说明符时,无需使用s
,它也会自动扫描空格
尝试以下更改-
int main (void)
{
int attempts = 0;
char password[20]; // Fix 1
do
{
printf("Enter your password:\n");
scanf("%[^\n]", password); // Fix 2
printf("\n");
attempts++;
} while (strcmp(password, "awesome 123 ok"));
printf("You entered a correct password in %d attempts!", attempts);
return 0;
}
发件人:
在尝试分析输入之前,[、c和n以外的所有转换说明符都会使用并丢弃所有前导空格字符
这意味着在循环中对scanf
的下一次调用中将包括尾随的换行符(一个空白字符)
解决方案很简单:告诉scanf
读取并丢弃前导空格:
scanf(" %[^\n]", password);
/* ^ */
/* | */
/* Note leading space */
还要注意的是,我删除了格式中的尾随s
,因为这告诉scanf
在输入中预期一个文本s
您可能还希望限制读取的字符数,以免读取到的缓冲区溢出:
scanf(" %9[^\n]", password);
请注意,上述格式将最大字段宽度设置为九个字符,因为缓冲区还需要包含终止的'\0'
字符。如果增加缓冲区大小,请修改此数字,但请记住,它(最多)应比缓冲区大小小一个。From:
在尝试分析输入之前,[、c和n以外的所有转换说明符都会使用并丢弃所有前导空格字符
这意味着在循环中对scanf
的下一次调用中将包括尾随的换行符(一个空白字符)
解决方案很简单:告诉scanf
读取并丢弃前导空格:
scanf(" %[^\n]", password);
/* ^ */
/* | */
/* Note leading space */
还要注意的是,我删除了格式中的尾随s
,因为这告诉scanf
在输入中预期一个文本s
您可能还希望限制读取的字符数,以免读取到的缓冲区溢出:
scanf(" %9[^\n]", password);
请注意,上述格式将最大字段宽度设置为九个字符,因为缓冲区还需要包含终止的
'\0'
字符。如果增加缓冲区大小,请修改此数字,但请记住,它最多应比缓冲区大小小一个。将dec密码[10]更改为密码[20]将dec密码[10]更改为密码[20]添加getchar()
以使用\n
字符。在下面找到修改后的代码
int main (void)
{
int attempts = 0;
char password[10];
do
{
printf("Enter your password:\n");
scanf("%[^\n]s", password);
getchar (); // Fix1
printf("\n");
attempts++;
} while (strcmp(password, "awesome 123 ok"));
printf("You entered a correct password in %d attempts!", attempts);
return 0;
}
您的代码中未正确使用数组密码
。因此,请更改其逻辑。用户可以输入N个字符。因此,请将用户输入限制为有限字符,或使用动态内存分配添加getchar()
以使用\N
字符。请在下面找到修改后的代码
int main (void)
{
int attempts = 0;
char password[10];
do
{
printf("Enter your password:\n");
scanf("%[^\n]s", password);
getchar (); // Fix1
printf("\n");
attempts++;
} while (strcmp(password, "awesome 123 ok"));
printf("You entered a correct password in %d attempts!", attempts);
return 0;
}
数组
密码
未在代码中正确使用。因此,请更改其逻辑。用户可以输入N个字符。因此,将用户输入限制为有限字符或使用动态内存分配问题在于密码
太窄。因此,程序通常会写入数组末尾y、 导致
您可以通过将密码
加宽来解决此问题。但是,您的程序仍然会受到以下攻击:攻击者可以通过输入精心编制的长密码字符串来执行任意代码
要解决这个问题,您需要更改scanf()
格式说明符,以限制它在password
中可以存储的字符数
以下更改将修复这两个问题:
char password[32]; /* more space: 31 characters + NUL */
do {
...
scanf("%31[^\n]%*c", password); /* format specifier */
后者将确保您在
password
中读取的字符数永远不会超过31个;它还会在不存储换行符的情况下使用换行符。问题在于password
太窄。因此,程序通常会写入数组末尾,从而导致错误
您可以通过将密码
加宽来解决此问题。但是,您的程序仍然会受到以下攻击:攻击者可以通过输入精心编制的长密码字符串来执行任意代码
要解决这个问题,您需要更改scanf()
格式说明符,以限制它在password
中可以存储的字符数
以下更改将修复这两个问题:
char password[32]; /* more space: 31 characters + NUL */
do {
...
scanf("%31[^\n]%*c", password); /* format specifier */
后者将确保您在密码
;i中读取的字符不会超过31个