-1

I'm working on a project with "main" function and some other functions.

I want to open the .data file in main function and and read it in another function like "getsize" and then read the file in "store_num".

First of all, it seems that I have to deliver some parameter or pointer to the functions so that they can recognize the .data file.What should I do?

Second, I want the content in file just read once, not reading all the content in the .data file once again in every different functions.What should I do?

There may be some errors in my code, but I think it'll be alright to understand my question.

#include <iostream>
#include <fstream>

typedef struct value {
    int x, y, value;
    bool check;
}value;

typedef struct peak {
    int col, row;
}peak;

class testcase {
public:
    void getsize(value*);
    void store_num(int, value*);
    void peaktest(int);
    int row = 1;
    int peak_num = 0;
    void set_peak(int, int);
    value* array;
    peak peak_list[10];
    int row_num, col_num;
};

int main(int argc, char * argv[]) {
    std::fstream myfile("matrix.data", std::ios_base::in);


    testcase* map;
    map->getsize(map->array);
    map->store_num(1, map->array);
    for (int countrow = 2; countrow <= map->row_num; countrow++) {
        map->store_num(countrow,map->array);
        map->peaktest(countrow - 1);
    }
    map->peaktest(map->row_num);


    return 0;
}

void testcase::getsize(value* array) {

    //std::cin >> row_num >> col_num;
    myfile >> row_num >> col_num;
    array = new value[row_num*col_num];
}

void testcase::store_num(int row, value* array) {
    if (row == 1 || row == 2 || row == 3) {
        for (int count = 0; count < col_num; count++) {
            /*std::cin*/ myfile >> (array + (row - 1)*col_num + count)->value;
            (array + (row - 1)*col_num + count)->check = true;
            if (count > 0) {
                if ((array + (row - 1)*col_num + count)->value >
                    (array + (row - 1)*col_num + count - 1)->value) {
                    (array + (row - 1)*col_num + count - 1)->check = false;
                }
                else if ((array + (row - 1)*col_num + count)->value <(array 
 + (row - 1)*col_num + count - 1)->value){
                    (array + (row - 1)*col_num + count)->check = false;
                }
            }
            if (row > 1) {
                if ((array + (row - 1)*col_num + count)->value >
                    (array + (row - 2)*col_num + count)->value) {
                    (array + (row - 2)*col_num + count)->check = false;
                }
                else if ((array + (row - 1)*col_num + count)->value <(array + (row - 2)*col_num + count)->value) {
                    (array + (row - 1)*col_num + count)->check = false;
                }
            }
        }
    }
    else {
        for (int count = 0; count < col_num; count++) {
            /*std::cin*/myfile >> (array + ((row - 1) % 3) + count)->value;
            (array + ((row - 1) % 3) + count)->check = true;
            if (count > 1) {
                if ((array + ((row - 1) % 3) + count)->value > (array + ((row - 1) % 3) + count - 1)->value) {
                    (array + ((row - 1) % 3) + count - 1)->check = false;
                }
                else if ((array + ((row - 1) % 3) + count)->value < (array + ((row - 1) % 3) + count - 1)->value) {
                    (array + ((row - 1) % 3) + count)->check = false;
                }
            }
            if ((array + ((row - 1) % 3) + count)->value > (array + ((row + 1) % 3) + count)->value)
                (array + ((row + 1) % 3) + count)->check = false;
            else if ((array + ((row - 1) % 3) + count)->value < (array + ((row + 1) % 3) + count)->value)
                (array + ((row - 1) % 3) + count)->check = false;
        }
    }
}

void testcase::peaktest(int row) {
    for (int col = 1; col <= col_num; col++) {
        if ((array + (row - 1)*row_num + (col - 1))->check == true)
            set_peak(row, col);
    }
}

void testcase::set_peak(int row ,int col) {
    peak_list[peak_num].row = row;
    peak_list[peak_num].col = col;
    peak_num++;
}
kj007
  • 6,073
  • 4
  • 29
  • 47
Eric Yu
  • 27
  • 9
  • Couple of questions about your code: the file that is read in `matrix.data` is this being read in as text that you have to convert to types or is this being read in as a binary file? The second question is more of a request: could you supply an example of your `matrix.data` file so that others can see what kind of data file you are trying to read in. – Francis Cugler Oct 11 '18 at 04:42

3 Answers3

2

Pass the file stream by reference into the other functions that need it.

class testcase {
public:
    void getsize(value*, std::fstream & myfile);
    void store_num(int, value*, std::fstream & myfile);
    ...
};

int main() {
    std::fstream myfile("matrix.data", std::ios_base::in);

    testcase* map; // Danger Will Robinson! Danger!
    map->getsize(map->array, myfile);
    map->store_num(1, map->array, myfile);
    for (int countrow = 2; countrow <= map->row_num; countrow++) {
        map->store_num(countrow,map->array, myfile);
        map->peaktest(countrow - 1);
    }
    ...
}

