Read file into 2D array

Hello,
I am trying to read the contents of a text file into a 2D array in a macro and this attempt crashes my program. Where am I going wrong?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int Nts = 4;  // number of rows
int Nnd = 14; // number of colums
float **crd;

DEFINE_ON_DEMAND(Move_By_Filedod)
{
	int i = 0;
	float dats;
	FILE* fp;

	fp = fopen("GGG.dat","r"); // file has 4 rows and 14 columns
	crd = malloc(Nts*sizeof(float *));

	for (i=0;i<Nts;i++)
	crd[i] = malloc(Nnd*sizeof(float));

	fread(crd, sizeof crd,Nts*Nnd,fp);
	fclose(fp);
        printf("Test: %f \n",crd[0][0]);
}
Last edited on

Could you not do this with C++? Something like:

1
2
3
4
5
6
7
8
9
10
11
std::vector<std::vector<float>> the2DVector (Nts, std::vector<float>(Nnd));

ifstream inFile("GGG.dat");

for (int i = 0 ; i < Nts; ++i)
{
  for  (int j = 0 ; j < Nnd; ++j)
  {
    inFile >> the2DVector[i][j];
  }
}



Anyway, this looks suspicious.
fread(crd, sizeof crd,Nts*Nnd,fp);
Are these values correct? sizeof crd is the size of a pointer, but you want to read float values. Are they the same size? And in what format is the file? Is it binary or text? You're reading raw bytes, so if the file is text, this will go very wrong.


Last edited on
You malloc the rows of the array separately, in different allocation blocks, so they are not contiguous. But you try to read it in as if all of the rows were contiguous. You either need to allocate the data block in one malloc call or do a separate fread for each row. I would do the former.

Also, you should open the file in binary mode since you are reading binary data. If the data file isn't binary (i.e., you can easily read it in a text editor) then you shouldn't be using fread.

And your fread call is not quite right. It should be sizeof **crd or sizeof crd[0][0], since each element is the size of a float, not the size of a pointer to a pointer to a float. And you don't want to read it into the same memory where you've stored your row pointers.

So maybe something like this:

1
2
3
4
5
6
7
8
9
10
11
DEFINE_ON_DEMAND(Move_By_Filedod)
{
    crd = malloc(Nts * sizeof *crd);           // allocate space for the row pointers
    crd[0] = malloc(Nnd * Nts * sizeof **crd); // allocate space for the data block
    for (int i = 1; i < Nts; i++)
        crd[i] = crd[i - 1] + Nnd;             // calculate the row pointers

    FILE *fp = fopen("GGG.dat","rb");          // open in binary mode
    fread(&crd[0][0], sizeof crd[0][0], Nts * Nnd, fp); // read into the data block
    fclose(fp);
}

Last edited on
Hello,

I am using a text file, not binary. I got this example from a c++ book but it only read into a 1D array, so that is where I got the idea to use fread for a 2D array as well. When I used the snippet suggested by dutch I did get another crash. Is it because I am using the text data? I want to accomplish this as low level commands and as quickly executed as possible because this file is only a test file. The real file will have 1500 rows and 6000 columns. My data file looks like this, with tabs between columns:

91.00000000000000 97.00000000000000 94.00000000000000
0.007000000000000 0.010000000000000 0.012000000000000
0.003333333333333 0.000300000000000 0.008333337633333

Also, to Repeater I cannot use the Vector class. I must use regular arrays.

Thanks for everyone's input so far!

P.S. I got the array initialization with malloc from this page:

https://www.eskimo.com/~scs/cclass/int/sx9b.html
Last edited on
I think there might be something else wrong with the code provided by dutch, because even this errors, without any file reading or anything.

1
2
3
4
5
6
7
8
9
10
	crd = malloc(Nts * sizeof *crd);// allocate space for the row pointers
	crd[0] = malloc(Nnd * Nts * sizeof **crd); // allocate space for data blocks
		for (int i=0;i<Nts;i++)
			crd[i] = crd[i-1] + Nnd;

		for (int i=0;i<Nts;i++)
	{
		for (int j=0;j<Nnd;j++)
			crd[i][j] = 12+3*i+j;
	}
Last edited on
Yes, it crashed because your data is not binary.

And the code you posted doesn't work because you f'ed it up!
You changed the starting value of i to 0 where I had it as 1 (we set element 0 in the previous line).

1500 rows by 6000 columns is not that big.
Don't worry about "efficiency".
Just do it in the simplest way you can.
And forget about fread. It is only for binary data.
Use fscanf with "%f" format instead.
Last edited on
Ah, I see I re-used my previous for loop because I didn't notice that yours started from 1. Thanks dutch! Now it doesn't crash when I make that change, but it says all elements of the array are zero. I guess because it is not binary.

My understanding is that fscanf will read a whole row at a time and I don't know how I can possibly give 6000 %f symbols in the call, which is why I thought fread would work. How would you recommend doing this? Is there something like repmat in matlab?

Thanks again!
No, you don't need to read a line at a time. Try something like this:

1
2
3
    for (int r = 0; r < Nts; ++r)
        for (int c = 0; c < Nnd; ++c)
            fscanf(fp, "%f", &crd[r][c]);

Actually, looking at the input values that you've displayed above, you may want to use double instead of float to hold them. Floats only have about 7 digits of precision whereas doubles have about 16. The format spec for doubles is "%lf" (that's a lowercase L before the f).
Last edited on
Thanks, dutch!
Topic archived. No new replies allowed.