วนกลับไปที่การตรวจสอบอินพุตของผู้ใช้ C

ฉันมีวิธีต่อไปนี้เพื่อสร้างสตริงที่ต้องเป็นไปตามข้อกำหนด แต่ฉันต้องการส่วนคำสั่งบางประเภทเพื่อวนกลับไปยังอินพุตของผู้ใช้หากไม่เป็นไปตามข้อกำหนดการตรวจสอบ ฉันรู้ว่าใน Java มีการอ่านในภายหลัง แต่ฉันไม่ แน่ใจว่ารหัสที่ต้องการใน C คืออะไร ฉันไม่คิดว่าอย่างอื่นถ้าคำสั่งมีไวยากรณ์ที่ถูกต้องหากใครก็ตามสามารถตรวจพบข้อผิดพลาด เคล็ดลับหรือคำแนะนำบางอย่างอาจเป็นประโยชน์ ขอบคุณ

void validatePass()
{
    FILE *fptr;
    char password[MAX+1];
    int iChar,iUpper,iLower,iSymbol,iNumber,iTotal,iResult,iCount;

    //shows user password guidelines
    printf("\n\n\t\tPassword rules: ");
    printf("\n\n\t\t 1. Passwords must be at least 9 characters long and less than 15 characters. ");
    printf("\n\n\t\t 2. Passwords must have at least 2 numbers in them.");
    printf("\n\n\t\t 3. Passwords must have at least 2 uppercase letters and 2 lowercase letters in them.");
    printf("\n\n\t\t 4. Passwords must have at least 1 symbol in them (eg ?, $, £, %).");
    printf("\n\n\t\t 5. Passwords may not have small, common words in them eg hat, pow or ate.");

    //gets user password input
    printf("\n\n\t\tEnter your password following password rules: ");
    scanf("%s", &password);


    iChar = countLetters(password,&iUpper,&iLower,&iSymbol,&iNumber,&iTotal);

    if(iUpper < 2)
    {
        printf("Not enough uppercase letters!!!\n");


    }
    else if(iLower < 2)
    {
        printf("Not enough lowercase letters!!!\n");


    }
    else if(iSymbol < 1)
    {
        printf("Not enough symbols!!!\n");


    }
    else if(iNumber < 2)
    {
        printf("Not enough numbers!!!\n");


    }
    else if(iTotal < 9 && iTotal > 15)
    {
        printf("Not enough characters!!!\n");


    }

    iResult = checkWordInFile("dictionary.txt",password);

    if( iResult == gC_FOUND )
    {
        printf("\nFound your word in the dictionary");
    }
    else if
    {
        printf("\nCould not find your word in the dictionary");
    }

    iResult = checkWordInFile("passHistory.txt",password);
    else if( iResult == gC_FOUND )
    {
        printf("\nPassword used");
    }
    else if
    {
        printf("\nOk to use!");
    }
    else
    {
    printf("\n\n\n Your new password is verified ");
    printf(password);
    }
    //writing password to passHistroy file.


    fptr = fopen("passHistory.txt", "w");   // create or open the file
    for( iCount = 0; iCount < 8; iCount++)
    {
        fprintf(fptr, "%s\n", password[iCount]);
    }

    fclose(fptr);

    printf("\n\n\n");
    system("pause");


}//end validatePass method

person Brian J    schedule 22.11.2012    source แหล่งที่มา


คำตอบ (2)


ดูเหมือนกรณีของ do {...} while(...) loop "else" ที่คุณกำลังมองหาอยู่หลังการค้นหาพจนานุกรมเท่านั้น

แก้ไข: มันจะทำงานเช่นนี้:

do {
  /* read password here */
  ...
  if (condition not met) {
    printf("condition not met!\n");
    continue;
  }
  if (another condition not met) {
    printf("another condition not met!\n");
    continue;
  }
  ...
} while(0);

แก้ไข 2: อาจเป็นความคิดที่ดีที่จะทำการทดสอบในฟังก์ชันอื่นเช่นนี้:

