Reputation: 810
I'm working on some code that does image manipulation, and it reads every 16 bits from a raw image file and stores each block into an array. The array needs 1392 columns and 1024 rows. I'm reading in data blocks from the raw file with fread:
fread(&q1[0][0], sizeof(uint16_t), NUM_COLS*NUM_ROWS*sizeof(uint16_t), fp);
which seems to work up until q1[0][280], where it suddenly stops (values past 280 are 0).
I had previously declared arrays directly:
uint16_t q1[NUM_COLS][NUM_ROWS];
but I thought that it would need dynamic allocation to store more than 280 values, so I re-wrote it to be
uint16_t** arr;
arr= (uint16_t**) malloc(NUM_ROWS * sizeof(uint16_t *));
if (arr == NULL) {
fprintf(stderr, "out of memory\n");
}
for(int i=0; i<NUM_ROWS; i++) {
arr[i]= (uint16_t*) malloc(NUM_COLS * sizeof(uint16_t));
if(arr[i] == NULL) {
fprintf(stderr, "out of memory\n");
}
}
Unfortunately, this still stops at index 280. Any ideas as to why it's stopping (or if there's a better way of doing this)?
Upvotes: 2
Views: 512
Reputation: 12675
If you're making your array dynamic, you might want to consider:
or
Allocating a one-dimensional array:
arr= (uint16_t *) malloc(NUM_ROWS*NUM_COLS*sizeof(uint16_t));
and accessing it at column col
and row row
as follows:
arr[col*NUM_ROWS+row]
This is not as convienient to use, but its simple to implement.
Upvotes: 0
Reputation: 137810
First, it's better not to presume that such an array will be too big. Most likely your platform does support a global array of a couple megabytes. Really you're not talking about a very big object at all.
Second, an array of pointers is most useful when the row size varies within the array of arrays. For a graphics application, this will degrade spatial locality and hurt performance. Also, you will call malloc
and free
thousands of times more than necessary, which can also add up.
The problem with reading NUM_COLS*NUM_ROWS*sizeof(uint16_t)
bytes at once is that the image is no longer contiguous in memory; it's divided into a separate block of memory for each row. Try a separate I/O operation for each malloc
ed block… although my recommendation would be to reconsolidate that block instead, and if its size is really constant, make it a global.
Upvotes: 5
Reputation: 28050
Your two-dimensional array is an array of arrays.
q1[0]
is the address of first subarray, q1[0][0]
is the first element in the first subarray. However, the second subarray q1[1][0]
is the result of a different call to malloc
. Therefore, it is not in consecutive memory after the first subarray.
Your read call fills the first row, and then should cause a segmentation fault afterwards, because the memory is not what you expect it to be.
You will have to read the data in steps, one for each subarray.
Upvotes: 4
Reputation: 92271
If this is your actual code for reading
fread(&q1[0][0], sizeof(uint16_t), NUM_COLS*NUM_ROWS*sizeof(uint16_t), fp);
you attempt to read way more than fits in the array. The second parameter is the size of each element and the third is number of elements. You cannot have sizeof
in both.
Did you check the return value of fread
, the number of elements actually read? If that is larger than the array, all bets are off!
When you later change to allocating each row separately, you will also have to read each row separately, because the whole matrix is no longer in contiguous memory.
Upvotes: 2
Reputation: 13170
You are reading NUM_COLS*NUM_ROWS integers into a location (&q1[0][0]) which is not the start of an allocated block of NUM_COLS*NUM_ROWS integers.
What you should do is:
for (int i = 0; i < NUM_ROS; ++i) {
fread (q[i], sizeof(uint16_t), NUM_COLS, fp);
}
The reason for this is that, according to the way you allocated, each 'row' is the start of an allocated block of NUM_COLS integers.
Also, not that the 3rd argument to fread
is the number of items, not the size of the items.
Upvotes: 2