为什么我必须两次点击“Enter”?

时间:2016-02-22 21:36:31

标签: c validation

我已经做了好几天了,终于让它像我想要的那样验证,一切正常。但是当我运行这个并且输入名字然后点击“Enter”时,控制台就会跳过一条线。当我第二次点击“Enter”时,程序继续进入下一个问题。任何想法为什么会这样?任何建议表示赞赏!

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "person.h"

// Program Contstants
#define INTEREST    .03         // Annual Interest Rate
#define CHAR_LEN    40          // Maximum Character Length
#define MAX_CUST    2           // Maximum Amount of Customers
#define MIN_PRIN    1000        // Minimum Principal Balance
#define MAX_PRIN    1000000     // Maximum Principal Balance
#define MIN_TERM    5           // Minimum Loan Term (Years)
#define MAX_TERM    30          // Maximum Loan Term (Years)

// Program Variables
struct person *customer = NULL;         // Pointer to the "person" Structure
FILE *ifp;                              // File Pointer
int num_cust = 0;

// Function Prototypes
void addCustomer();                         // Function to Add a Customer
struct person *findCustomer(int custID);    // Function to Find a Customer
void printCustomer();                       // Function to Print a Customer
float calcMonthlyPayment(float, int);       // Function to Calculate monthlyPayment
float calcActualPayment(int, float);        // Function to Calculate actualPayment
void flushLine();                           // Function to Clear "scanf" Input

int main(void)
{
    char input;             // Local Variable to Hold User's Choice

    ifp = fopen("Customers.txt", "w");      // Opens/Creates the File to be Written - Overwrites Existing File

    for(;;)                 // Infinite "FOR" Loop to Run the Program
    {
        // Print Statements to Display the Menu
        printf("\n\nChoose From the Options Below:\n");
        printf("Type 'N' to Add a New Customer\n");
        printf("Type 'P' to Print a Customer's Information\n");
        printf("Type 'Q' to Quit the Program\n\n");
        scanf(" %c", &input);           // Scans User Input and Assigns to "input" Variable
        flushLine();                    // Calls the "flushLine" Function to Clear the "scanf"

        switch(toupper(input))          // Switch Statement to Control Function Calls. Converts input to Upper Case
        {
            case 'N':                                           // If the User Chose "N"
                ifp = fopen("Customers.txt", "a");              // Appends Data to the Open File
                addCustomer();                                  // Calls the "addCustomer()" Function
                break;                                          // Break Statement to Exit the Switch Statement
            case 'P':                                           // If the User Chose "P"
                printCustomer();                                // Calls the "printCustomer()" Function
                break;                                          // Break Statement to Exit the Switch Statement
            case 'Q':                                           // If the User Chose "Q"
                exit(0);                                        // Exits the Program
            default:                                            // If the User Chose Anything Else
                printf("Invalid Entry. Please Reenter.\n");     // Prints an Error Message
                break;                                          // Break Statement to Exit the Switch Statement
        }
    }
}