bool password_is_safe(char *password)
{
  ...
  if (condition not met) {
    printf("condition not met!\n");
    return false;
  }
  if (another condition not met) {
    printf("another condition not met!\n");
    return false;
  }
  ...
  return true;      
}

  /* in another function */
  ...
  do {
    ...
    /* read password here */
    ...
  } while(!password_is_safe(password));

ช่วยให้เข้าใจตรรกะของโปรแกรมได้ง่ายขึ้นมากโดยไม่ต้องเลื่อนขึ้นและลง

แก้ไข 3:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define STRINGIFY(x) #x
#define STRINGIFY_VALUE(x) STRINGIFY(x)

#define MAX 80

static bool test_and_complain(const bool test, const char *complain)
{
    if (test) {
        printf("%s\n", complain);
    }
    return test;
}

static void write_history(const char *password)
{
    FILE *f = fopen("passHistory.txt", "w");
    // always check if fopen() was successful
    if (!f) {
        fprintf(stderr, "can't write password history\n");
        exit(EXIT_FAILURE);
    }
    fprintf(f, "%s\n", password);
    fclose(f);
}

void validatePass()
{
    char password[MAX+1];
    int iUpper,iLower,iSymbol,iNumber,iTotal;

    //shows user password guidelines
    printf("\n\n\t\tPassword rules: ");
    printf("1. Passwords must be at least 9 characters long and less than 15 characters.");
    printf("2. Passwords must have at least 2 numbers in them.");
    printf("3. Passwords must have at least 2 uppercase letters and 2 lowercase letters in them.");
    printf("4. Passwords must have at least 1 symbol in them (eg ?, $, £, %%).");
    printf("5. Passwords may not have small, common words in them eg hat, pow or ate.");

    // loop until we got a good password
    bool pw_invalid;
    do {
        //gets user password input
        printf("Enter your password following password rules: ");
        // Security risc:
        // Never ever use "%s" without specifying a length!
        // scanf("%s", password);
        scanf("%" STRINGIFY_VALUE(MAX) "s", password);

        countLetters(password,&iUpper,&iLower,&iSymbol,&iNumber,&iTotal);

        // Notice that you could eliminate the boolean variable and
        // wrap all the tests in a single expression and put
        // that inside the loop condition of the loop.
        // I think it looks nicer this way though.
        // Notice that the || operator does not evaluate the right hand
        // expression if the left hand expression evaluates to true.
        // I.e. after the first test fails, no other tests are performed.
        // This is equivalent to the if-else cascade from before.
        pw_invalid = false;
        pw_invalid = pw_invalid || test_and_complain(
                      (iUpper < 2),
                      "Not enough uppercase letters!!!");
        pw_invalid = pw_invalid || test_and_complain(
                      (iLower < 2),
                      "Not enough lowercase letters!!!");
        pw_invalid = pw_invalid || test_and_complain(
                      (iSymbol < 1),
                      "Not enough symbols!!!");
        pw_invalid = pw_invalid || test_and_complain(
                      (iNumber < 2),
                      "Not enough numbers!!!") ;
        pw_invalid = pw_invalid || test_and_complain(
                      (iTotal < 9),
                      "Not enough characters!!!");
        pw_invalid = pw_invalid || test_and_complain(
                      (checkWordInFile("dictionary.txt",password)==gC_FOUND),
                      "Found your word in the dictionary");
        pw_invalid = pw_invalid || test_and_complain(
                      (checkWordInFile("passHistory.txt",password)==gC_FOUND),
                      "You already used this password recently");
    } while(pw_invalid);

    printf("\nYour new password is verified\n");
    // Security risc:
    // Never ever use a user supplied string as a format string!
    // printf(password);
    printf("%s\n", password);

    //writing password to passHistroy file.
    write_history(password);

    printf("\n\n\n");
    system("pause");
} //end validatePass method

หากนี่คือการบ้าน โปรดตรวจสอบเกรดของคุณอีกครั้ง ;-)