Regarding the danger message,

testcase* map; 

allocates a pointer to a testcase, but doesn't point it a anything. You could

testcase* map = new testcase; 

but there is no need for dynamic allocation here. Consider discarding the pointer.

int main() {
    std::fstream myfile("matrix.data", std::ios_base::in);

    testcase map;
    map.getsize(map.array, myfile);
    map.store_num(1, map.array, myfile);
    for (int countrow = 2; countrow <= map->row_num; countrow++) {
        map.store_num(countrow,map.array, myfile);
        map.peaktest(countrow - 1);
    }
    map.peaktest(map.row_num);


    return 0;
}

And fixing up that, I see a bug:

void testcase::getsize(value* array, std::fstream & myfile) {

    myfile >> row_num >> col_num;
    array = new value[row_num*col_num];
}

When you pass in a pointer, the data pointed at, if any, is passed by reference. The pointer itself is not. array holds a copy of the address used to call getsize and is an automatic variable scoped by getsize. The allocation assigned to array inside the function is lost when array goes out of scope. This leaves the value passed in unchanged. Oops. Normally you would

void testcase::getsize(value*& array, std::fstream & myfile) {

    myfile >> row_num >> col_num;
    array = new value[row_num*col_num];
}

and pass in a reference. But...

I find myself wondering why pass an object's own data into one of its methods? the testcase instance already knows array. We can assign directly to it. For example

void testcase::getsize(std::fstream & myfile) {

    myfile >> row_num >> col_num;
    array = new value[row_num*col_num];
}

Next, what if the testcase instance already has an allocation when you call getsize? array = new value[row_num*col_num]; leaks it. You want to add a constructor that sets array to nullptr

testcase::testcase(): array(nullptr)
{
}

and then

void testcase::getsize(std::fstream & myfile) {

    delete[] array;
    myfile >> row_num >> col_num;
    array = new value[row_num*col_num];
}

Other possibilities are to overload operator>> to read into a testcase. Information on that can be found in What are the basic rules and idioms for operator overloading? Do that and getsize and store_num just go away. They are built into operator>> and the first few lines of main become

testcase map;
myfile >> map;

Probably more bugs in there, but I'm not looking for them. Instead... I'm going to rant.

typedef struct value {
    int x, y, value;
    bool check;
}value;

is a C-ism. C++ took advantage of 20 or so years of C and eliminated the need to typedef a struct to avoid typing struct all the time. C++ knows darn well that value is a struct, so all you need, other than love, is

struct value {
    int x, y, value;
    bool check;
}
user4581301
  • 33,082
  • 7
  • 33
  • 54
0

Put std::fstream myfile in the class itself, and call myfile.open with file name in the constructor of the class, or make a method like init and call myfile.open from there.

If you do like to keep the myfile variable in main, then pass it to the constructor of testcase and have a reference variable of type std::fstream in the class. This way:

class testcase {
std::fstream& _myfile;
public:
testcase(std::fstream& fileArg):_myfile(fileArg){}
Ajay
  • 18,086
  • 12
  • 59
  • 105
0

My advice is to add a class who's single responsibility is to handle I/O from the file in question. Instantiate it in main before you call the other functions, then pass it as a parameter and invoke a public .get() method from it for the next line of data. If you simply put file I/O into your testcase class and had more than one testcase then you either need one data file per object or else each object could be trying to open the same data file. This could also reposition the stream cursor within the file and give you unpredictable results. Better to have one object fulfilling the single responsibility principle.

/*---------------------------------

 * FileMgr class

 ----------------------------------*/

class fileMgr
{
private:

    bool open;
    std::string filename;
    std::string buffer;
    std::fstream myfile;

public:

    //-- constructor with filename parameter

    fileMgr(std::string filename)
        : filename(filename)
    {
        buffer = "";    
        myfile = std::fstream(filename, std::ios_base::in | std::ios_base::app);

        if(!myfile)
        {
             /*-----------------------------------
             * check to make sure the file opened without
             * any problems, and set a bit flag to tell 
             * which state it is in
             -----------------------------------*/

            std::cerr << "\nERROR: file manager cannot open file: " << filename << std::endl;
            open = false;
        }
        else
        {
            /*---------------------------------------
             * Otherwise it opened fine and we place the 
             * cursor at the beginning of the file
             -----------------------------------------*/

            open = true;
            myfile.clear();
            myfile.seekg(0, std::ios::beg);
        }
    }

    //-- function to serve a result row

    value get()
    {
        value newValue;

        if(open)
        {
            std::getline(myfile, buffer);

            //--- parse buffer for your data
        }
        return value;
    }
};
Adam Coville
  • 141
  • 7