void addCustomer()
{
    struct person *cur, *prev, *new_node;                       // Defines Pointers for the "person" Structure

    new_node = malloc(sizeof(struct person));                   // Allocates Space For a New Customer and Assigns it to the "new_node" Variable

    if((new_node == NULL) || (num_cust == MAX_CUST))                    // If the "new_node" Variable is Empty
    {
        printf("The Database is Full. You Cannot Add a New Customer.");     // Alerts the User that there is No Room
        return;                             // Return Statement
    }

    printf("\nEnter the Customer ID: ");    // Prompts the User to Enter a Customer ID
    scanf("%d", &new_node->custID);         // Scans User Input and Assigns it to the "custID" field for the New Customer
    flushLine();                            // Calls the "flushLine" Function to Clear the "scanf"

    while((new_node->custID <= 0) || (new_node->custID > MAX_CUST))     // Validates the Customer ID is Numeric and Between 0 - 100
    {
        printf("\nInvalid Entry. The Customer ID must be Numeric and Below %d.\n", MAX_CUST);   // Prints an Error Message
        printf("Enter the Customer ID: ");                          // Prompts the User to Reenter the Customer ID
        scanf("%d", &new_node->custID);                     // Scans User Input and Assigns it to the "custID" field for the New Customer
        flushLine();                        // Calls the "flushLine" Function to Clear the "scanf"
    }

    for(cur = customer, prev = NULL; cur != NULL && new_node->custID > cur->custID; prev = cur, cur = cur->next)
    {
        continue;
    }       

    if(cur != NULL && new_node->custID == cur->custID)          // Tests Whether or Not the Customer ID is a Duplicate
    {
        printf("This Customer ID Already Exists.\n");           // Prints an Error Message
        free(new_node);                                         // Releases the Reserved Memory
        return;                                                 // Return Statement
    }

    fprintf(ifp, "%s", "Customer ID:\t\t");                     // Prints the Customer ID Heading to File
    fprintf(ifp, "%d", new_node->custID);                       // Prints the Customer ID to File

    printf("\nEnter Customer's First Name: ");                  // Prompts the User for the Customer's First Name
    fgets(new_node->fName, 41, stdin);                          // Gets Input and Assigns it to the "fName" Variable


    while(strlen(new_node->fName) == 0)
    {
        printf("\nYou Cannot Leave this Field Blank.");
        printf("\nEnter the Customer's First Name: ");
        gets(new_node->fName);
    }   

    fprintf(ifp, "%s", "\nCustomer Name:\t\t");                 // Prints the Customer Name Heading to File
    fprintf(ifp, "%s", new_node->fName);                        // Prints the Customer's First Name to File
    flushLine();                                                // Calls the "flushLine" Function to Clear the "scanf"

    printf("\nEnter Customer's Last Name: ");                   // Prompts the User for the Customer's Last Name
    scanf("%40[^\n]s", new_node->lName);                            // Scans the Input and Assigns it to the "lName" Variable
    fprintf(ifp, "%s", " ");                                    // Prints a Space to File
    fprintf(ifp, "%s", new_node->lName);                        // Prints the Customer's Last Name to File
    flushLine();                                                // Calls the "flushLine" Function to Clear the "scanf"

    printf("\nEnter Customer's Street Address: ");              // Prompts the User for the Customer's Address
    scanf("%40[^\n]s", new_node->address);                      // Scans the Input and Assigns it to the "address" Variable
    fprintf(ifp, "%s", "\nCustomer Address:\t");                // Prints the Customer Address Heading to File
    fprintf(ifp, "%s", new_node->address);                      // Prints the Customer's Address to File
    flushLine();                                                // Calls the "flushLine" Function to Clear the "scanf"

    printf("\nEnter Customer's City: ");                        // Prompts the User for the Customer's City
    scanf("%40[^\n]s", new_node->city);                         // Scans the Input and Assigns it to the "city" Variable
    fprintf(ifp, "%s", "\n\t\t\t");                             // Prints Spacing to File
    fprintf(ifp, "%s", new_node->city);                         // Prints the Customer's City to File
    flushLine();                                                // Calls the "flushLine" Function to Clear the "scanf"

    printf("\nEnter Customer's 2-Digit State: ");               // Prompts the User for the Customer's State
    scanf("%2s", new_node->state);                              // Scans the Input and Assigns it to the "state" Variable
    fprintf(ifp, "%s", ", ");                                   // Prints Spacing to File
    fprintf(ifp, "%s", new_node->state);                        // Prints the Customer's State to File
    flushLine();                                                // Calls the "flushLine" Function to Clear the "scanf"

    printf("\nEnter Customer's 5-Digit Zip Code: ");            // Prompts the User for the Customer's Zip
    scanf("%5s", new_node->zip);                                // Scans the Input and Assigns it to the "zip" Variable
    fprintf(ifp, "%s", " ");                                    // Prints Spacing to File
    fprintf(ifp, "%s", new_node->zip);                          // Prints the Customer's Zip to File
    flushLine();                                                // Calls the "flushLine" Function to Clear the "scanf"

    printf("\nEnter the Customer's Principal: ");               // Prompts the User for the Customer's Principal
    scanf("%f", &new_node->principal);                          // Scans the Input and Assigns it to the "principal" Variable
    flushLine();                                                // Calls the "flushLine" Function to Clear the "scanf"

    // While Loop to Test for In-Range Principal Input
    while((new_node->principal < MIN_PRIN) || (new_node->principal > MAX_PRIN))
    {
        printf("Invalid Entry. The Customer's Principal must be Between %d and %d.\n", MIN_PRIN, MAX_PRIN);     // Prints an Error Message
        printf("\nEnter Customer's Principal: ");               // Prompts the User to Reenter the Principal
        scanf("%f", &new_node->principal);                      // Scans the Input and Assigns it to the "principal" Variable
        flushLine();                                            // Calls the "flushLine" Function to Clear the "scanf"
    }

    fprintf(ifp, "%s", "\nPrincipal:\t\t$");                    // Prints the Principal Heading to File
    fprintf(ifp, "%.2f", new_node->principal);                  // Prints the Customer's Principal to File

    printf("\nEnter the Customer's Loan Term (In Years): ");    // Prompts the User for the Customer's Loan Term
    scanf("%d", &new_node->yearlyTerm);                         // Scans the Input and Assigns it to the "yearlyTerm" Variable
    flushLine();                                                // Calls the "flushLine" Function to Clear the "scanf"

    // While Loop to Test for In-Range Yearly Term Input
    while((new_node->yearlyTerm < MIN_TERM) || (new_node->yearlyTerm > MAX_TERM))
    {
        printf("Invalid Entry. The Loan Term must be Between %d and %d.\n", MIN_TERM, MAX_TERM);                // Prints an Error Message
        printf("\nEnter the Customer's Loan Term (In Years): ");    // Prompts the User to Reenter the Yearly Term
        scanf("%d", &new_node->yearlyTerm);                     // Scans the Input and Assigns it to the "yearlyTerm" Variable
        flushLine();                                            // Calls the "flushLine" Function to Clear the "scanf"
    }

    fprintf(ifp, "%s", "\nYearly Term:\t\t");                   // Prints the Yearly Term Heading to File
    fprintf(ifp, "%d", new_node->yearlyTerm);                   // Prints the Customer's Yearly Term to File

    float payment = calcMonthlyPayment(new_node->principal, new_node->yearlyTerm);  // Calls the "calcMonthlyPayment()" Function and Assigns it to the "payment" Variable
    new_node->monthlyPayment = payment;                         // Assigns the "payment" Variable to the Customer's "monthlyPayment" Variable
    fprintf(ifp, "%s", " Years\nMonthly Payment:\t$");          // Prints the Monthly Payment Heading to File
    fprintf(ifp, "%.2f", new_node->monthlyPayment);             // Prints the Customer's Monthly Payment to File

    float actPayment = calcActualPayment(new_node->yearlyTerm, payment);    // Calls the "calcActualPayment()" Function and Assigns it to the "actPayment" Variable
    new_node->actualPayment = actPayment;                       // Assigns the "actPayment" Variable to the Customer's "actualPayment" Variable
    fprintf(ifp, "%s", "\nActual Payment:\t\t$");               // Prints the Actual Payment Heading to File
    fprintf(ifp, "%.2f", new_node->actualPayment);              // Prints the Customer's Actual Payment to File
    fprintf(ifp, "%s", "\n--------------------------------------------\n");     // Prints a Line Seperater to File

    fclose(ifp);                                                // Closes the .txt File

    new_node->next = cur;                                       

    if (prev == NULL)                                           
    {
        customer = new_node;                                    
    }

    else
    {
        prev->next = new_node;                                   
    }

    num_cust++;
}

