简体   繁体   中英

Issue with substring search when using recursion

I have a program that simulates a bank. When I choose deposit amount, it asks me for searching a user by part of name.

Here, I type 'aar' and this outputs the user without any issue.

No issue here

Now, I start the program again and type 'ar'. This gives me all users that have 'ar' as my substring.

Again, no issue with this output

After this, when I type 'aar' in order to select my user, it again displays all the users that were in the previous photo.

The bug displayed here is an infinite loop

I am not sure where exactly I went wrong. I'm still learning C++ and appreciate your assistance. Here's the code for the program.

#include <iostream>
#include <iomanip>      //used for setw which is used for formatting cout output
#include <cctype>
using namespace std;

// This Function searches if we have a match or if we have reached the end of string
bool isMatch(char name[], char search_str[])
{
    int i = 0;
    int idx = 0;

    if (search_str[idx] == '\0')
    {
        return true;
    }
    
    if(name[i] == '\0' && search_str[idx] != '\0')
    {
        return false;
    }

    if (name[i] == search_str[idx])
    {
        return isMatch(name + 1, search_str + 1);
    }

    return false;
}

bool IsSubString(char name[], char search_str[])
{
    /*
    Searches the character array for the first occurrence of the sequence specified by its arguments.
    */
    int i = 0;
    int idx = 0;

    for (int i = 0; search_str[idx] != '\0'; i++)
    {
        if (isupper(search_str[idx]))
        {
            search_str[idx] += 32;
        }
    }

    if (name[i] == '\0')
    {
        return false;
    }

    if (name[i] == search_str[idx])
    {
        if (isMatch(name, search_str))
        {
            return true;
        }
    }
    else
    {
        return IsSubString(name + 1, search_str);
    }

    return IsSubString(name + 1, search_str);

}

int select_user(char cust_names[][100], int num_cust)
{
    /*
    Selects a user by searching for part of their name
    */
    char search_user[100];
    int cust_idx = 0;
    int count = 0;
    int selected_user_id;

    while (count != 1)
    {
        cout << "Search user by part of name: ";
        cin.ignore();
        cin.getline(search_user, 100);
        cust_idx = 0;
        count = 0;
        selected_user_id = -1;
        for (cust_idx = 0; cust_idx < num_cust; cust_idx++)
        {
            if (IsSubString(cust_names[cust_idx], search_user))
            {
                selected_user_id = cust_idx;
                cout << "User match: " << cust_names[cust_idx] << endl;
                count++;
            }
        }
        if (count > 1)
        {
            cout << endl << "More than one user found with that substring. Please search again with more characters ************************* " << endl;
        }
        else if (count == 0)
        {
            cout << endl << "No user found with that substring. Please search again *************************" << endl;
        }
    }
    return selected_user_id;
}

void withdraw_from_account(double acct_bal[], double loan_bal[], int account_id, double withdraw_amount)
{
    //withdraw the amount if account has enough balance
    //otherwise, if withdraw amount is more than account balance, charge an overdraft fee and add extra withdrawn amount to loan dues
    double overdraft_fee = 35;
    if (withdraw_amount < 0)
    {
        cout << "Error: Cannot withdraw a negative amount *************************" << endl << endl;
        return;
    }

    acct_bal[account_id] = acct_bal[account_id] - withdraw_amount;

    if (acct_bal[account_id] < 0)
    {
        cout << "Withdrawing amount larger than current account balance. Additional overdraft fee of $35 shall be charged. *************************" << endl << endl;
        loan_bal[account_id] = -acct_bal[account_id] + overdraft_fee;
        acct_bal[account_id] = 0;
    }
}

void deposit_to_account(double acct_bal[], double loan_bal[], int account_id, double deposit_amount)
{
    //deposit the amount if account has no loans
    //otherwise, if deposit amount is more than outstanding loan, add extra amount to account balance
    if (deposit_amount < 0)
    {
        cout << "Error: Cannot deposit a negative amount *************************" << endl << endl;
        return;
    }
    if (loan_bal[account_id] == 0.0)
    {
        acct_bal[account_id] += deposit_amount;
    }
    else
    {
        loan_bal[account_id] -= deposit_amount;
        if (loan_bal[account_id] < 0)
        {
            acct_bal[account_id] = -loan_bal[account_id];
            loan_bal[account_id] = 0;
        }
    }
}