person Mackie Messer    schedule 22.11.2012
comment
ฉันจะใช้ do.. While วนซ้ำในโค้ดของฉันได้อย่างไร เนื่องจากฉันไม่แน่ใจในสถานการณ์นี้ ขอบคุณ - person Brian J; 23.11.2012

ใช้ข้ามไป เป็นหนึ่งในไม่กี่กรณีที่ได้รับการรับประกัน

นี่คือตัวอย่าง อย่างที่คุณเห็น มันสะอาดกว่า while(0) มาก และจะทำให้คอมไพเลอร์บ่นน้อยลงด้วย -Wall เช่นกัน!

// Returns whether or not the condition failed, printing the
// given error if it did.
static bool verifyThat(bool condition, const char* error) {
    if(!condition) printf("%s", error);
    return !condition;
}

void validatePass()
{
    FILE *fptr;
    char password[MAX+1];
    int iChar,iUpper,iLower,iSymbol,iNumber,iTotal,iResult,iCount;

    //shows user password guidelines
    printf("\n\n\t\tPassword rules: ");
    printf("\n\n\t\t 1. Passwords must be at least 9 characters long and less than 15 characters. ");
    printf("\n\n\t\t 2. Passwords must have at least 2 numbers in them.");
    printf("\n\n\t\t 3. Passwords must have at least 2 uppercase letters and 2 lowercase letters in them.");
    printf("\n\n\t\t 4. Passwords must have at least 1 symbol in them (eg ?, $, £, %).");
    printf("\n\n\t\t 5. Passwords may not have small, common words in them eg hat, pow or ate.");

    get_user_password:

    printf("\n\n\t\tEnter your password following password rules: ");
    scanf("%s", &password);

    iChar = countLetters(password,&iUpper,&iLower,&iSymbol,&iNumber,&iTotal);
    iUpper = ...
    iLower = ...
    iSymbol = ...
    iNumber = ...
    iTotal = ...

    if(verifyThat(iUpper >= 2, "Not enough uppercase letters!!!\n")
          || verifyThat(iLower >= 2, "Not enough lowercase letters!!!\n")
          || verifyThat(iSymbol >= 1, "Not enough symbols!!!\n")
          || verifyThat(iNumber >= 2, "Not enough numbers!!!\n")
          || verifyThat(iTotal >= 9, "Not enough characters!!!\n")
          || verifyThat(iTotal <= 15, "Too many characters!!!\n"))
        goto get_user_password;

    iResult = checkWordInFile("dictionary.txt", password);

    if(verifyThat(iResult != gC_FOUND, "Password used."))
        goto get_user_password;

        printf("Your new password is verified.");
}
person Clark Gaebel    schedule 22.11.2012
comment
ฉันไม่เคยใช้ goto มาก่อน นี่หมายถึงการใส่ goto หลังข้อความแสดงข้อผิดพลาดในการตรวจสอบความถูกต้องแต่ละครั้งหรือไม่ - person Brian J; 23.11.2012
comment
การใช้ตัวดำเนินการ && ที่นี่เป็นคำแนะนำที่ดีมาก แต่การใช้ goto ไม่ใช่ โดยพื้นฐานแล้วนี่คือการวนซ้ำ ดังนั้นการใช้คำสั่งวนซ้ำจึงเป็นวิธีแสดงความตั้งใจนี้ต่อผู้ที่อ่านโค้ดของคุณ มีหลายกรณีที่จำเป็นต้องระบุ goto แต่นี่ไม่ใช่กรณีใดกรณีหนึ่ง - person Mackie Messer; 23.11.2012
comment
กรุณาใช้โค้ดที่มีการวนซ้ำในคำตอบของคุณ จากนั้นให้ OP ตัดสินใจว่าอันไหนชัดเจนกว่า ฉันลองใช้การตรวจสอบประเภทนี้ด้วยการวนซ้ำเมื่อหลายปีก่อน และมันก็ดูไม่ชัดเจนนัก - โดยเฉพาะเมื่อเปรียบเทียบกับโซลูชัน goto ที่หรูหรา หากคุณสามารถเข้าใจได้ฉันก็อยากเห็นมัน! - person Clark Gaebel; 23.11.2012