struct person *findCustomer(int custID)
{
    struct person *p;

    for(p = customer; p != NULL && custID > p->custID; p = p->next)
    {
        continue;       // DO I NEED THIS? Works through structure
    }

    if (p != NULL && custID == p->custID)
    {
        return p;
    }

    else
    {
        return NULL;
    }
}

void printCustomer()
{
    int custID;
    struct person *p;

    printf("\nEnter Customer ID: ");
    scanf("%d", &custID);
    flushLine();                    // Calls the "flushLine" Function to Clear the "scanf"

    p = findCustomer(custID);

    if(p != NULL)
    {
        printf("\nCustomer ID:\t\t%d", p->custID);
        printf("\nCustomer Name:\t\t%s %s", p->fName, p->lName);
        printf("\nCustomer Address:\t%s", p->address);
        printf("\n\t\t\t%s, %s %s", p->city, p->state, p->zip);
        printf("\nCustomer Principal:\t$%.2f", p->principal);
        printf("\nCustomer Loan Term:\t%d Years", p->yearlyTerm);
        printf("\nMonthly Payment:\t$%.2f", p->monthlyPayment);     
        printf("\nActual Payment:\t\t$%.2f", p->actualPayment);
    }

    else
    {
        printf("The Customer ID Wasn't Found.\n");
    }
}

float calcMonthlyPayment(float principal, int yearlyTerm)
{
    int monthlyTerm = yearlyTerm * 12;
    float monthlyIR = INTEREST / 12;
    float payment = principal * monthlyIR * (pow(1 + monthlyIR, monthlyTerm) / (pow(1 + monthlyIR, monthlyTerm)-1));

    return payment;
}

float calcActualPayment(int yearlyTerm, float monthlyPayment)
{
    int monthlyTerm = yearlyTerm * 12;
    float actPayment = monthlyPayment * monthlyTerm;

    return actPayment;
}

void flushLine() 
{
    int c;

    while((c = getchar()) != EOF && c != '\n')
    {
        continue;
    }
}

Person.h

// Program Constants
#define CHAR_LEN    40

struct person 
{
    int custID;
    char fName[CHAR_LEN + 1];
    char lName[CHAR_LEN + 1];
    char address[CHAR_LEN + 1];
    char city[CHAR_LEN + 1];
    char state[3];
    char zip[6];
    float principal;
    int yearlyTerm; 
    float monthlyPayment;
    float actualPayment;    
    struct person *next;
};

1 个答案:

答案 0 :(得分:0)

你的姓氏代码非常接近。我将它复制为名字并进行了一些更改。

以下是addCustomer中的更改:

    // NOTE/BUG: original code
#if 0
    printf("\nEnter Customer's First Name: ");                  // Prompts the User for the Customer's First Name
    fgets(new_node->fName, 41, stdin);                          // Gets Input and Assigns it to the "fName" Variable

    while(strlen(new_node->fName) == 0)
    {
        printf("\nYou Cannot Leave this Field Blank.");
        printf("\nEnter the Customer's First Name: ");
        fgets(new_node->fName,sizeof(new_node->fName),stdin);
    }

    // NOTE/FIX: modified code
#else
    while (1) {
        printf("\nEnter Customer's first Name: ");                   // Prompts the User for the Customer's First Name
        scanf("%40[^\n]s", new_node->fName);                         // Scans the Input and Assigns it to the "fName" Variable
        if (strlen(new_node->fName) != 0)
            break;
        printf("\nYou Cannot Leave this Field Blank.");
        flushLine();                                                // Calls the "flushLine" Function to Clear the "scanf"
    }
#endif