void print_account_details(char cust_names[][100], double acct_bal[], double loan_bal[], int num_cust)
{
    /*
    Prints account statements for all users
    */
    if (num_cust == 0)
    {
        //print header
        cout << "--------------------------------------------------------------------" << endl;
        cout << "\t\t\t ACCOUNT DETAILS " << endl;
        cout << "--------------------------------------------------------------------" << endl;
        cout << "CUSTOMER NAME -> ACCOUNT BALANCE -> LOAN DUE" << endl;
        cout << "--------------------------------------------------------------------" << endl;
        return;
    }

    print_account_details(cust_names, acct_bal, loan_bal, num_cust - 1);
    int print_idx = num_cust - 1;
    cout << std::left << setw(40) << cust_names[print_idx] << " $" << setw(20) << acct_bal[print_idx] << "$" << setw(20) << loan_bal[print_idx] << endl;
}


int print_menu()
{
    /*
    Prints the menu
    */
    int menu_select = -1;

    while (menu_select < 0 || menu_select > 3)
    {
        cout << "--------------------------------------------------------------------" << endl;
        cout << "\t\t MENU" << endl;
        cout << "--------------------------------------------------------------------" << endl;
        cout << "1: Show Account Details" << endl;
        cout << "2: Deposit amount to account" << endl;
        cout << "3: Withdraw amount from account" << endl;
        cout << "0: Exit" << endl;
        cout << "--------------------------------------------------------------------" << endl;
        cout << "Select menu option [1, 2, 3, 0] : ";
        cin >> menu_select;
        cout << "--------------------------------------------------------------------" << endl;
        if (menu_select < 0 || menu_select > 3)
            cout << "Error: Incorrect menu item selected. Please select again *************************" << endl << endl;
    }

    return menu_select;
}



int main()
{
    const int num_customers = 5;
    char customer_names[num_customers][100] = {
        "john fitzgerald kennedy",
        "william shakespeare",
        "salvador felipe jacinto dali domenech",
        "elvis aaron presley",
        "elizabeth alexandra mary windsor" };


    double customer_account_balances[num_customers] = { 100.5, 120.75, 50.2, 150.15, 200.99 };
    double customer_loan_dues[num_customers] = { 0.0, 0.0, 0.0, 0.0, 0.0 };


    cout << "************************* Welcome to BANK OF ANTARCTICA *************************" << endl << endl << endl;



    print_account_details(customer_names, customer_account_balances, customer_loan_dues, num_customers);
    cout << endl << endl << endl;
    double amount;
    int acct_id;
    int menu_select = -1;
    while (menu_select != 0)
    {
        menu_select = print_menu();
        switch (menu_select)
        {
        case 1:     // Show Account Details
            print_account_details(customer_names, customer_account_balances, customer_loan_dues, num_customers);
            cout << endl << endl << endl;
            break;
        case 2:     // Deposit amount to account
            acct_id = select_user(customer_names, num_customers);
            cout << "Please enter amount to DEPOSIT into the account of: " << customer_names[acct_id] << " :: $";

            cin >> amount;
            deposit_to_account(customer_account_balances, customer_loan_dues, acct_id, amount);
            print_account_details(customer_names, customer_account_balances, customer_loan_dues, num_customers);
            cout << endl << endl << endl;
            break;
        case 3:     // Withdraw amount from account
            acct_id = select_user(customer_names, num_customers);
            cout << "Please enter amount to WITHDRAW from the account of: " << customer_names[acct_id] << " :: $";

            cin >> amount;
            withdraw_from_account(customer_account_balances, customer_loan_dues, acct_id, amount);
            print_account_details(customer_names, customer_account_balances, customer_loan_dues, num_customers);
            cout << endl << endl << endl;
            break;
        }
    }


    cout << endl << endl << "Final Details:" << endl;
    print_account_details(customer_names, customer_account_balances, customer_loan_dues, num_customers);
    cout << endl << endl << endl;

    cout << "THANK YOU!!! for using BANK OF ANTARCTICA services" << endl;

    return 0;
}

Take a close look at this loop:

int i = 0;
int idx = 0;

for (int i = 0; search_str[idx] != '\0'; i++)
{
    if (isupper(search_str[idx]))
    {
        search_str[idx] += 32;
    }
}

The loop condition checks search_str[idx] != '\0' , yet nowhere in the loop, idx is changed (you only change i ). So whenever the loop condition is true, you run into a neverending loop.

I would generally recommend to test the IsSubstring function in isolation before putting it into a larger program (using some test framework or just a simple program computing the IsSubstring on several test inputs and checking its result).

I guess this is some kind of homework assignment? Otherwise I would suggest to completely move away from your IsMatch/IsSubString methods and use std::string and its find function (or maybe contains in the future ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM