Последний элемент, добавленный в массив, добавляется дважды, не в состоянии понять, почему

Осознание: Ух ты потратил так много времени, уставившись на этот код, что я наконец-то заметил кое-что, чего мне все время не хватало. Я инициализирую i = size, что означает, что в начале массив смотрит на незаполненное место, поэтому я наконец понимаю, почему он всегда ставит повторение. Теперь, чтобы попытаться это исправить. Не стесняйтесь ругать меня.

Я просматриваю массив в обратном направлении, потому что я использую алгоритм сортировки вставок, поэтому я работаю в обратном направлении от последнего известного элемента, чтобы расположить данные в алфавитном порядке. Однако независимо от того, какая последняя строка в файле данных (из которой я читаю), она всегда повторяется дважды. Вот содержимое массива, напечатанное для демонстрации повторения:

List of names sorted:
100 bill gates
100 bill gates
65 duck donald
60 frog freddie
71 ghost casper
85 mouse abby
73 mouse mickey
95 mouse minnie

Обратите внимание, что Билл Гейтс указан дважды. Кажется, проблема в том, как я зацикливаюсь. Если я изменю нижнюю границу в цикле на 1 вместо 0, то дерьмо станет бесполезным. Вот функция, о которой идет речь, я не верю, что какой-либо внешний код имеет значение, поэтому я не включил ее:

bool sortInput(ifstream &infile, StudentType students[], int &size)
{
StudentType temp;

//empty condition
if(size == 0)
{
infile >> temp.last >> temp.first >> temp.grade;
strcpy(students[0].last, temp.last);
strcpy(students[0].first, temp.first);
students[0].grade = temp.grade;
size++;
}

while(infile)
{
infile >> temp.last >> temp.first >> temp.grade;

if(temp.grade >= LOWGRADE && temp.grade <= MAXGRADE)
{
for(int i = size; i > 0; i--)
{
if(strcmp(temp.last, students[i-1].last) < 0)
{
students[i] = students[i-1];
students[i-1] = temp;
}
else if(strcmp(temp.last, students[i-1].last) == 0 && strcmp(temp.first, students[i-1].first) < 0)
{
students[i] = students[i-1];
students[i-1] = temp;
}
else
{
students[i] = temp;
break;
}
}

size++;

//tester loop to print contents every step of the way
for(int i = 0; i < size; i++)
{
cout << "TEST: " << students[i].last << " " << students[i].first << " " << students[i].grade << endl;
}
cout << "DONE" << endl;

} //end for loop
} //end while loop

return true;
}

Однако, если полный код необходим для дальнейшего контекста, то вот он:

// ----------------------------------------------------------------------------
// You write meaningful doxygen comments and assumptions

#include <string.h>
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;

int const MAXSIZE = 100;            // maximum number of records in total
int const MAXLENGTH = 31;           // maximum string length
int const MAXGRADE = 100;           // highest possible grade
int const LOWGRADE = 0;             // lowest possible grade
int const GROUP = 10;               // group amount
int const HISTOGRAMSIZE = (MAXGRADE-LOWGRADE)/GROUP + 1;    // grouped by GROUP

struct StudentType  {               // information of one student
int grade;                       // the grade of the student
char last[MAXLENGTH];            // last name (MAXLENGTH-1 at most)
char first[MAXLENGTH];           // first name (MAXLENGTH-1 at most)
};

// prototypes go here
bool sortInput(ifstream &, StudentType [], int &);
void displayList(StudentType [], int);
void setHistogram(int [], StudentType [], int);
void displayHistogram(int []);
int findAverage(StudentType [], int);

