0

试图解决这个问题。我编写了如下代码:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int i,j,n,t;

int main()
{
cin>>t;

while(t--)
{
    vector <string> dr,rd;
    string a,b;
    cin>>n;
    cin.ignore();

    for(i=0;i<n;i++)
    {
        a.clear(),b.clear();
        getline(cin,a);
        j=a.find(" on ");
        b=a.substr(j,a.size()-1);
        a.resize(j);
        dr.push_back(a);
        rd.push_back(b);
    }

    for(i=0,j=rd.size()-1;i<rd.size();i++,j--)
    {
        cout<<dr[i]<<rd[j]<<endl;
    }
    cout<<endl;
}

return 0;
}

它完美地工作,至少在给定的示例中,当我使用文件 I/O(fstream) 运行它时,但是当我使用控制台 I/O 时,给出的代码在读取测试用例的第二个数字后崩溃。

像这样:
2
4
从 A 路开始
右路 B 路
右路 C 路
左路 D (读取并打印应该打印到这里的内容)
6 (读取并转到新行)
(崩溃)从旧马德拉斯路开始
在 Domlur 立交桥
左转 左转 100 Feet Road
右转 Sarjapur 路
右转 Hosur 路
右转 Ganapathi Temple Road

我的错误在哪里?

4

1 回答 1

1

欢迎来到 SO。

如果您说您的程序“崩溃”,您还应该说明它是如何崩溃的,并尽可能引用显示它如何崩溃的确切输出。如果必须找出问题的真正含义并解决问题,许多可能能够提供帮助的人不会打扰

如果您的问题是关于编码问题,例如您的问题,那么用您正在编码的编程语言的名称标记您的问题也很重要 - 在您的情况下是 C++。如果您不这样做,那么大多数可以提供帮助的 C++ 程序员根本不会注意到您的问题。(我现在已经标记了你的问题 C++。)

如果您使用编译语言(如 C++)进行编程,那么说明您使用的是什么编译器以及该编译器的版本(例如“GCC 4.7.2”、“MS VC++ 2012”)也很有帮助——因为那时程序员可以尝试使用相同的方法重现问题。编码问题在某种程度上取决于所使用的编译器或编译器版本是很常见的。

我已经在 Linux 上使用 GCC 4.7.2 和 clang 3.2 构建了您的程序,当我从控制台输入输入行时,它可以毫无问题地执行您给出的测试用例。

当你说它“崩溃”时,这让我推测你的意思,这就是我推测的:

我想您可能的意思是,在您输入“6”后,程序会以错误诊断终止,例如:

terminate called after throwing an instance of 'std::out_of_range'
  what():  basic_string::substr
Aborted

如果我对此有误,请随时停止阅读。

如果我是对的,那么诊断会告诉您,在您的通话a.substr(j,a.size()-1)中,索引j超出了范围。

如果j此时超出范围,那么它一定是由于前一行而超出范围j=a.find(" on ")。而那只能a.find(" on ")意味着" on "a.

查找 的文档std::string::find,例如 此处 并阅读有关返回值的信息:

如果未找到匹配项,则该函数返回 string::npos。

(size_t)-1并且肯定超出范围。

接下来,如果a.find(" on ")失败,那只能意味着前一行getline(cin,a)在该点上无法从cincontains中读取一行" on "。我们知道这是真的!因为您说程序在读取“6”并打印所需的换行符后立即崩溃。

所以这getline(cin,a)必须是在“6”之后但“Begin on Old Madras Road”之前从控制台读取一行。一个空行。如果您[Enter]在输入“6”时碰巧按下了太久,那么键盘缓冲区会包含“6\n\n”,或者可能是“6\n\n\n”,这就是它会做的事情,而不仅仅是“6\n”。cin.ignore()在读取整数后,您对 的调用将仅使用一个后续字符,因为您接受以下默认参数:

std::istream& std::istream::ignore(std::streamsize n = 1, int delim = EOF)  

正如我所说,你的程序对我来说很好。[Enter]但是我可以通过在输入测试用例行数时按下太久(第一次或第二次)或 [Enter]在我这样做后再次按下来使其以我描述的方式崩溃。无论哪种方式,我都在输入一个空行getline(cin,a)

如果到目前为止我是对的,那么您的代码中的一个严重错误是您没有检查std::string::find()输入字符串是否成功,而只是假设它是. 即使我说的不对,那也是严重的错误。

当用户的手指停留太久时,您可以阻止程序崩溃,方法[Enter]是确保cin忽略它可以读取的所有cin>>n换行符。您必须查看下一个字符(如果有),但不要提取它;检查它是否是换行符,如果是则提取并重复。替换cin.ignore()为:

for (   ;cin.peek() == '\n'; cin.ignore()){}

但是,如果用户碰巧错误地输入了不包含的路线,这不会阻止您的程序以相同的方式崩溃" on ":尝试使用“Left On Domlur Flyover”。

要修复此错误,您必须检查它j=a.find(" on ")是否成功并在不成功时处理这种情况。这是我认为是问题的完整解决方案,使用 GCC 4.7.2 和 clang 3.2 构建:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int main()
{

int t;

cin>>t;

while(t--)
{
    vector <string> dr,rd;
    string a,b;
    size_t i,j,n;
    cin>>n;
    for (   ;cin.peek() == '\n'; cin.ignore()){}

    for(i=0;i<n;i++)
    {
        a.clear(),b.clear();
        getline(cin,a);
        j=a.find(" on ");
        if (j == string::npos) {
            cout << "Invalid direction. Try again" << endl;
            --i;
            continue;
        }
        b=a.substr(j,a.size()-1);
        a.resize(j);
        dr.push_back(a);
        rd.push_back(b);
    }

    for(i=0,j=rd.size()-1;i<rd.size();i++,j--)
    {
        cout<<dr[i]<<rd[j]<<endl;
    }
    cout<<endl;
}

return 0;
}

请注意,我还纠正了几个小缺陷:-

  • 不需要任何全局变量。如果可能,最好避免使用全局变量并在尽可能小的范围内声明变量。

  • 我已将i,j,nfrom的类型更改intsize_t。用于保存 的返回值some_class::some_method()或 的返回值some_function(),或与该返回值进行比较的变量,最好使用与该返回值相同的类型声明以避免错误和编译器警告:string::find()vector::size()return size_t,这与int.

PS如果用户错误地将整数输入之一输入为“y”或“6y”而不是“6”,请调查您的原始程序或我的程序出了什么问题。你怎么能解决这个问题?

于 2013-05-13T09:53:13.843 回答