【问题标题】:getline() is repeatedly reading the first line of my filegetline() 重复读取我的文件的第一行
【发布时间】:2011-04-03 03:14:20
【问题描述】:

我不知道是否有人会及时看到,但我会尝试... 我在上 c++ 入门课程(本科生),我有一个作业要在星期一早上到期......(是的!我知道我已经拖延了 :),)

好的。我必须以这种形式阅读学生记录:

Adriana,Smith,692493955,50,43,52,86,74,83
Adrienne,Johnson,480562092,75,72,93,71,81,89
Bla, Bla, Bla

从一个文件(最多 200 个)中对它们进行排序。

我已设法完成所有其他必要的功能,但无法验证它们。

我创建了一个函数,它应该打开文件,读取每一行并在每一行中读取每个令牌并将它们存储在一个临时数组中。这个 tempArr[9] 在放入真正的数组 [9][200] 之前经过验证。

我已经设法打开文件,读取第一行并将其标记为一个数组,但是当 while 循环重复时,它再次读取文件的第一行,因此当我打印出真正的数组时获得第一个记录的 +/-200 倍。

我在 cplusplus.com 上阅读并重新阅读了我的手册、getline() 信息、在论坛中搜索并将我的代码切换了大约一百万次。

PLEEEEAAASSSEEE 帮助!

这是fn:

void getFile(std::string realArray[][200], const int ROW_SIZE)
{
    std::string filename, token, line;

    int positionLine(0);
    int positionToken(0);
    int row(0);
    int numOfLine(0);
    const int ROWS (9);
    const int MAX_RECORDS (200);
    std::string tempArray[ROWS];

    std::cout << "Please enter the desired filename with it's extension:\t ";
    std::cin  >> filename;

    const char *file=filename.c_str();
    std::ifstream input(file, std::ios::in);

    while (!input.is_open())
    {
        std::cout <<    "The file did not open correctly. \n\nPlease enter a valid filename.\n";
        std::cin  >> filename;

        const char *file=filename.c_str();
        std::ifstream input(file, std::ios::in);
    }

    while (input.good() && numOfLine < MAX_RECORDS)
    {
        getline (input,line);
        std::istringstream inputss (line);

        while (getline(inputss, token, ',') && row < ROWS )
        {
            tempArray[row] = token; 

            row++;
        }
        numOfLine++;

        validateData (tempArray,ROWS , numOfLine);

        storeData(tempArray, ROWS, realArray, ROW_SIZE, numOfLine);

    }

    if (numOfLine == MAX_RECORDS)
    {
    std::cout << "The maximum number of records to be read (" << MAX_RECORDS << ") has been reached.\n";
    }

}   

PS 我正在开发 Visual Studio 2010 我的文件是 *.dos

哦,我拿出来了

使用命名空间标准;

因为它给出了:cout 是模棱两可的错误。

谢谢 N.

【问题讨论】:

  • 上面没有显示,但是第二条记录前有一个\n。即每条记录都在单独的行上。
  • 要格式化代码,缩进4个空格。 :)
  • 您的编译器将向您发出有关隐藏其他变量的变量的警告。你应该听听。
  • 虽然我看不到您的文件读取问题在哪里,但我可以告诉您using namespace std 行。如果你添加using namespace std;,你会写一个类似cout&lt;&lt;"stuff";而不是std::cout&lt;&lt;"stuff";的cout。
  • 顺便说一句,查看您对getline() 的调用是否不起作用的简单方法是在调用getline() 之后直接输出line。因此,即之后立即执行std::cerr &lt;&lt; line &lt;&lt; endl; 之类的操作。不要这样做std::cout,因为它会缓冲并且在调用时可能不会立即输出。这样可以查看您是否真的在读取您想要的数据。正如我在回答中提到的,我认为您对getline() 没有任何问题,而且您的真正问题还在后面。像我提到的那样调试代码将帮助您更快地隔离问题点。

标签: c++ getline


【解决方案1】:

从哪里开始!!!!

不好的做法。每行一个!

std::string filename, token, line;

这些是未使用的。删除它们。

int positionLine(0);
int positionToken(0);

不要将指向字符串的指针提取到新变量中。
如果文件名被更改,则文件将变为无效。
只有将结果传递给函数时才能安全使用。

const char *file=filename.c_str();
std::ifstream input(file, std::ios::in);

所以你应该这样做。

std::ifstream input(file.c_str());

这里。您正在声明一个全新的变量input。此变量与其他变量input 无关。此版本在 while 循环结束时超出范围时被销毁。

while (!input.is_open())
{
    // <STUFF DELETED>
    std::ifstream input(file, std::ios::in);
}

