I'm having difficulties to get the buffer read 10 numbers from a file, then after it's empty read next 10 numbers, and so on till eof is reached. The input file contains several lines of data, with a single integer value on each line. Here is my code (I have commented where help is needed):

#include <fstream>
#include <iostream>
using namespace std;

const int MAXLEN = 10;

class BufferClass
{
  private:
          int buffer[MAXLEN];
          ifstream f;
  
  public:
         BufferClass();
         ~BufferClass();
         void startNumber();
         void getNumber(int &num, bool &endfile);
         void printNumber(int &num);
};

BufferClass::BufferClass()
{
     //no use, since startNumber() takes care of opening the file?!?
}

BufferClass::~BufferClass()
{
     f.close();
}

//sets whatever is necessary to cause getNumber to return
// values beginning at the first number in the file
void BufferClass::startNumber()
{
     f.open("p2355.dat");
}

//getNumber() returns the value of the next number stored in a disk file
//and set endfile to false, or set endfile to true if there
//is no more data in the file
//getNumber() has to interface with the disk file through
//a 10 element buffer (i.e. at most 10 numbers from
//the fileare resident in memory at one time
void BufferClass::getNumber(int &num, bool &endfile)
{
     //read ten numbers from file
     //
}

void BufferClass::printNumber(int &num)
{
     cout << num << endl;
}



int main(void)
{
    BufferClass buffer;
    int num;
    bool endfile;
    
    buffer.startNumber();
    buffer.getNumber(num, endfile);
    
    while(!endfile)
    {
         buffer.printNumber(num);
         buffer.getNumber(num, endfile);
    }
    return 0; 
}

Thank you,

Waldis

Please to post bufferclass::get_number() Helping you without it is really hard. Even if you know for sure it works, helping you is way easier with it.

I re-wrote the code, and still having trouble :sad:

Here's code:

#include <fstream>
#include <iostream>
//#include <strstream>
using namespace std;

const int MAXLEN = 10;
int buffer[MAXLEN];
int pcount;
int ncount;
ifstream f;


void startnumber()
{
     pcount = -1;
     ncount = 0;
     
     f.open("P2355.DAT",ios::in);
     //assert(!f.fail());
}

void finish()
{
     f.close();
     //assert(!f.fail());
}

void getnumber(int *num, bool *endfile)
{
     int tmpnum;
     
     f >> tmpnum;
     
     while((!f.eof()) && (pcount < MAXLEN-1))
     {
         buffer[++pcount] = tmpnum;
         f >> tmpnum;
     }
     
     *endfile = ((bool)f.eof());
     if(!endfile)
         *num = buffer[ncount++];
}

void printnumber(int *num)
{
     cout << num << endl;
}



int main(void)
{
    int num;
    bool endfile;
    
    startnumber();
    getnumber(&num, &endfile);
    
    while(!endfile)
    {
         printnumber(&num);
         getnumber(&num, &endfile);
    }
    return 0; 
}

Any help would be appreciated.

Waldis

I'd first off recommend using return types instead of pointers. Handling pointers like that (imho) just makes the code messier than it needs to be. You could do it with references instead of pointers as well. And instead of keeping endfile as a variable, just use f.eof() .

I'd also suggest you try to design the program to not use global variables. While they do make it easier for this size of a project, using them is typically regarded as a bad thing. You could either wrap them in a class (as you attempted before), or pass them around as parameters. You could (and probably should) also make use of return types. For instance, if your functions used return types, you could have int getnumber(fstream& f); instead of void getnumber(int*, bool*); . This is a more intuitive design for the function as well ( getnumber takes a file and gets a number out of it; seems pretty straightforward, no?). And the fstream could be a local variable in main, rather than a global variable.

As a precaution, you should make sure the file is not empty when you get the first number. You have:

startnumber();
  getnumber(&num, &endfile);

  while(!endfile)
  {
    printnumber(&num);
    getnumber(&num, &endfile);
  }

whereas I would recommend something along the lines of:

startnumber();
  while(!f.eof())
  { // note: I'd assume that you'd use references and not need the ampersands
    getnumber(num, endfile); // endfile could probably be dropped too if you use f.eof()
    // previous line could also be num = getnumber(); if you use return types
    printnumber(num);
  }

