当你试图登录某个系统却忘了密码时,系统一般只会允许你尝试有限多次,当超出允许次数时,账号就会被锁死。本题就请你实现这个小功能。

输入格式:

输入在第一行给出一个密码(长度不超过 20 的、不包含空格、Tab、回车的非空字符串)和一个正整数 N(≤ 10),分别是正确的密码和系统允许尝试的次数。随后每行给出一个以回车结束的非空字符串,是用户尝试输入的密码。输入保证至少有一次尝试。当读到一行只有单个 # 字符时,输入结束,并且这一行不是用户的输入。

输出格式:

对用户的每个输入,如果是正确的密码且尝试次数不超过 N,则在一行中输出 Welcome in,并结束程序;如果是错误的,则在一行中按格式输出 Wrong password: 用户输入的错误密码;当错误尝试达到 N 次时,再输出一行 Account locked,并结束程序。

输入样例 1:

  1. Correct%pw 3
  2. correct%pw
  3. Correct@PW
  4. whatisthepassword!
  5. Correct%pw
  6. #

输出样例 1:

  1. Wrong password: correct%pw
  2. Wrong password: Correct@PW
  3. Wrong password: whatisthepassword!
  4. Account locked

输入样例 2:

  1. cool@gplt 3
  2. coolman@gplt
  3. coollady@gplt
  4. cool@gplt
  5. try again
  6. #

输出样例 2:

  1. Wrong password: coolman@gplt
  2. Wrong password: coollady@gplt
  3. Welcome in

思路

第一次写的时候,我在读取密码时用的是

  1. char input[1001];
  2. scanf("%s", input);

后面提交到平台测试点2和测试点5是过不去的。

我才想起来,用户输入密码的时候,“空格”可是是组成密码的一部分,但是

  1. scanf("%s");

代码却是是 whitespce(换行符、空格、tab) 来作为分割的。

如果用户输入的密码包括了“空格”,那在输出

  1. Wrong password: 用户输入的错误密码

的时候肯定是错的。

查阅资料后,这道题可以改进scanf()函数读取数字的方式,即使用 扫描集(scan set)


扫描集(scan set)

Example1

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. char scanset[128];
  5. char input[128];
  6. printf("Enter a string: ");
  7. scanf("%[A-Z]s", str); /* This is a scanset format */
  8. scanf("%s", input);
  9. printf("scanset: %s\n", str);
  10. printf("input: %s\n", input);
  11. return 0;
  12. }

输入:

  1. GEeKS_For_GeeKs

输出是:

  1. scanset: GE
  2. input: eKS_For_GeeKs

结论1

由此观之,扫描集会读取到一个不符合指定集合的元素位置为止,在输入缓冲区中仍包含着这个不符合规定的元素,在下一个输入语句中被一起读进新的字符数组。


Example2

If first character of scanset is ‘^’, then the specifier will stop reading after first occurrence of that character. For example, given below scanset will read all characters but stops after first occurrence of ‘o’

  1. scanf("%[^o]s", input);

测试代码如下:

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. char scanset[128];
  5. char input[128];
  6. printf("Enter a string: ");
  7. scanf("%[^o]s", scanset);
  8. scanf("%s", input);
  9. printf("scanset: %s\n", scanset);
  10. printf("input: %s\n", input);
  11. return 0;
  12. }

输入:

  1. http://geeks for___Geeks

输出:

  1. scanset: http://geeks f
  2. input: or___Geeks

结论2

反义特性^十分有用。

我们可以利用这个特性来完成对一整行字符的读取,即实现gets()函数的功能(PAT平台不允许使用gets()函数)。

即:

  1. scanf("%[^\n]s", input);

由此我们可以得到本题的AC参考代码

代码

  1. #include<stdio.h>
  2. #include<string.h>
  3. int main() {
  4. int tryTimes;
  5. char correctPasswd[21] = {'\0'};
  6. scanf("%s%d", correctPasswd, &tryTimes);
  7. for(int i = 0; i < tryTimes; i++) {
  8. char input[1001] = {'\0'};
  9. getchar(); /* Absort the '\n' */
  10. scanf("%[^\n]s", input);
  11. if(strcmp(input, "#") == 0) {
  12. return 0;
  13. }
  14. if(strcmp(input, correctPasswd) == 0) {
  15. printf("Welcome in\n");
  16. return 0;
  17. }
  18. else {
  19. printf("Wrong password: %s\n", input);
  20. }
  21. }
  22. printf("Account locked\n");
  23. return 0;
  24. }