2

I'm trying to populate an array from a .txt that I am reading. I am using this code that I am using as a function to read the file:

double* read_text(const char *fileName, int sizeR, int sizeC)
{
    double* data = new double[sizeR*sizeC];
    int i = 0;
    ifstream myfile(fileName);
    if (myfile.is_open())
    {

        while (myfile.good())
        {
            if (i > sizeR*sizeC - 1) break;
            myfile >> *(data + i);
            //cout << *(data + i) << ' '; // Displays converted data.
            i++;
        }
        myfile.close();
    }

    else cout << "Unable to open file";
    //cout << i;

    return data;
}

Now when I read the file I am trying to take the elements from the 1D data array and store them into a 2D array.

I've tried to create an array in a public class, however I have no idea on how to move the data that I am reading to a 2D array.

I know it's not very clear but basically I'm doing the nearest neighbour search algorithm to compare 2 images. I have taken one image and converted it into the values using this bit of code above. However now I am trying to store the data that I am reading into a 2D public array?

Biffen
  • 5,354
  • 5
  • 27
  • 32
Hparsons28
  • 69
  • 1
  • 6
  • 1
    I don't understand. There are already a plethora of examples and questions regarding reading into a 2d array. Search the internet for "C++ read file matrix" or "c++ read file 2D array". – Thomas Matthews Dec 05 '18 at 15:00
  • 3
    Doing `while (myfile.good())` is almost the same as `while (!myfile.eof())`, and [you should not not do that](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong). – Some programmer dude Dec 05 '18 at 15:00
  • 1
    Why do you want to do that? The 1D array is much better than any 2D shenanigans. Can't you just remap indexes for access to the 1D array that you've already got? – Lightness Races in Orbit Dec 05 '18 at 15:00
  • 1
    @Someprogrammerdude In this case, it's fine. There is no "work" done after the final read is attempted, so the condition is evaluated at the right time. I do agree that re-arranging the loop could produce more idiomatic code. – Lightness Races in Orbit Dec 05 '18 at 15:00
  • Is the data in text format or binary format? – Thomas Matthews Dec 05 '18 at 15:02
  • 1
    So there is no answer to give here. You are doing the right thing by returning a 1d array. Don't change that. It's better. – Matthieu Brucher Dec 05 '18 at 15:06
  • Ok thanks, the reasons I was thinking of the 2d is because one of the demonstrators in our workshop at university told me I needed to put it into a 2D array rather than keep it in a 1D array. – Hparsons28 Dec 05 '18 at 15:11
  • 1
    It's very annoying when teachers are doing the wrong thing. They should go back to training themselves. – Matthieu Brucher Dec 05 '18 at 15:12
  • It may be helpful to convert to a 2D array later, but not for easy of use, rather for processor pre-fetching optimization. If your data-set is a rather small size, say under 1,000 by 1,000 indexes I wouldn't worry about it. http://katecpp.github.io/cache-prefetching/ – aj.toulan Dec 05 '18 at 15:12
  • 1
    Yes I agree Mattihieu. Its the reason ive began to use stackoverflow, because you can usually get better results and much more detailed answers. – Hparsons28 Dec 05 '18 at 15:15
  • @MatthieuBrucher, it's possible there is a specific exercise they want the OP to go through so it becomes muscle memory. Learning best practice is easy in the field, but only if you have all the right tools at your disposal. I know it's frustrating to see bad practice exercises, but it's not the end all of their education. – aj.toulan Dec 05 '18 at 15:17
  • 1
    @aj it's always going to be better. You can add some cache line alignment to make it better, but 1d array is what you want for performance, not a 2d array because of the additional memory indirection. Even if it's looking at a 1d array. – Matthieu Brucher Dec 05 '18 at 15:18
  • @aj I disagree. That's where they should be taught good practices. Using a 2d array instead of a 1d is not. There is ample proof of that. – Matthieu Brucher Dec 05 '18 at 15:19
  • @MatthieuBrucher, but if you're creating the 1D array row by row and you access a column, you're going to prefetch a whole row. Is it not more performant to transpose the array? – aj.toulan Dec 05 '18 at 15:20
  • @MatthieuBrucher, just to be clear, I was always taught to use a 1D array because it's faster, I'm just curious as to what's the best thing to do in a variety of circumstances. – aj.toulan Dec 05 '18 at 15:23
  • This is a different problem, that has nothing to do with the problem at hand. Using a 2d array doesn't solve the prefetch problem. – Matthieu Brucher Dec 05 '18 at 15:24
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/184764/discussion-between-aj-toulan-and-matthieu-brucher). – aj.toulan Dec 05 '18 at 15:24

2 Answers2

3

Here is a more compact version of reading in a 2D matrix:

int quantity = sizeR * sizeC;
double * matrix = new double [quantity];
double value = 0.0;
double * p_cell = matrix;
//...
while ((myfile >> value) && (quantity > 0))
{
  *p_cell++ = value;
  --quantity;
}

In the above code snippet, a pointer is used to point to the next slot or cell of the matrix (2D array). The pointer is incremented after each read.

The quantity is decremented as a safety check to prevent buffer overrun.

Thomas Matthews
  • 52,985
  • 12
  • 85
  • 144
0

Assuming every double returned represents a pixel. You can define a function that retrieves pixels like so:

double get_pixel(int x, int y, double* data, int sizeC)
{
    return data[x + y*sizeC];
}

Where sizeC is the width of the image (number of columns).

You can then use the function above to fill your 2D array like so:

for(int i = 0; i < sizeC; i++)
    for(int j = 0; j < sizeR; j++)
        my2Darray[i][j] = get_pixel(i, j, data, sizeC);

But then notice how unnecessary this is. You don't really need a 2D array :) keep it simple and efficient.

The function above could be a part of a struct that represents the Image where you'd have sizeC, sizeR and data defined as members.

struct Image
{
    int sizeC;
    int sizeR;
    double* data;

    get_pixel(int x, int y)
    {
        return data[x + y*sizeC];
    }
};

Then to access the image pixels you can simply do:

Image img;
// read image data and stuff
double p = img.get_pixel(4, 2);

You can even make it look prettier by overriding the operator() instead of get_pixel so retrieving the pixel would look something like:

double p = img(4, 2);
Adam Zahran
  • 1,527
  • 2
  • 13
  • 29