//------------------------------- main ----------------------------------------
int main()  {
StudentType students[MAXSIZE];   // list of MAXSIZE number of students
int size = 0;                    // total number of students
int histogram[HISTOGRAMSIZE];    // grades grouped by GROUP
int average = 0;                 // average exam score, truncated

// creates file object and opens the data file
ifstream infile("data1.txt");
if (!infile)  {
cout << "File could not be opened." << endl;
return 1;
}

// read and sort input by last then first name
bool successfulRead = sortInput(infile, students, size);

// display list, histogram, and class average
if (successfulRead)  {
displayList(students, size);
setHistogram(histogram, students, size);
displayHistogram(histogram);
average = findAverage(students, size);
cout << "Average grade: " << average << endl << endl;
}
return 0;
}

bool sortInput(ifstream &infile, StudentType students[], int &size)
{
StudentType temp;

//empty condition
if(size == 0)
{
infile >> temp.last >> temp.first >> temp.grade;
strcpy(students[0].last, temp.last);
strcpy(students[0].first, temp.first);
students[0].grade = temp.grade;
size++;
}

while(infile)
{
infile >> temp.last >> temp.first >> temp.grade;

if(temp.grade >= LOWGRADE && temp.grade <= MAXGRADE)
{
for(int i = size; i > 0; i--)
{
if(strcmp(temp.last, students[i-1].last) < 0)
{
students[i] = students[i-1];
students[i-1] = temp;
}
else if(strcmp(temp.last, students[i-1].last) == 0 && strcmp(temp.first, students[i-1].first) < 0)
{
students[i] = students[i-1];
students[i-1] = temp;
}
else
{
students[i] = temp;
break;
}
}

size++;

for(int i = 0; i < size; i++)
{
cout << "TEST: " << students[i].last << " " << students[i].first << " " << students[i].grade << endl;
}
cout << "DONE" << endl;

} //end for loop
} //end while loop

return true;
}

void displayList(StudentType students[], int size)
{
cout << "List of names sorted:" << endl;

for(int i = 0; i < size; i++)
{
cout << " " << students[i].grade << " " << students[i].last << " " << students[i].first << endl;
}

cout << endl;
}

void setHistogram(int histogram[], StudentType students[], int size)
{
int groupIndex;

for(int i = 0; i < size; i++)
{
groupIndex = (students[i].grade - LOWGRADE) / GROUP;
histogram[groupIndex]++;
}
}

void displayHistogram(int histogram[])
{
cout << "Histogram of grades: " << endl;
int bottomBin = LOWGRADE;
int binWidth = (MAXGRADE - LOWGRADE) / GROUP - 1;
int topBin = bottomBin + binWidth;

for(int i = 0; i < HISTOGRAMSIZE; i++)
{
cout << bottomBin << "--> " << topBin << ": ";

for(int j = 0; j < histogram[i]; j++)
{
cout << "*";
}

cout << endl;
bottomBin += binWidth + 1;
topBin = min(topBin + binWidth + 1, MAXGRADE);
}
}

int findAverage(StudentType students[], int size)
{
int total = 0;

for(int i = 0; i < size; i++)
{
total += students[i].grade;
}

return total / size;
}

// ----------------------------------------------------------------------------
// functions with meaningful doxygen comments and assumptions go here

0

Решение

Вы можете объединить извлечение потока и тестирование состояния потока, изменив:

while(infile)
{
infile >> temp.last >> temp.first >> temp.grade;
...
}

в

while(infile >> temp.last >> temp.first >> temp.grade)
{
...
}

Это прочитает поток и потерпит неудачу (вернет false), если чтение завершится неудачей по любой причине, включая EOF.

Примечание: читать этот связанный вопрос для большего объяснения.

1

Другие решения

Индикатор конца файла устанавливается не при чтении последнего байта файла, а при попытке прочитать следующий байт — несуществующий байт.

Таким образом, после прочтения последней строки while(infile) проверка все еще успешна, но infile >> temp.last вызов завершается неудачно, оставляя переменную нетронутой. Вы не проверяете этот сбой, поэтому запускаете одну дополнительную итерацию цикла, используя значения, прочитанные предыдущей итерацией.

1

По вопросам рекламы [email protected]