I am trying to flip an image in C vertically so if the image is < it will end up > and my function includes
//Setting the struct up for the pixel's
struct pixel
{
unsigned char red;
unsigned char green;
unsigned char blue;
};
//Setting the struct up for the Image Type and scanning in the pxiels into an array
struct ImageType
{
char ppImage[3];
char comment[256];
char newlinechar;
int width, height;
int maxColor = 255;
struct pixel image[100][100];
};
//Function in order to flip the image, going from the left most pixel flipping with the right most
void MirrorVertical(struct ImageType imgur)
{
int x,y;
const int middle = imgur.width / 2;
struct pixel tmp;
struct *pixel p;
for(y=0; y < imgur.height; ++y)
{
p = tmp + y * imgur.width;
for(x=0; x < middle; ++x)
{
tmp = p[x];
p[x] = p[imgur.width - 1 - x];
p[imgur.width - 1 - x] = tmp;
}
}
}
I got my structs to work but for some reason my function will not output it, I am scanning in the image into from a struct so....
//Scanning in the pixels for the first image
for(i=imageA.height-1; i <= 0; i--)
{
for(j=0; j < imageA.width; j++)
{
scanf("%hhu", &imageA.image[i][j].red);
scanf("%hhu", &imageA.image[i][j].green);
scanf("%hhu", &imageA.image[i][j].blue);
}
}
What am I doing wrong in my function?
It should be
for(x=0; x < width; x++)
{
for(y = 0; y < height/2; y++)
{
temp = imgur.image[x][y];
imgur.image[x][y] = imgur.image[x][height-y-1]
imgur.image[x][height-y-1] = temp;
}
}
}
Shouldn't this: for(i=imageA.height-1; i <= 0; i--) be for(i=imageA.height-1; i >= 0; i--)? (in the "scanning in the pixels for the first image" code)
I imagine your compiler must be complaining about
struct pixel tmp;
struct *pixel p;
for(y=0; y < imgur.height; ++y)
{
p = tmp + y * imgur.width;
You are adding a struct to an int and allocating the result to a pointer. How is it supposed to work?
EDIT now that you have updated your question with "better" code and it's still not working, here are a few things you could / should change.
You declare a variable tmp then try to access temp. Recipe for failure
You pass the entire struct imgur to the function. That means "make a copy of everything". You should really pass a pointer to the object - change the prototype to reflect that, and access the elements as imgur->height etc
You never declare the variables height and width in your MirrorVertical function
(minor) you compute the value height - 1 - y twice per inner loop - 20000 times in total. If you swap the inner and outer loops and compute it just once (and assign to a new variable newY) you can save a little bit of time (not sure it it's really more efficient since you end up looping over X which might destroy cache coherence instead, especially with big images).
My compiler (and the C standard) complains about the statement int maxColor = 256; in the definition of the struct; you cannot initialize a value in the typedef.
Miscellaneous other errors thrown by the compiler.
I took the liberty of fixing many of them - that leads to the following code which appears to compile and run; now all you need is add your "input image" and "output image" functions (maybe).
#include <stdio.h>
//Setting the struct up for the pixels
struct pixel
{
unsigned char red;
unsigned char green;
unsigned char blue;
};
//Setting the struct up for the Image Type and scanning in the pixels into an array
struct ImageType
{
char ppImage[3];
char comment[256];
char newlinechar;
int width;
int height;
int maxColor; // cannot initialize this here; removed "=256"
struct pixel image[100][100];
};
//Function in order to flip the image, going from the left most pixel flipping with the right most
void MirrorVertical(struct ImageType *imgur) // using a pointer to the struct
{
int x,y, height, width; // added declaration of height, width
// const int middle = imgur->width / 2; // removed, not used
struct pixel tmp; // use same name here and in loop
height = imgur->height; // initialize once - save a redirect later
width = imgur->width; // ditto
for(y = 0; y < imgur->height/2; y++) // made this the outer loop
{
int newY = height - y - 1; // so we only compute it once
for(x=0; x < imgur->width; x++)
{
tmp = imgur->image[x][y]; // use "tmp" not "temp"
imgur->image[x][y] = imgur->image[x][newY];
imgur->image[x][newY] = tmp;
}
}
}
// a simple main program… this doesn't really do anything except call the function
int main(void) {
struct ImageType i1;
// … need to add code to import the image
MirrorVertical(&i1); // note - passing POINTER to i1, not the entire struct
// … need to add code to export the image
}
Let me know if that works.
Related
I have written some serial code which I would like to optimise as much as possible before I parallelise it using OpenMP. The program reads in a PPM file by iterating through the pixel data in 4x4 cells (variable c), then it finds the average RGB value of each of those 4x4 cells, and then finally writes to a new file by outputing the average colour value, again of each of the 4x4 cells. This creates a sort of mosaic/pixelation effect.
Having performance profiled my code, the main bottlenecks are fscanf and fprintf. I am ignoring execution time to read/write to disk, so these two functions do not matter.
My effort to optimise so far:
Loop jamming: There are two nested FOR loops within the code which have the exact same loop conditions. However, the second set of nested FOR loops requires that the functions needed to calculate the average RGB value are kept outside of that specific set. The average RGB value calculations are then needed for use in the third set of nested FOR loops (which have the same loop conditions as the second set). Because of this, I have struggled to combine the second and third sets of nested FOR loops despite their similarity.
Loop invariant computations: I have tried to move certain operations outside of the loop where possible, but this has proven to be difficult.
To summarise: How can I optimise this program to reduce the execution time as much as possible?
My code:
typedef struct { //struct holding RGB type int
int r, g, b; //12 bytes
} pixelInt;
typedef struct { //struct holding RGB type unsigned char
unsigned char r, g, b; //3 bytes
} pixel;
int c = 4; // Variable of 4x4 grids
int width, height; //image variable declarations
//Raw 1 dimensional store of pixel data - will contain all the data for each pixel in the image
pixel *data = (pixel *)calloc(width * height, sizeof(pixelInt));
//Loop through entire input image
for (int yy = 0; yy < height; yy += c)
{
for (int xx = 0; xx < width; xx += c)
{
//the total colour of cell of size 'c'
pixelInt cell_tot = { 0, 0, 0 }; //zero initialize struct containing mosaic cell pixel totals.
unsigned int counter = 0; //the counter for how many pixels are in a 4x4 cell
int bx = xx + c; //used in loop conditions
int by = yy + c;
// Store each color from the cell into cell_tot struct
for (int y = yy; y < by; y++)
{
for (int x = xx; x < bx; x++)
{
unsigned int index_1d = x + y * width; //calculate 1d index from x-index (x), y-index(y) and width;
unsigned char r, g, b; //maximum vales are 255, i.e. unsigned char data type
fscanf(f, "%hhu %hhu %hhu", &r, &g, &b); //%hhu is unsigned char specifier
//store the pixel value into data array
data[index_1d].r = r;
data[index_1d].g = g;
data[index_1d].b = b;
counter++; //increment counter
//average pixel color of cell
cell_tot.r += r;
cell_tot.g += g;
cell_tot.b += b;
}
}
//average colour of cell found by dividing cell total by loop counter
pixel cell_average;
cell_average.r = cell_tot.r / counter;
cell_average.g = cell_tot.g / counter;
cell_average.b = cell_tot.b / counter;
//Loop through the new image in cells of size c
for (int y = yy; y < by; y++)
{
for (int x = xx; x < bx; x++)
{
unsigned int index_1d = x + y * width; //calculate 1d index from x-index (x), y-index(y) and width;
//Assign average cell value to the pixels in the cell
data[index_1d].r = cell_average.r;
data[index_1d].g = cell_average.g;
data[index_1d].b = cell_average.b;
//Output the average colour value for the image
fprintf(f_output, "%hhu %hhu %hhu \t", data[index_1d].r, data[index_1d].g, data[index_1d].b);
}
fprintf(f_output, "\n"); //Prints new line
}
}
}
On a 1024x1024 image on my machine your code executes in 0.325s. The following code executes in 0.182s:
unsigned w = width/c, h = height/c;
unsigned *accum = (unsigned*)malloc(3*sizeof(unsigned)*w);
char *line = (char*)malloc(12*w);
unsigned denom = c*c;
//Loop through entire input image
for (int yy = 0; yy < h; ++yy)
{
memset(accum, 0, 3*sizeof(unsigned)*w);
// read and accumulate c lines
for(int y = 0; y < c; ++y)
{
for (int xx = 0; xx < w; ++xx)
{
for (int x = 0; x < c; ++x)
{
unsigned char r, g, b;
fscanf(f, "%hhu %hhu %hhu", &r, &g, &b);
accum[3*xx+0] += r;
accum[3*xx+1] += g;
accum[3*xx+2] += b;
}
}
}
// format a line
for(int xx = 0; xx < w; ++xx)
{
char *cell = line + 12*c*xx;
snprintf(cell, 12, "%3u%4u%4u", accum[3*xx]/denom, accum[3*xx+1]/denom, accum[3*xx+2]/denom);
cell[11] = '\t';
for(int x = 1; x < c; ++x)
memcpy(cell + 12*x, cell, 12);
}
// write it out times c
line[12*w-1] = '\n';
for(int y = 0; y < c; ++y)
fwrite(line, 12*w, 1, f_output);
}
The trick here is to format the averaged values only once and then duplicate the formatted strings. Also by acting on one row at a time I have better chances of utilizing the memory caches.
To go beyond that you would need to re-implement the fscanf to parse the integers faster.
I have a school project related to bmp and im a bit stuck with the dynamic allocation aspect of things(as I have been asked to use that).
What im trying to do is pass my array using a pointer, so that the array changes its value even after the function ends,which is why i used **. However, the code just ends up crashing because of this single bit(as without it it runs smoothly).Im sure it's my use of * and & incorrectly but I don't know where and how to fix it.
typedef struct pixel{unsigned int r,g,b;}pixel;
void liniarizare(char *filename,pixel **liniar)
{int i;
... (i calculate size which is surely correct and declare fin;size=width*height*sizeof(pixel)
*liniar=(pixel*)malloc(size);
for (i=0;i<width*height;i++)
{fread(&liniar[i]->b,1,1,fin);
fread(&liniar[i]->g,1,1,fin);
fread(&liniar[i]->r,1,1,fin);
}
}
...
int main()
{...
pixel *liniar
liniarizare(filename,&liniar);
....}
Note that this is prefaced by my top comments.
That is, have the function return pixel *. And, use an extra unsigned char variable to prevent reading a byte into an unsigned int
Here's a simplified version that I think should work:
typedef struct pixel {
unsigned int r;
unsigned int g;
unsigned int b;
} pixel;
pixel *
liniarizare(char *filename)
{
int i;
int count = width * height;
int size = sizeof(pixel) * count;
pixel *liniar = malloc(size);
pixel *pix = liniar;
unsigned char byte;
for (i = 0; i < count; ++i, ++pix) {
fread(&byte,1,1,fin);
pix->b = byte;
fread(&byte,1,1,fin);
pix->g = byte;
fread(&byte,1,1,fin);
pix->r = byte;
}
return liniar;
}
int
main(void)
{
pixel *liniar;
liniar = liniarizare(filename);
return 0;
}
UPDATE:
Miraculously enough it works. The only problem is that i need to be able to pass the array by "reference" in the function and have the function provide back the modified array,which is why i insisted on using ** and a void. Do you have any idea what could be wrong in my code with your advice? You said something about linear[i]->b being wrong.
Okay, the simplest/best way to deal with a "return" double star argument (e.g.) whatever **retptr) is to ignore this as much as possible.
That is, the function deals with the simpler whatever *ptr internally. This is faster because there is only a single dereference level and not a double dereference on each statement.
The return value (i.e. the double star pointer) is only set at the end once.
Here's my example reworked to use your original function prototype [but with my other cleanup]. Note that only two lines are changed (the function prototype and the last line of the function):
typedef struct pixel {
unsigned int r;
unsigned int g;
unsigned int b;
} pixel;
void
liniarizare(char *filename,pixel **retval)
{
int i;
int count = width * height;
int size = sizeof(pixel) * count;
pixel *liniar = malloc(size);
pixel *pix = liniar;
unsigned char byte;
for (i = 0; i < count; ++i, ++pix) {
fread(&byte,1,1,fin);
pix->b = byte;
fread(&byte,1,1,fin);
pix->g = byte;
fread(&byte,1,1,fin);
pix->r = byte;
}
*retval = liniar;
}
int
main(void)
{
pixel *liniar;
liniarizare(filename,&liniar);
return 0;
}
Sometimes the "return value" pointer needs to be read at the top of a function and set at the bottom.
Here's a "push to tail" function for a singly linked list:
void
push(node **list,node *new)
{
node *head;
node *prev;
node *cur;
head = *list;
prev = NULL;
for (cur = head; cur != NULL; cur = cur->next)
prev = cur;
if (prev != NULL)
prev->next = new;
else
head = new;
new->next = NULL;
*list = head;
}
UPDATE #2:
Okay, now that we've got something working, it's time to optimize it [after a suitable rest period :-)].
Keep the now working version around as a reference/cross-check.
fread calls on single bytes are somewhat expensive.
Since your code is doing byte at a time I/O, we can replace the fread calls with fgetc. This should be slightly faster:
for (i = 0; i < count; ++i, ++pix) {
pix->b = fgetc(fin) & 0xFF;
pix->g = fgetc(fin) & 0xFF;
pix->r = fgetc(fin) & 0xFF;
}
However, we'd like to read as much as we can in single chunk. To read the entire image in one fread call would require a temp array of (e.g.) unsigned char image[count];. This is probably too much memory, and reading a large image might run into cache hit/miss issues.
But we could do a row at a time (e.g. unsigned char row[width * 3];). This is more tractable and probably produces as good or better results, so it may be a good compromise.
This may or may not be faster. That's why we keep the other versions around and benchmark to determine the fastest/best.
Note that this code assumes that pixels in the X dimension are physically adjacent [a reasonable possibility], but still works even if the matrix is transposed. In the end, it still reads count pixels in linear order, per your original code:
typedef struct pixel {
unsigned int r;
unsigned int g;
unsigned int b;
} pixel;
void
liniarizare_by_row(char *filename,pixel **retval)
{
int i;
int yidx;
int count = width * height;
int size = sizeof(pixel) * count;
int w3 = width * 3;
pixel *liniar = malloc(size);
pixel *pix = liniar;
unsigned char row[w3];
for (yidx = 0; yidx < height; ++yidx) {
fread(row,sizeof(row),1,fin);
for (i = 0; i < w3; i += 3, ++pix) {
pix->b = row[i + 0];
pix->g = row[i + 1];
pix->r = row[i + 2]
}
}
*retval = liniar;
}
int
main(void)
{
pixel *liniar;
pixel *liniar_fast;
liniarizare(filename,&liniar);
liniarizare_fast(filename,&liniar_fast);
return 0;
}
I have the following structure im using to encode a PPM file with a message using steganography:
typedef struct{
char code[CODE_LENGTH];
COMMENT *commentPPM;
int width, height, max;
COLOR (*colorValues)[];
} PPM;
and the color:
typedef struct{
unsigned char red, green, blue;
} COLOR;
and method:
PPM *encode(char *text, PPM *img){
//tested
printf("entered encode\n");
PPM *newPPM;
newPPM = duplicate(img);
printf("duplicated ppm\n");
int x,y, currentChar, textLength;
textLength = strlen(text);
////
for(currentChar = x = y = 0; currentChar < textLength; currentChar++){
printf("the current character is %c\n", *(text+currentChar));
//between 1 and the width
x += (rand() % (newPPM->width -1)) + 1;
printf("generated %d for x\n",x);
if(x >= newPPM->width){
printf("%d is greater than width(%d)\n",x,newPPM->width);
x -= newPPM->width;
printf("%d is the new x\n", x);
y++;
printf("incremented y to be %d\n", y);
}
newPPM->colorValues[y][x].red = text[currentChar]; //error (1)
printf("changed the value of color[%d][%d].red, to be %d, which is %c\n",y,x, text[currentChar], text[currentChar]);
}
return newPPM;
}
How do you access for example "red" within the pointer to the 1d array seen at (1)?
Edit: I get the error message:
"error: invalid use of array with unspecified bounds
newPPM->colorValues[y][x].red = text[currentChar];"
Edit 2: I'm hearing that I cannot access the elements of colorValues in
typedef struct{
char code[CODE_LENGTH];
COMMENT *commentPPM;
int width, height, max;
COLOR (*colorValues)[];
} PPM;
as it hasn't got the width specified so i cant determine the offset. However I this is just a pointer to a flexible array member is getting assigned a type
ppmFile->colorValues = getColors(fd, ppmFile->width, ppmFile->height);
COLOR (*getColors(FILE *fd, int width, int height))[]{
COLOR (*colors)[width] = (COLOR(*)[width]) malloc(sizeof(COLOR[height][width]));
int i,j;
for(i = 0; i < height; i++) {
for(j = 0; j < width; j++) {
fscanf(fd,"%d %d %d", &colors[i][j].red, &colors[i][j].green, &colors[i][j].blue);
}
}
return colors;
}
which has got the width specified. So if I'm understanding correct when I am passing this back to be stored in the struct i am "losing" the offset (width). However When I am in the encrypt method, I have access to the width, height, and current x and y positions, surely there is a way of telling the compiler that this flexible array member has the offset of width,I did do this in the printColors method and it worked fine (see bellow), why cant I tell the compiler that the values stored in newPPM->colorValues have the offset of width?
void printColors(int width, int height, COLOR (*colors)[width]){
int n, j;
for(n = 0; n < height; n++) {
for(j = 0; j < width; j++) {
printf("%d %d %d\n", colors[n][j].red, colors[n][j].green, colors[n][j].blue);
}
}
}
is there a way of casting the newPPM->colorValues to tell it to have the offset width? Like I did with colors in printColors
You're probably getting an error like:
prog.c:10:14: error: subscript of pointer to incomplete type 'struct foo []'
thing->foos[0][0].bar;
~~~~~~~~~~~^
1 error generated.
For reference, the above is the output of compiling this code:
struct foo { int bar; };
struct baz {
struct foo (*foos)[];
};
int main () {
struct baz * thing;
thing->foos[0][0].bar;
return 0;
}
(Live)
What the compiler is trying to tell you is that it cannot compute the offset needed to access subsequent elements of the outer array. The reason is that it doesn't know the size of the array elements (as they're of incomplete type, that is lacking size information).
Basically, it's trying to compute (the following is a pseudo language, not C)
thing + offset(foos) + 0 * sizeof(struct foo[]) + 0 * sizeof(struct foo) + offset(bar)
but it can't because it doesn't know sizeof(struct foo[]).
The root of this issue is that your trying to have a pointer to a variable length array in the first place. Changing the member to
struct foo (*foos)[42];
"solves" this by giving the arrays dome size.
If you want a 2D array just make it 1D, appending all inner arrays. (Of course this works only if they're of the same size, i.e. if you want a rectangular 2D array)
struct foo * grid = malloc (sizeof (struct foo) * rows * columns);
// access using grid [c * rows + r]
You can access 2D data in a 1D array by calculating the array index formula yourself.
buf[ width*y + x ];
where width needs to be the stride in units of the buffer type.
I want to show how stack is allocated through pointers on struct, union, array
I just have no clue how to approach. The following is my try.
// to check the boundary
char *minimum_pointer, *maximum_pointer ;
// to check marked
void markmark(char *x, int size, char marking_address) {
minimum_pointer = x;
maximum_pointer = minimum_pointer + size;
// is this correct?
// I am trying to place marking_address
// to every byte of x
if (*minimum_pointer>marking_address || *maximum_pointer<marking_address) {
printf("%s \n", "out of boundary");
}
int number_of_array_element = size/sizeof(char);
for (int i=0; i<number_of_array_element; i++) {
if (&x[i] >= minimum_pointer && &x[i] <= maximum_pointer) {
x[i] = marking_address;
// am I doing this right?
// I need to place the address to every byte of input x
}
}
}
int main(int argc, const char * argv[]) {
struct structure_example {
char* a ;
char b[20] ;
float c ;
} str_ex;
markmark((char *) &str_ex, sizeof(str_ex), 0xa1);
union union_example {
float a ;
char b ;
int c ;
} uni_ex;
markmark((char *) &uni_ex, sizeof(uni_ex), 0xa2);
char arr_ex[50] ;
markmark((char *) &arr_ex, sizeof(arr_ex), 0xa3);
return 0;
}
My question is
maximum_pointer = minimum_pointer + size;
// is this correct?
// I am trying to place marking_address
// to every byte of x
And another question is
int number_of_array_element = size/sizeof(char);
for (int i=0; i<number_of_array_element; i++) {
if (&x[i] >= minimum_pointer && &x[i] <= maximum_pointer) {
x[i] = marking_address;
// am I doing this right?
// I need to place the address to every byte of input x
}
}
What is confusing me is that
how and what do I need to initialize the struct and union and array.
Thanks,
if you want the address of the stack then minimum_pointer = x is not correct, that would only make minimum_pointer point to the same thing x points to i.e.
char* p = "42";
markmark(p, ...
it doesn't say anything about the stack, you need to take the address of x instead
minimum_pointer = &x;
i think if you look in the standard header file stdarg.h you can get some hints how to work with the stack.
I'm having some trouble with the realloc function.
I'm allocating a dynamic bidimensional array with this function:
Bubble ***allocBubblesMatrix(int height, int width) {
Bubble ***bubblesMatrix = (Bubble***) malloc(height * sizeof(Bubble**));
assert(bubblesMatrix != NULL);
int i;
for (i = 0; i < height; ++i) {
bubblesMatrix[i] = (Bubble**) malloc(width * sizeof(Bubble*));
assert(bubblesMatrix[i] != NULL);
}
int x, y;
for (y = 0; y < height; ++y)
for (x = 0; x < width; ++x)
bubblesMatrix[y][x] = newBubble(rand() % N_BUBBLES);
return bubblesMatrix;
}
wich is called with the next code:
int matrixHeight = 1,
matrixWidth = MATRIX_X_SIZE;
Bubble ***bubblesMatrix = allocBubblesMatrix(matrixHeight, matrixWidth);
This successfuly creates a bidimensional array 1* MATRIX_X_SIZE.
Then, I want to add a row or multiple rows to the matrix, so I use realloc with the following function. It's supposed to add heightIncrement rows. The problem is that sometimes it works, other it crashes de program.
void resizeBubblesMatrix(Bubble ****bubblesMatrix, int height, int width,
int heightIncrement) {
if (heightIncrement <= 0) /* temporary */
return;
*bubblesMatrix = (Bubble***) realloc(*bubblesMatrix, (height + heightIncrement) * sizeof(Bubble**));
assert(bubblesMatrix != NULL);
int x, y;
int newHeight = height + heightIncrement;
for (y = height; y < newHeight; ++y) {
(*bubblesMatrix)[y] = (Bubble**) malloc(width * sizeof(Bubble*));
assert((*bubblesMatrix)[y] != NULL);
for (x = 0; x < width; ++x)
(*bubblesMatrix)[y][x] = newBubble(rand() % N_BUBBLES);
}
}
This function is called with:
while(true) {
drawBubblesMatrix(x1, y1, matrixHeight, matrixWidth, &bubblesMatrix, bubbles);
resizeBubblesMatrix(&bubblesMatrix, matrixHeight, matrixWidth, 1);
++matrixHeight;
getch();
clear_screen(1);
}
What am I doing wrong?
Function to deallocate the memory blocks previously allocated:
void freeBubblesMatrix(Bubble ****bubblesMatrix, int height, int width) {
int y, x;
for (y = 0; y < height; ++y) {
for (x = 0; x < width; ++x) {
free((*bubblesMatrix)[y][x]);
(*bubblesMatrix)[y][x] = NULL;
}
free((*bubblesMatrix)[y]);
(*bubblesMatrix)[y] = NULL;
}
free(*bubblesMatrix);
*bubblesMatrix = NULL;
}
Thanks in advance.
EDIT
Silly me. I wasn't doing anything with the return value of realloc as the Karl Knechtel pointed out. But now the program crashes whenever I run it.
With Bart van Ingen Schenau's answer, I confirmed what I feared: I was ignoring the several independent memory blocks that I had allocated previously. I even ended up with a similar code to the one written by Bart but it continues to crash the program.
I've added the assert's to check the results of the malloc/realloc calls and yet I didn't have any luck. I'm using djgpp with Win98 and what's happening it's really odd:
Windows: Sometimes, it never crashes; others, it crashes after adding 2 rows.
MS-DOS: Crashes after adding 2 rows.
I'm gonna try to use -O3 with gcc to get additional clues. What would be a useful (and quick to learn/use) memory corruption/leak detection tool for windows? Is Purify the best solution?
Even my function to free the array is returning page faults.
Read the documentation:
The function may move the memory block to a new location, in which case the new location is returned.... A pointer to the reallocated memory block, which may be either the same as the ptr argument or a new location.
The type of this pointer is void*, which can be cast to the desired type of data pointer in order to be dereferenceable.
If the function failed to allocate the requested block of memory, a NULL pointer is returned, and the memory block pointed to by argument ptr is left unchanged.
You cannot correctly use realloc without doing something with the return value. Your code, right now, expects that realloc will always be able to reallocate the memory in such a way that the new block is in the same place. This is clearly impossible; the memory immediately after your array might be in use for something else.
There are a number of things wrong with your use of realloc.
You are passing the wrong pointer to realloc. You should pass the pointer you optained from malloc, which would be *bubblesMatrix.
The 'layout' of the matrices in your allocBubblesMatrix and resizeBubblesMatrix functions is different. In the alloc function, you allocate several independent memory blocks, but in the resize function, you treat it as one big block of memory. That will simply not work.
The correct usage would be:
void resizeBubblesMatrix(Bubble ****bubblesMatrix, int height, int width,
int heightIncrement) {
*bubblesMatrix = (Bubble ***) realloc(*bubblesMatrix, (height + heightIncrement) * sizeof(Bubble**));
int i;
int newHeight = height + heightIncrement;
for (i = height; i < newHeight; ++i)
(*bubblesMatrix)[i] = (Bubble**) malloc(width * sizeof(Bubble*));
int x, y;
for (y = height; y < newHeight; ++y)
for (x = 0; x < width; ++x)
(*bubblesMatrix)[y][x] = newBubble(rand() % N_BUBBLES);
}
But this function still has some issues:
Both malloc and realloc can fail, which is not taken into account here
If heightIncrement is negative, you have a memory leak in the resize function.
I threw together a quick test case, and I have come to the conclusion that the problem you are now experiencing is not in this block of code. I created a very simple test case that replaces the Bubble objects with ints. When I do this, the reallocation completes successfully without crashing. Here is my code:
#include <malloc.h>
#include <assert.h>
int myVal = 0xDEAD;
int ***allocBubblesMatrix(int height, int width);
void resizeBubblesMatrix(int ****bubblesMatrix, int height, int width,
int heightIncrement);
int main(int argc, char **argv)
{
int matrixHeight = 1, matrixWidth = 10;
int i = 0;
int ***matrix = allocBubblesMatrix(matrixHeight, matrixWidth);
for(i = 1; i < matrixWidth; i++)
resizeBubblesMatrix(&matrix, matrixHeight, matrixWidth, 1);
printf("Complete!\n");
}
int ***allocBubblesMatrix(int height, int width) {
int ***bubblesMatrix = (int***) malloc(height * sizeof(int**));
assert(bubblesMatrix != NULL);
int i;
for (i = 0; i < height; ++i) {
bubblesMatrix[i] = (int**) malloc(width * sizeof(int*));
assert(bubblesMatrix[i] != NULL);
}
int x, y;
for (y = 0; y < height; ++y)
for (x = 0; x < width; ++x)
bubblesMatrix[y][x] = &myVal;
return bubblesMatrix;
}
void resizeBubblesMatrix(int ****bubblesMatrix, int height, int width,
int heightIncrement) {
if (heightIncrement <= 0) /* temporary */
return;
*bubblesMatrix = (int***) realloc(*bubblesMatrix, (height + heightIncrement) * sizeof(int**));
assert(bubblesMatrix != NULL);
int x, y;
int newHeight = height + heightIncrement;
for (y = height; y < newHeight; ++y) {
(*bubblesMatrix)[y] = (int**) malloc(width * sizeof(int*));
assert((*bubblesMatrix)[y] != NULL);
for (x = 0; x < width; ++x)
(*bubblesMatrix)[y][x] = &myVal;
}
}
The only changes I made were to replace Bubble with int, and to point all the entries in the matrix to a single int variable rather than doing even more allocation.
That means the error is either in drawBubblesMatrix() or in newBubble().
You need to reallocated each dimension separately. You cannot reallocate both dimensions at once, since each "row" was allocated individually.
*bubblesMatrix = (Bubble ***) realloc(bubblesMatrix, (height + heightIncrement) * width * sizeof(Bubble*));
needs to change to
*bubblesMatrix = (Bubble ***) realloc(*bubblesMatrix, (height + heightIncrement) * sizeof(Bubble**));