0

Realization: Wow spent so much time staring at this code I finally noticed something I'd been missing all along. I initialize i = size which means at the start the array is looking at an unfilled spot so I finally understand why it always puts a repeat. Now to attempt to fix it. Feel free to berate me.

I'm looking through the array backwards because I'm using an insertion sort algorithm so I work backwards from the last known element to alphabetize the data. However no matter what the final line in the data file (from which I'm reading) it always repeats twice. Here is the array contents printed to demonstrate the repeat:

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

Notice that bill gates is listed twice. The problem appears to be with the way I'm looping. If I modify the lower bound in the loop to 1 instead of 0 then shit goes haywire. Here is the function in question, I don't believe any of the code outside is relevant so I did not include it:

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

However if the full code is necessary for further context then here it is:

// ----------------------------------------------------------------------------
// 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
4

2 回答 2

1

文件结束指示符不是在读取文件的最后一个字节时设置,而是在尝试读取下一个字节时设置,即不存在的字节。

因此,在读取最后一行后,while(infile)检查仍然成功,但infile >> temp.last调用失败,变量完好无损。您不检查该故障,因此您使用前一次迭代读取的值运行循环的一个额外迭代。

于 2013-10-07T02:16:39.077 回答
1

您可以通过更改来组合流提取和测试流状态:

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

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

如果由于任何原因(包括 EOF)读取失败,这将读取流并失败(返回 false)。

注意:阅读此相关问题以获得更多解释。

于 2013-10-07T02:30:23.937 回答