繁体   English   中英

检查某些字符是否在 C 的字符串中

[英]checking if certain characters are in a string in C

嗨,我是新手 C 学习者,这是一个作业。

任务是编写一个更改用户密码的程序,并检查新的给定密码是否至少包含一个数字、一个字母和其中一个( @#$% )符号,其长度应在 6 到 20 之间.

我已经将 3 个变量描述为counter1counter2counter3来检查给定密码中是否至少有一个符号、一个数字和一个字母,如果其中一个是 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;
}

(这对于评论来说太长了)让我们从头开始:

  1. 您向用户询问当前密码。 1.1 重复,如果是错误的。
  2. 你要新的。
  3. 你 go 关于新密码中的每个字符。
    3.1 如果是数字,计数器2加1
    3.2 如果是特殊字符,计数器1加1
    3.3 这里你应该简单地给 counter1 加 1。
    4.之后你进入while(check == 0) -Loop
    4.1 您进入while(counter1 == 0 || counter2 == 0 || counter3 == 0)循环,这些将是无止境的,因为不可能改变计数器变量之一。
    4.2 其他都是死代码,因为无法访问。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM