【问题标题】:Getting an error when calling functions inside a while loop in C++在 C++ 中的 while 循环内调用函数时出错
【发布时间】:2020-03-13 11:31:34
【问题描述】:

如果这是重复的,我很抱歉。我试图找到一个类似但没有得到解决方案的问题。当我询问用户是否想再次输入时,我收到以下错误:“libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: basic_string”。如果您输入“N”,则程序结束,但是当您输入“Y”时,它会给我上面的错误。我的程序向用户询问格式为:(2019 年 12 月 25 日)的日期,并将其转换为格式:(MM/DD/YYYY)。代码有效,但我在循环时遇到了一个错误。

这是我的代码:

#include <iostream>
#include <string>
using namespace std;

void getDate(string &mdy){
    cout<<"Enter Any Date in Format: (December 25th, 2019) ";
    getline(cin, mdy);
}
void extract (string &mdy, string &m, string &d, string &y){
    int startIndex, endIndex, endIndexDay, startIndexDay, startIndexYear, endIndexYear;

    startIndex = 0;
    endIndex = mdy.find(' ');
    startIndexDay = ((endIndex - startIndex) +1);
    endIndexDay = mdy.find(',');
    startIndexYear = (endIndexDay +2);
    endIndexYear = mdy.find(' ');

    m = mdy.substr(startIndex, endIndex - startIndex);
    d = mdy.substr(startIndexDay, (endIndexDay - startIndexDay) - 2);
    y = mdy.substr(startIndexYear, endIndexYear - startIndexYear);
}
void convertDigits(string &mdy, string &d, string &y, int &dInt, int &yInt){
    dInt = stoi(d);
    yInt = stoi(y);
}
void convertMonths(string &mdy, string &m, int &mInt, int &dInt, int &yInt){

    if (m == "january" || m == "January")
        mInt = 1;
    else if (m == "febraury" || m == "February")
        mInt = 2;
    else if (m == "march" || m == "March")
        mInt = 3;
    else if (m == "april" || m == "April")
        mInt = 4;
    else if (m == "may" || m == "May")
        mInt = 5;
    else if (m == "june" || m == "June")
        mInt = 6;
    else if (m == "july" || m == "July")
        mInt = 7;
    else if (m == "august" || m == "August")
        mInt = 8;
    else if (m == "september" || m == "September")
        mInt = 9;
    else if (m == "october" || m == "October")
        mInt = 10;
    else if (m == "november" || m == "November")
        mInt = 11;
    else if (m == "december" || m == "December")
        mInt = 12;
    else
        cerr<<"Error...Please check your spelling and the date format and try again.";

    cout<<endl<<"Another Date Format is: "<<dInt<<"/"<<mInt<<"/"<<yInt<<endl;   //Outputting the new date.
}
int main() {
    string date, month, day, year;
    int monthInt, dayInt, yearInt;
    char tryAgain = 'Y';

    while (tryAgain =='Y' || tryAgain == 'y'){

        getDate(date);
        extract(date, month, day, year);
        convertDigits(date, day, year, dayInt, yearInt);
        convertMonths(date, month, monthInt, dayInt, yearInt);

        cout<<"Try Again? Type Y or N: ";
        cin>>tryAgain;
    }
    return 0;
}

【问题讨论】:

  • 为我工作..这是什么编译器?
  • 我正在使用 cLion
  • CLion 不是编译器,它是 IDE...我假设您使用的是 gcc/g++ .. 在这种情况下,问题一定出在其他地方。
  • 是的,对不起,我使用的编译器是 gcc 或 g++
  • std::out_of_range: basic_string 表示,您正在访问std::string 后面的字符。不确定它发生在哪里,但是:混合流输入 &gt;&gt;std::getline() 需要格外小心。因此,我会对此进行调试和检查。

标签: c++ string loops while-loop


【解决方案1】:

如果您在 cin &gt;&gt; 之后使用 getline,则需要将 换行符 从中间的缓冲区中清除。

在 getDate() 函数中添加cin.ignore()

void getDate(string &mdy){
    cin.ignore();
    cout<<"Enter Any Date in Format: (December 25th, 2019) ";
    getline(cin, mdy);
}

【讨论】:

  • 谢谢。当我在如果他们想再试一次的行下的 while 循环中使用 cin.ignore(100, '\n') 时,这很有效。
【解决方案2】:

有几个错误导致发布的代码无法按预期工作。

如前所述,std::cin 在输入流中留下任何换行符,因此随后对std::getline 的调用将导致一个空字符串。您可以简单地跳过每个仅包含换行符的输入行

while ( getline(cin, mdy)  &&  mdy.empty() )
    ;

另一个问题是在 extract 函数中,其中多次调用 std::string::find 而没有指定起始位置(始终隐式设置为 0):

int endIndex, startIndexYear, endIndexYear;
// ...
endIndex = mdy.find(' ');
// ...
endIndexYear = mdy.find(' '); // --> endIndexYear is equal to endIndex

y = mdy.substr(startIndexYear, endIndexYear - startIndexYear);
//                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This becomes negative.
// It seems to "work" because when converted to an unsigned type, it is interpreted
// as a big number, greater than the size of the string, and then clamped to that size.

当未找到搜索到的字符时(几乎可以预期传递一个空字符串),find 返回std::string::npos,定义为

static const size_type npos = -1;

其中size_type 是无符号类型。所以当一个空字符串被传递给这个函数时,会发生这种情况

startIndex = 0;
endIndex = mdy.find(' ');                        // --> -1
startIndexDay = ((endIndex - startIndex) +1);    // -->  0
endIndexDay = mdy.find(',');                     // --> -1  
startIndexYear = (endIndexDay +2);               // -->  1
endIndexYear = mdy.find(' ');                    // --> -1 

m = mdy.substr(startIndex, endIndex - startIndex);                 // --> ""
d = mdy.substr(startIndexDay, (endIndexDay - startIndexDay) - 2);  // --> ""
y = mdy.substr(startIndexYear, endIndexYear - startIndexYear);
//             ^^^^^^^^^^^^^^ mdy[1] is out of bounds, so it throws an exception

使用std::stringstream 提取这些标记并形成转换后的日期会容易得多。

#include <string>
#include <sstream>
#include <iomanip>

std::string convert_date(std::string const& mdy)
{
    std::string s_month;
    std::string s_day;
    int year;

    std::istringstream iss{mdy};

    iss >> s_month >> s_day >> year;
    if ( !iss )
    {
        // Wrong format, deal with the error as you prefer
        return "";
    }

    // Convert a string to the corresponding month number. To be implemented.
    // E.g. "Jannuary" -> 1
    int month = get_month_num(s_month);

    // It extracts only the numbers, ignoring trailing "st," or "th,"
    int day = std::stoi(s_day);

    // Here you could validate those numbers, e.g. rejecting a day greater than 31

    // Now compose the converted string "MM/DD/YYYY"
    std::ostringstream oss;
    oss << std::setfill('0') << std::setw(2) << month << '/'
        << std::setfill('0') << std::setw(2) << day << '/' << year;
    return oss.str();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-16
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 2015-07-13
    • 2015-07-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多