Hope that was mostly intelligible and that it helps a bit. As for the problems you're having, it would be good if you'd post some information about them (e.g. compile errors or what the program should do vs. what it does instead).

Thanks for reply!

Here is what the program should do:

------------------------------------------
=======================
------------------------------------------

Your task is to develop a procedure "getnumber(value,eof)" which
will return the value of the next number stored in a disk file and set eof
(end of file) to false, or set eof to true if there is no more data in the file.
The getnumber procedure will interface with the disk file through a 10 element
buffer (i.e. at most 10 numbers from the file are resident in memory at one
time). The input file contains several lines of data, with a single integer
value on each line.

In addition to the getnumber procedure, you will need to write a procedure
"startnumber" which sets whatever is necessary to cause getnumber to return
values beginning at the first number in the file. Furthermore, you will need to
write a main driver program which tests the getnumber procedure by using it to
write out all numbers that are in the file. The pseudocode for the main program
is shown below:

startnumber
    getnumber(num,endfile)
    while not endfile
         print(num)
         getnumber(num,endfile)

------------------------------------------
=======================
------------------------------------------

As fas as what it is doing... it outputs one and the same address in infinite loop :sad:

Thanks.

I made a few changes to the code, mostly small ones, but here's what I've got atm:

#include <fstream>
#include <iostream>
using namespace std;

const int MAXLEN = 10;
int buffer[MAXLEN];
int pcount;
int ncount;
ifstream f;

void startnumber()
{
  pcount = 0; // makes more sense to initialize to 0 (IMHO)
  ncount = 0;
  f.open("P2355.DAT",ios::in);
}

void finish()
{
  f.close();
}

void getnumber(int &num, bool &endfile) // use references instead of pointers
{
  int tmpnum;
  f >> tmpnum; 
  while((!f.eof()) && (pcount < MAXLEN)) // MAXLEN - 1 will have you only use 9 spaces.  
                                         // If you used <= you'd need the -1.
  {
    buffer[pcount++] = tmpnum; // since pcount was init to 0, use post-increment
    f >> tmpnum;
  }
  endfile = ((bool)f.eof());
  if(!endfile)
    num = buffer[ncount++];
}

void printnumber(int num) // just take a value, not a pointer
{
  cout << num << endl;
}

int main(void)
{
  int num;
  bool endfile;

  startnumber();
  getnumber(num, endfile);

  while(!endfile)
  {
    printnumber(num);
    getnumber(num, endfile);
  }
  return 0; 
}

I made myself a file consisting of 35 lines, each containing the line number (1-35). Here's the output when I run the program:

1
2
3
4
5
6
7
8
9
10   // up to here is correct, but this is where the buffer is full and the rest is junk
10
11
0
0
0
0
-1208485396
0
-1208485272
134521200
134521283
134521296
0
0
0

Here's the main problem that I see: once the buffer is full, you read in a number ( f >> tmpnum; ), then you skip the loop since pcount >= MAXLEN, then you set endfile and increment ncount. Once you've done that, you'll be reading from beyond the buffer (I'm surprised it didn't crash), and you won't be saving tmpnum anywhere.

Another thing. You'll notice that my file was 35 lines long, but I only got 25 lines of output. This is because it reads 10 lines from the file, sets num to the first number. From then on it does the following:

void getnumber(int &num, bool &endfile)
{
  int tmpnum;
  f >> tmpnum; // reads one number
  while((!f.eof()) && (pcount < MAXLEN)) // this is false, so skip the loop
  { /* ... */  }
  endfile = ((bool)f.eof()); // not at the end yet
  if(!endfile)
    num = buffer[ncount++]; // set to the 2nd number, 3rd, etc...
}

So, it reads 10 numbers, then each time after that reads only 1 number. After the original 10 numbers are read, it doesn't save the values it reads after that (when it's reading 10 at a time). Also, ncount will lag behind pcount by about 10.

There's two ways you could fix this:
a) Read a single number into the buffer, set num, and return. Each time pcount and ncount will be the same. When the buffer is full you need to reset pcount and ncount to 0, and overwrite the buffer again.
b) Fill the buffer all at once and set num like you do now. For each successive call, check that ncount has not reached the end of the buffer. If it has not, return the next value from the buffer. If it has, reset pcount and ncount and fill the buffer again.

