簡體   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