[英]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.