getline () повторно читает первую строку моего файла - PullRequest
1 голос
/ 03 апреля 2011

Я не знаю, увидит ли кто-нибудь это вовремя, но я постараюсь ... Я нахожусь во вводном классе 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 раз первой записи.

Я прочитал и перечитал свое руководство, getline () info на cplusplus.com, искал в форумах и переключал свой код около миллиона раз.

PLEEEEAAASSSSEEE HELP!

Вот 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

О, и я убрал

с использованием пространства имен std;

, потому что он давал: cout - неоднозначная ошибка.

СПАСИБО N.

Ответы [ 2 ]

3 голосов
/ 03 апреля 2011

С чего начать !!!!

Плохая практика. Один на линию!

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++;

Edit:

На основе приведенных ниже боевых коментариев Бо.

Технически в этом нет ничего плохого:

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. Этот объект возвращается по значению и не присваивается какой-либо переменной и поэтому является временным. Временные объекты уничтожаются в конце выражения, поэтому метод data (), который возвратил указатель на внутреннюю часть QByteArray, присвоил переменной file значение, которое недопустимо, как только ';' ударил.

Безопасный способ сделать это - передать результат непосредственно в качестве параметра функции:

readFile(path.toLatin1().data());
1 голос
/ 03 апреля 2011

Я предполагаю, что вы не переустанавливаете значение row ... поэтому, когда вы увеличиваете строку, и она превышает значение ROWS, вы прекращаете сохранять любые новые значения внутри tempArray.Таким образом, вы просто прекрасно читаете файл из getline(), но вы не сохраняете эти новые значения в tempArray для проверки один раз row >= ROWS.

Сброс значения row должен помочь.,Вы также можете захотеть, в зависимости от того, как работает ваша validateData() функция, передать ей значение row, а не ROWS, чтобы вы не получали данные, сохраненные из предыдущего цикла, смешиваясь с данными, считанными натоковая петля, если getline(inputss, token, ',') возвращает ошибку и выдает сообщение до того, как вы прочитали ROWS объем данных.

Надеюсь, это поможет,

Джейсон

...