As per my previous question (many thanks to Jonathan Leffler), I edited my code (second two blocks of code), but I ran into a rather strange problem.
The following one breaks unpredictably...
void free_array(array_info *A)
{
int i;
for(i = 0; i < (A->height); ++i)
{
printf("About to free: %x\n", A->dat_ptr[i]);//for debugging purposes
free(A->dat_ptr[i]);
printf("Freed row %i\n", i);//for debugging purposes
}
free(A->dat_ptr);
}
I initially tested create_array
directly followd by free_array
and it worked flawlessly with rather big arrays (10^8). However, when I do my calculations in between and then try to free()
the arrays, I get an access violation exception (c00000005). When I was debugging it, I noticed that the program would execute perfectly every time if I had a breakpoint within the "free_array" loop and did every line individually. However, the compiled code wouldn't ever run past row6 of my second array on its own. I turned off all optimisations in the compiler, and I still got the error upon execution.
Additional info
typedef struct {
int height;
int width;
int bottom;//position of the bottom tube/slice boundary
unsigned int** dat_ptr;//a pointer to a 2d array
} array_info;
Where the dat_ptr
is now a proper 2D pointer. The create_array
function that creates the array that is to be put in the structure is (i have stripped NULL checks for readability):
int create_array(array_info *A)
{
int i;
unsigned int **array = malloc(sizeof(*array) * A->height);
for (i = 0; i < A->height; ++i)
{
array[i] = malloc(sizeof(**array) * A->width);
}
A->dat_ptr = array;
return 0;
}
This function works exactly as expected.
More Additional Info
Added after the responses of Jonathan, Chris, and rharrison33
Thank you so much, Jonathan, with every one of your posts I find out so much about programming :) I finally found the culprit. The code causing the exception was the following:
void fill_number(array_info* array, int value, int x1, int y1, int x2, int y2)//fills a rectangular part of the array with `value`
{
int i, j;
for(i=y1 ; ((i<=y2)&&(i<array->height)) ; i++)//start seeding the values by row (as in vertically)
{
for(j=x1 ; ((i<=x2)&&(i<array->width)) ; j++)//seed the values by columns (as in horizontally)
{
array->dat_ptr[i][j]=value;
}
}
}
And ((i<=x2)&&(i<=array->width))
wasn't being evaluated as I expected (Chris Dodd, you were right). I thought that it would evaluate both conditions in that order or stop if either was "FALSE", independent of their order. However, it turned out it didn't work that way and it was simply refusing to evaluate the (i<array->width)
part correctly. Also, I assumed that it would trigger an exception upon trying to access memory outside of the array range, but it didn't. Anyway,
I changed the code to:
void fill_number(array_info* array, int value, int x1, int y1,
int x2, int y2)
{
int i, j;
if(y1>=array->height){ y1=array->height-1;}
if(y2>=array->height){ y1=array->height-1;}
if(x1>=array->width) { x2=array->width-1;}
if(x2>=array->width) { x2=array->width-1;}
for(i=y1 ; i<=y2 ; i++)//start seeding the values by row
{
for(j=x1 ; j<=x2 ; j++)//seed the values by column
{
array->dat_ptr[i][j]=value;
}
}
}
And now it works. The block of if()
s is there because I won't be calling the function very often compared to the rest of the code and I need a visual way to remind me that the check is there.
Again, thank you so much Jonathan Leffler, Chris Dodd, and rharrison33 :)