【问题标题】:Exception: string subscript out of range异常:字符串下标超出范围
【发布时间】:2020-04-03 20:04:08
【问题描述】:

我只是尝试编写一个简单的基于控制台的登录代码,而我被分配隐藏用户密码并且我编写了代码,但在调试时出现异常错误。我尝试了一些方法来解决它,但严重失败并且不知道该怎么做。代码似乎有点混乱。我也尝试了

string subscript out of rangeC++: Expression: string subscript out of range

并没有找到这样做的解决方案。所以,我需要帮助解决这个问题。

编辑:当我使用固定大小的字符数组时,它工作得很好,但由于它的固定大小和内存问题,我用字符串变量更改了它

string data_handle::hidden_password()

以下代码的功能。

#include <iostream>
#include <conio.h>
#include <exception>
#include <fstream>
#include <string>

using namespace std;


class username_data {
protected:
    string username;
    ifstream file;
public:

    int is_user_matched(string);            //the function will return the index at which the data is found
};

int username_data::is_user_matched(string user_input) {
    int index = -1;
    file.open("username.txt");                  //to open user-name file for reading file
    if (file.is_open()) {                       // if the file is open 
        for (int i = 0; getline(file, username); i++) {         // to get data from the file
            if (username == user_input) {                           //if both inputs matches then it will return the index
                index = i;
                break;
            }
        }
        file.close();                   //closing the file
    }
    else {                          //if the file is not open then it will throw user defined exception that file does not exist
        throw "user-name file not found";
    }
    return index;           //it will return the index at which the user-name is found otherwise it will return -1
}





class admin {
public:
    bool check_admin(string);       //function to check whether administrator logged in or not
};

bool admin::check_admin(string username) {
    string file_data;               //to get data from administrator file
    bool is_found = false;          //to check whether the data is found in the file and return whether it is present or not
    ifstream admin_file;            //to open the file
    admin_file.open("admin.txt");   //opening administrator file
    if (admin_file.is_open()) {     //if administrator file is open
        while (getline(admin_file, file_data)) {        //to get data till user-name is not found or file is not giving any further data
            if (file_data == username) {        //if data is matches with the passed user-name then it will break the loop
                is_found = true;        //if data is found then the boolean will turn true and break the loop
                break;              //breaking the loop
            }
        }
        admin_file.close();         //closing the file
    }
    else {
        throw "administrator file not found";       //if anything wrong occurs then it will throw exception
    }
    return is_found;                //to return true or false of data
}







class password_data {
    string password;
    ifstream file;
public:
    int is_password_matched(string);            //it will return the index at which the entered password is found
};


int password_data::is_password_matched(string user_input) {
    int index = -1;                         //if the data is not found then it will return -1
    file.open("password.txt");              //opening the password file
    if (file.is_open()) {                   //it will return true if the file is open for reading
        for (int i = 0; getline(file, password); i++) {     //this will get input from the file and checks until the last data or the relevant file is found
            if (password == user_input) {               //if data is matched
                index = i;                  //then it will store the input and the loop will broken down
                break;                      //to break the loop
            }
        }
        file.close();               //to close the program it will save from force closing of file which may leads to data corruption
    }
    else {
        throw "password file not found";        //it will throw exception
    }
    return index;                       //to return the found index
}







class data_handle  {
    string entered_username;
    username_data handler1;         //to handle user-name data
    password_data handler2;         //to handle password data
    string hidden_password();       //to return the string about the password
public:
    bool is_admin_logged_in;
    void user_input();              //this function will get user input
};

string data_handle::hidden_password() try {
    string entered_password;
    for (int i = 0; true; i++) {
        entered_password[i] = _getch();
        if (entered_password[i] != 8 && entered_password[i] != 13) {        //8 is the ASCII of backspace and 13 is the ASCII of enter

            cout << '*';                //password form
        }
        else if (entered_password[i] == 8) {            //backspacing for erasing password 
            if (i >= 1) {
                cout << "\b \b";            //only erase stars from console window
                i -= 2;                     /* just for array overwriting -2 because when we press backspace it goes one index up(-1 for that) and
                                            to go to the variable to be changed (-1 again for that too) so as a whole -1-1=-2*/
            }
            else {
                i = -1;                     /* if the password array went to 0 index then by pressing backspace the index of array will go in negative values to restore them to 0
                                             -1 is used because if index went -1 then when the loop starts the index i will be restored to 0 index*/
            }
        }

        else if (entered_password[i] == 13) {
            entered_password[i] = '\0';             // if user press enter then store \0 as null character
            break;                          // terminating the loop
        }
    }
    return entered_password;
}
catch (exception ex) {              //if anything occurs like array index out of bounds
    cout << ex.what() << " occurred\n\n";
    return "";
}

void data_handle::user_input() try {
    int idx1, idx2;
    bool login_successful = false;          //to control the login
    do {
        cout << "Enter user-name :\t";
        getline(cin, entered_username);     //to get the user-name from the user
        cout << "Enter password :\t";
        idx1 = handler1.is_user_matched(entered_username);          //this function will pass the user-name to the handler for execution
        idx2 = handler2.is_password_matched(hidden_password());     //to get the password from the user it will return the string and then pass it to the handler function
        if ((idx1 != -1 && idx2 != -1) && idx1 == idx2) {       //if handlers methods returned -1 then data does not exists in the file if any index is returned then it is in the file and both user-name and password must have same index
            login_successful = true;                //if it is true then the login will be successful
            admin login_check;              //a class to check whether administrator logged in or anyone else
            is_admin_logged_in = login_check.check_admin(entered_username);     //running the function
        }
        if (!login_successful) {                    //if login is not successful then it will print login failed
            cout << "\n\nLogin Failed . . .\n\n";
        }
        else {                                      //else it will print login successful
            cout << "\nlogin successful!\n";
        }
    } while (!login_successful);                    //the loop will continue till user continues to enter wrong password
}
catch (const char * message) {                      //if any exception is thrown it will be handled by this catch like file is not opened then this setting will run
    cout << message << " occurred\n";
}
catch (exception ex) {              //if any other exception occurs
    cout << "\n\n" << ex.what() << "occurred . . .\n\n";
}

【问题讨论】:

  • ??????小心前行,看看会发生什么?
  • 这是因为我使用字符串作为字符数组我猜这是由于索引当我使用固定大小的字符数组时它工作正常。我也在更新问题。
  • @tadman 我更新了问题。

标签: c++ string exception


【解决方案1】:

默认构造的字符串为空。您不能使用entered_password[i] 向其中添加字符,因为那里没有字符。如果存在一个字符,它将替换一个字符,但在您的情况下不存在。

在字符串末尾添加字符的一种方法是

entered_password += _getch();

完成后,后面对entered_password[i] 的引用将引用此字符,应该没问题。

【讨论】:

  • 感谢您的帮助。我能做些什么来进一步优化这段代码。如果需要?
【解决方案2】:

hidden_password() 中,entered_password 最初为空,因此使用entered_password[i] 分配(而不是添加)字符超出了界限。要添加字符,您需要改用entered_password += ...entered_password.push_back(...)

就此而言,您应该使用std::cin.get() 而不是_getch() 从控制台读取字符。或者更好的是,您应该使用std::getline() 一口气将整个密码读入entered_password(让控制台处理退格,std::getline() 处理 ENTER),然后您可以循环entered_password 的字符根据需要使用entered_password[...]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-31
    • 2014-08-27
    • 2014-07-23
    • 1970-01-01
    • 2013-04-22
    相关资源
    最近更新 更多