проверка наличия определенных символов в строке в C - PullRequest
1 голос
/ 12 июля 2020

Привет, я новичок ie 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;
}

Ответы [ 3 ]

2 голосов
/ 12 июля 2020

Тест на специальные символы неверен: if (newpassword[i] == '@' || '#' || '$' || '%') всегда будет успешным, потому что '#', принятое как логическое, является истинным.

Вместо этого вы должны написать:

int c = newpassword[i];
if (c == '@' || c == '#' || c == '$' || c == '%') {
    counter1++;
}

Есть другие проблемы в вашем коде:

  • вы не передаете максимальное количество символов для scanf() для чтения в password: любое входное слово длиннее 19 байтов вызовет неопределенное поведение.

  • вы не проверяете scanf() сбой: неожиданный конец файла приведет к неопределенному поведению и, вероятно, к бесконечному l oop.

  • вам следует более четко указать причину повторного запроса нового пароля.

  • счетчики должны быть сброшены на 0 для каждого нового введенного пароля, и их имена должны быть более значимыми .

  • все тесты должны повторяться для каждой новой попытки: используйте for l oop с одним экземпляром scanf(), чтобы прочитать текущий или новый пароль, выполните тесты и выйти из l oop, если все te sts удачно. Как правило, избегайте циклов 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;
    }
}
1 голос
/ 12 июля 2020

Я предлагаю вам выделить вашу валидацию в отдельную функцию, чтобы сделать код более читабельным. Ниже приведено предложение, которое также позволяет легко распечатать, какие критерии проверки не работают в случае неверного пароля.

#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;
}

EDIT: теперь правильно возвращает все отсутствующие критерии.

1 голос
/ 12 июля 2020

Используйте strchr (https://www.cplusplus.com/reference/cstring/strchr/). Если символ не был найден, он возвращает нулевой указатель.

Изменить: другим решением было бы использовать для l oop:

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 Если это ди git, прибавьте 1 к счетчику 2 3.2 Если это специальный символ, добавьте 1 к счетчику 1 3.3 Здесь вы должны просто добавить 1 к counter1. 4. После этого вы вводите while(check == 0) -L oop 4.1. Вы вводите while(counter1 == 0 || counter2 == 0 || counter3 == 0) l oop, они будут бесконечными, так как невозможно изменить одну из переменных счетчика. 4.2 Все остальное - мертвый код, потому что к нему нельзя получить доступ.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...