这是一个非常常见的错误。
在这里测试良好状态(通常)是错误的。这是因为当您到达文件末尾时,您通常希望循环退出。但是最后一次读取实际上读取到但没有超过文件末尾,因此它不会触发 EOF 标志并且重新进入循环。那么下一次读取就会失败:

while (input.good() && numOfLine < MAX_RECORDS)
{
    getline (input,line);

更好的版本是:

while (getline (input,line) && numOfLine < MAX_RECORDS)
{

这里你猜对了:

    while (getline(inputss, token, ',') && row < ROWS )
    {

在这里你递增行以索引到tempArray。但我看不到该行重置为 0 的位置。

        tempArray[row] = token; 
        row++;

编辑:

基于以下 Bo 的评论。

从技术上讲,这样做没有错:

const char *file=filename.c_str();
std::ifstream input(file, std::ios::in);

这里file 被立即使用并且不再使用。但根据经验,我发现通过这样做,您已经在上下文中引入了一个新变量,其他人可以随意重用。通常这不是问题,但是这个特定的指针可能会在不可见的情况下变得无效(如果文件名对象被修改,那么文件指针可能会变得无效)。

这是一个维护问题,当您有多个开发人员修改代码时尤其危险。如果变量file 稍后被开发人员“A”和开发人员“B”在代码中重复使用,然后出现并添加修改变量filename 的代码,那么您将处于危险境地。

因此,存储可能不可见无效的指针总是更安全。因此,使用它们的唯一安全方法是作为函数的参数。

std::ifstream input(filename.c_str(), std::ios::in);

我最近遇到的另一种情况是在稍微不同的环境中遇到同样的问题:

QString   path(<Some String>);
char*     file = path.toLatin1().data();
readFile(file);

这里的问题是 toLatin() 返回一个 QByteArray 的对象。此对象按值返回,未分配给任何变量,因此是临时对象。临时对象在表达式的末尾被销毁,因此返回指向 QByteArray 内部部分的指针的方法 data() 已为变量 file 分配了一个值,该值在 ';' 时立即无效被击中了。

执行此操作的安全方法是将结果作为参数直接传递给函数:

readFile(path.toLatin1().data());

【讨论】:

  • 按部就班地做事并没有错,比如在一行获取指向文件名的指针,在下一行使用。非常好的代码!
  • @Bo Persson:在这种情况下没有危险。但是我发现它在维护代码时会导致问题。您现在有了这个额外的指针变量,它可能会在您不知情的情况下变得无效,并且可以稍后在代码中使用。如果你想把它放到一个单独的变量中,你应该小心限制它的范围,以免它在后面的代码中被意外使用。
  • 好吧,只是为了你的快乐,@Martin,我拿出指针并按照你写的那样做,只是为了确保。当一大堆不同的人说一大堆不同的事情时,它会变得非常混乱......我正在努力变得更好......(我还有很长的路要走......)无论如何,我变漂亮了人们告诉我的所有内容:@Xeo 缩进 4 个空格,嗨,嗨……等等。但我宁愿在 while 循环之外使用 getline 并将其放在末尾,以确保注意到 eof 并且不复制最后一行。我仍然有问题,但与 getline 无关......所以谢谢大家!
【解决方案2】:

我的猜测是您没有重新设置row 的值...因此,当您增加行并且它超过ROWS 的值时,您将停止在tempArray 中存储任何新值。因此,您从 getline() 读取文件就好了,但您没有将这些新值存储在 tempArray 中以便验证一次 row &gt;= ROWS

重置row 的值应该可以解决问题。根据validateData() 函数的工作方式,您可能还希望将row 的值而不是ROWS 传递给它,这样您就不会将前一个循环中存储的数据与在如果getline(inputss, token, ',') 在您读取ROWS 数据量之前返回错误并退出,则当前循环。

希望这会有所帮助,

杰森

【讨论】:

  • 嗯,感谢您回答@Jason,但它没有用。我在 validateData fn 调用后重置了 row 并改为将 row 传递给它,但我仍然得到一个充满 Adrianna Smith 的数组...
  • @prelic - 是的,我知道。编译我的代码很好,直到突然之间它给了我“cout is ambiguous”,我在一个网站上读到它更好
  • 最好总是使用 std::whatever 并且菜鸟会在未来弄清楚为什么...... :)
  • @johnsyweb - 嗯,我真的很想知道你的意思。 :)
  • @Natlie ...当您在调用getline() 之后添加std::cerr &lt;&lt; line &lt;&lt; endl; 时,输出是否与您正在读取的文件的行匹配?如果是这样,那么问题不在于您致电getline()
猜你喜欢
  • 1970-01-01
  • 2015-06-05
  • 2021-07-29
  • 2020-07-01
  • 2022-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
相关资源
最近更新 更多