I'd go with the 2nd way of doing it (2 reasons: the first doesn't make use of the buffer, and the second is already closer to the code you already have).

Oh, and whoever wrote that assignment is imposing a horrible design on you... :eek:

Here is what I came up with. The infinite loop the program was giving was a side effect of not being able to read the .dat file for some reason (path was too long or something), so when I moved it to c:\tmp\ it actually didn't do it no more.

I modified the code as you suggested, left -1 for pcount though so I could compare it with ncount, commented as much as I could, and it run "almost" right... it's loosing every eleventh integer out of .dat file.

I added some cout's to see where I'm loosing it, so it happens at the f >> tmpnum; within the loop after pcount reaches 9 and reads an extra integer, and then it looses it.

Here's the code:

#include <fstream>
#include <iostream>
using namespace std;

void startnumber();
void finish();
void getnumber(int *num, bool *endfile);
void printnumber(int num);

const int MAXLEN = 10;

int buffer[MAXLEN];
int ncount;
int pcount;
ifstream f;

void startnumber()
{
     pcount = -1;
     ncount = 0;
     
     f.open("P2355.DAT",ios::in);
     assert(!f.fail());
}

void finish()
{
     f.close();
     //assert(!f.fail());
}

void getnumber(int *num, bool *endfile)
{
     int tmpnum;

// if ncount is larger, buffer has been emptied
// and time to read next 10 records
if(ncount > pcount)
{
     //reset counters
     pcount = -1;
     ncount = 0;

     //read the first record, so we can check the eof()
     f >> tmpnum;
     cout << "first num: " << tmpnum << endl;
     while((!f.eof()) && (pcount < MAXLEN-1))
     {
         //get records into buffer
         cout << "pcount before increment: " << pcount << endl;
         buffer[++pcount] = tmpnum;
         cout << "tmpnum is: " << tmpnum << " pcount after incriment is: " <<
          pcount << " buffer contains: " << buffer[pcount] << endl;
         //read next record
         cout << "tmpnum before reading: " << tmpnum << endl;
         f >> tmpnum; //11th number is being read in here
                      // and sent to outer space!?!
         cout << "tmpnum after reading: " << tmpnum << endl;
     }
}
     //assign eof status
     *endfile = (ncount > pcount);
     
     //if not eof, pass next record in buffer
     if(!*endfile)
         *num = buffer[ncount++];
}

void printnumber(int num)
{
     cout << num << endl;
}



int main(void)
{
    int num;
    bool endfile;
    
    startnumber();
    getnumber(&num, &endfile);
    
    while(!endfile)
    {
         printnumber(num);
         //cout << num << endl;
         getnumber(&num, &endfile);
    }
    
    finish();
    system("pause");
    return 0; 
}

I hope it's readable.

Thanks,

Waldis

(...) it run "almost" right... it's loosing every eleventh integer out of .dat file. (...)

This is because it reads the number, then the loop condition fails so it doesn't save the number. I'll let you figure out a way to fix that ;)

Here it goes, I got rid of eof() and changed the while loop around...

void getnumber(int *num, bool *endfile)
{
     int tmpnum = 0;

// if ncount is larger, buffer is empty
// and it's time to read in first/next 10 records
if(ncount > pcount)
{
     //reset counters (in case it's a re-run ;)
     pcount = -1;
     ncount = 0;

     while((f.good()) && (pcount < MAXLEN-1))
     {
         //get record into buffer
         f >> tmpnum >> ws; //without ws if there is a new line at the end
                                        //it outputs last number twice
         buffer[++pcount] = tmpnum;
     }
}
     //assign endfile status
     *endfile = (ncount > pcount);
     
     //if not endfile, pass next record from buffer
     if(!*endfile)
         *num = buffer[ncount++];
}

Thanks,

Waldis :)

Why not check to see whether the input operation succeeds before using its result? (Like I tried to point our earlier?)

[edit]To me, this kinda reads something like this...

while((f.good()) && (pcount < MAXLEN-1))
     {
         // We're good so far!
         f >> tmpnum >> ws;
         // Who knows if this succeeded or not? Let's blindly continue on...
         buffer[++pcount] = tmpnum;
         // Hey! Maybe the next loop iteration will tell me 
         // I shouldn't have done the last thing that I did.
     }
This question has already been answered. Start a new discussion instead.