[英]checking if certain characters are in a string in C
嗨,我是新手 C 学习者,这是一个作业。
任务是编写一个更改用户密码的程序,并检查新的给定密码是否至少包含一个数字、一个字母和其中一个( @
、 #
、 $
、 %
)符号,其长度应在 6 到 20 之间.
我已经将 3 个变量描述为counter1
、 counter2
和counter3
来检查给定密码中是否至少有一个符号、一个数字和一个字母,如果其中一个是 0,则从用户那里扫描另一个密码。 这应该一直持续到输入的密码包含上述所有条款。
我的程序将检查给定密码中的数字、字母和符号,但是当输入第一个新密码时,无论是否包含所有条款,程序都会结束,这是我认为问题出在程序的一部分
int counter1 = 0, counter2 = 0, counter3 = 0;
char mypassword[20] = "A1$B2C";
char password[20];
char newpassword[50];
int check = 0;
do {
printf("Please enter your current password: ");
scanf("%s", password);
} while (strcmp(mypassword, password) != 0);
printf("Please enter your new password: ");
scanf("%s", newpassword);
for (int i = 0; i < strlen(newpassword); i++) {
if (isalpha(newpassword[i]) != 0) {
counter3 += 1;
}
else if (isdigit(newpassword[i]) != 0) {
counter2 += 1;
}
else if (newpassword[i] == '@' || '#' || '$' || '%') {
counter1 += 1;
}
}
while (check == 0) {
while (counter1 == 0 || counter2 == 0 || counter3 == 0) {
printf("Please enter you new password: ");
scanf("%s", newpassword);
}
if (strlen(newpassword) < 6 || strlen(newpassword) > 20) {
printf("Please enter you new password: ");
scanf("%s", newpassword);
}
else
check += 1;
}
特殊字符的测试不正确: if (newpassword[i] == '@' || '#' || '$' || '%')
将始终成功,因为将'#'
视为 boolean 为真。
你应该写:
int c = newpassword[i];
if (c == '@' || c == '#' || c == '$' || c == '%') {
counter1++;
}
您的代码中还有其他问题:
您没有为scanf()
传递最大字符数以读取password
:任何超过 19 个字节的输入字都会导致未定义的行为。
您不测试scanf()
失败:文件意外结束将导致未定义的行为,并可能导致无限循环。
您应该更明确地说明再次提示输入新密码的原因。
对于输入的每个新密码,计数器应重置为0
,并且它们的名称应该更有意义。
每次新尝试都必须再次尝试所有测试:使用带有单个scanf()
实例的for
循环来读取当前或新密码,执行测试并在所有测试成功时退出循环。 根据经验,避免do
/ while
循环,因为它们往往会导致混乱和冗余代码。
这是修改后的版本:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int get_new_password(char *output, // destination array, longer than max_length
int min_length, // minimum password length
int max_length, // maximum password length
const char *special_chars, // set of special chars if any required
const char *current_pwd) // current password if any
{
char password[50];
char newpassword[50];
int has_letter, has_digit, has_special, len, c;
if (current_pwd != NULL && *current_pwd != '\0') {
for (;;) {
printf("Please enter your current password: ");
if (scanf("%49s", password) != 1)
return -1;
if (strcmp(current_pwd, password) != 0) {
printf("Invalid password. Try again.\n");
continue;
}
break; // current password is correct.
}
}
for (;;) {
printf("Please enter your new password: ");
if (scanf("%49s", newpassword) != 1)
return -1;
len = strlen(newpassword);
if (len < min_length) {
printf("The password must have at least %d characters.\n", min_length);
continue;
}
if (len > max_length) {
printf("The password must have at most %d characters.\n", max_length);
continue;
}
has_letter = has_digit = has_special = 0;
for (int i = 0; i < len; i++) {
c = newpassword[i];
if (isalpha((unsigned char)c)) {
has_letter = 1;
} else
if (isdigit((unsigned char)c)) {
has_digit = 1;
} else
if (special_chars && strchr(special_chars, c) != NULL) {
has_special = 1;
}
}
if (has_letter == 0) {
printf("The password must have at least one letter.\n");
continue;
}
if (has_digit == 0) {
printf("The password must have at least one digit.\n");
continue;
}
if (special_chars != NULL && has_special == 0) {
printf("The password must have at least one of %s\n", special_chars);
continue;
}
break; // new password passed all tests
}
strcpy(output, newpassword);
return 0;
}
int main() {
char mypassword[] = "A1$B2C";
char newpassword[21];
if (get_new_password(newpassword, 6, 20, "@#$%", mypassword)) {
printf("Invalid input, aborted.\n");
return 1;
} else {
printf("New password: %s\n", newpassword);
return 0;
}
}
我建议您将验证分解为单独的 function,使代码更具可读性。 下面是一个建议,它还可以让您轻松打印出在密码无效的情况下哪些验证标准失败。
#define VALIDATE_OK 0
#define VALIDATE_TOO_SHORT (1 << 0)
#define VALIDATE_TOO_LONG (1 << 1)
#define VALIDATE_LETTER (1 << 2)
#define VALIDATE_DIGIT (1 << 3)
#define VALIDATE_SPECIAL_CHAR (1 << 4)
#define MIN_LENGTH 6
#define MAX_LENGTH 20
static int validate(const char *str) {
const char special_chars[] = { '@', '#', '$', '%' };
size_t len = strlen(str);
int ret = VALIDATE_TOO_SHORT|VALIDATE_TOO_LONG|VALIDATE_LETTER|
VALIDATE_DIGIT|VALIDATE_SPECIAL_CHAR;
if (len >= MIN_LENGTH) ret &= ~VALIDATE_TOO_SHORT;
if (len <= MAX_LENGTH) ret &= ~VALIDATE_TOO_LONG;
for (size_t i = 0; i < len; i++) {
if (isalpha((unsigned char)str[i])) {
ret &= ~VALIDATE_LETTER;
continue;
}
if (isdigit((unsigned char)str[i])) {
ret &= ~VALIDATE_DIGIT;
continue;
}
for (size_t j = 0; j < sizeof special_chars; j++) {
if (str[i] == special_chars[j]) {
ret &= ~VALIDATE_SPECIAL_CHAR;
break;
}
}
}
return ret;
}
编辑:现在正确返回所有缺失的条件。
使用 strchr ( https://www.cplusplus.com/reference/cstring/strchr/ )。 如果未找到 char,则返回 null 指针。
编辑:另一个解决方案是使用 for 循环:
size_t len=strlen(newpassword);
if(len<3||len>20){
//Invalid length
}
int hasDigit=0;
int hasSpecial=0;
int hasLetter=0;
for(size_t i=0;i<len;i++) {
char c=newpassword[i];
if(isdigit(c)){
hasDigit=1;
}else if(c=='@'||c=='#'||c=='$'||c=='%'){
hasSpecial=1;
}else{
hasLetter=1;
}
...
}
if(hasDigit&&hasSpecial&&hasLetter){
//Valid password
}
编辑2:
if (isalpha(newpassword[i]) != 0){
counter3 += 1;
}
我认为这不应该存在,而只是在 else 子句中:
else{
counter3 += 1;
}
(这对于评论来说太长了)让我们从头开始:
while(check == 0)
-Loopwhile(counter1 == 0 || counter2 == 0 || counter3 == 0)
循环,这些将是无止境的,因为不可能改变计数器变量之一。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.