Multidimensional dynamic arrays & images (updated)

EDITED May 19th

This first set of code is a program that generates fractals to tga images, which I am trying to modify so that the image can be of any size (the pic array). To solve this I decided to use a char***, and dynamically allocate and deallocate the array.

The second set of code is a small program I wrote just to make sure that this solution would work on its own, before changing the actual proper program. In the second set of code it works fine, but when I put it into the proper program:

-the delete loop gives a seg fault
-the resultant image is junk

Now here's the actual problem that I came here to try and resolve:
Why does this allocation and deallocation work in my small program but not in the proper program? I cannot see what the difference could be.

-neither programs give compile errors
-the proper program works with non-dynamic char[][][] arrays fine
-both have width, height and the array pointer declared in the same scope.
-both use the same allocation/deallocation blocks
-both pass the array to functions in the same way

Am I incorrect on one of those points, or is it something else I am missing?

First set of code: the proper program itself:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include <iostream>
#include <fstream>
#include <math.h>
using namespace std;

const int width = 1024;
const int height = 768;
//const int width = 1024;
//const int height = 768;

bool outputFile(char***); //output the contents of pixel to a file
void calculatePixel(char***, int, double, double, int, int);
//should be passed: pic, iter, x, y, i, j //calculate the value of a single pixel

int main()
{
	double x,y; 
	double xstart,xstep,ystart,ystep;
	double xend, yend;
	int iter = 0; 
	long col = 0;
//	char pic[height][width][3]; //non dynamic pic
  	int i,j,k; 
  	int fd = 0;
	char*** pic; //dynamic pic

	// get data
	cout << "Enter xstart, xend, ystart, yend, iterations: " << endl;
	cin >> xstart >> xend >> ystart >> yend >> iter;

//START allocation block
	pic = new char**[height];
	
	for (int i=0; i < width; i++)
	{
		pic[i] = new char*[height];
		for (int a=0; a<height; a++)
			pic[i][a] = new char[3];
	}
//END allocation block

	// compute the step relative to the resolution of the image
  	xstep = (xend-xstart)/width;
  	ystep = (yend-ystart)/height;
  
	// do the calculation
  	x = xstart;
  	y = ystart;
  	for (i=0; i<height; i++)
  	{
    		for (j=0; j<width; j++)
    		{
    			calculatePixel(pic, iter, x, y, i, j);
      			x += xstep;
    		}
    		y += ystep;
    		x = xstart;
  	}
  	
  	
  	if ( !outputFile(pic) )
  	{
  		cerr << "file could not be written. terminating." << endl;
  		return 0;
  	}

//START deallocation block
	for (int i=0; i < height; i++)
	{
		for (int a=0; a<width; a++)
			delete pic[i][a];
		delete pic[i];	
	} 
	
	delete pic;
//END deallocation block
	return 0;
}

void calculatePixel(char*** pic, int iter, double x, double y, int i, int j) //calculates a single pixel
{
	double z,zi,newz,newzi;
	int inset = 0;
	double colour;

	z = 0;
      	zi = 0;
      	inset = 1;
      	for (int k=0; k<iter; k++)
      	{
		newz = (z*z)-(zi*zi) + x;
		newzi = 2*z*zi + y;
        	z = newz;
        	zi = newzi;
		if(((z*z)+(zi*zi)) > 4)
		{
			inset = 0;
			colour = k;
			k = iter;
		}
	}
	if (inset)
	{
		pic[i][j][0] = 0;
		pic[i][j][1] = 0;
		pic[i][j][2] = 0;
      	}
      	else
      	{	 
		pic[i][j][0] = (char) (colour / iter * 255);
		pic[i][j][1] = (char) (colour / iter * 255 / 2);
		pic[i][j][2] = (char) (colour / iter * 255 / 2);
      	}
}

bool outputFile(char*** pic) //writes image to a file, returns true on success
{
	char buffer[100] = {0};

	// create an output stream for the file

	ofstream ofs;
	ofs.open("image.tga", ios::out);

	if (ofs.fail())
	{
		cout << "Error Opening File" << endl;
		return false;
  	}

	// prepare the buffer for the TGA format.

  	buffer[0] = 0;
  	buffer[1] = 0;
  	buffer[2] = 2;
  	buffer[8] = 0; buffer[9] = 0;
  	buffer[10] = 0; buffer[11] = 0;
  	buffer[12] = (width & 0x00FF); buffer[13] = (width & 0xFF00) >> 8;
  	buffer[14] = (height & 0x00FF); buffer[15] = (height & 0xFF00) >> 8;
  	buffer[16] = 24;
  	buffer[17] = 0;

	// write the entire buffer out i.e. tga header

  	ofs.write((char*)buffer, 18);

	// now write the pic out which is stored in pic

  	ofs.write((char*)pic, width*height*3);
  	ofs.close();
  	return true;
}


Second set: This is the code that works (just to try out allocation and deallocation)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
using namespace std;

void foo(char***);

const int width = 1024;
const int height = 768;

int main()
{
	
	
//	cin >> width >> height;
	
	char *** pic;
	
//START allocation block
	pic = new char**[height];
	
	for (int i=0; i < height; i++)
	{
		pic[i] = new char*[width];
		for (int a=0; a<width; a++)
			pic[i][a] = new char[3];
	}
//END allocation block
	
	pic[12][13][1] = 'a';
	
	foo(pic);
	
	cout << pic[13][14][2] << endl;

//START deallocation block
	for (int i=0; i < height; i++)
	{
		for (int a=0; a<width; a++)
			delete pic[i][a];
		delete pic[i];	
	} 
	
	delete pic;
//END deallocation block
	return 0;
}

void foo(char*** pic)
{
	cout << pic[12][13][1] << endl;
	pic[13][14][2] = 'z';
}


note for original repliers: yes, it was rather stupid of me to try and solve this problem without posting all my source, but I wanted to avoid that originally.
Last edited on
I tried your code in VS 2010 and it did not crash.

Is this the working or not working code?
Why would you want to store an image inside a 3D array? Why not use a 2D array. Or is the idea here to have 3 images width and height stored into a 3D array?
Why would you want to store an image inside a 3D array? Why not use a 2D array. Or is the idea here to have 3 images width and height stored into a 3D array?


Probably height x width x rgb.

And from the first line it seems to be an assignment and not free choice ;-)
He never mentions anything to do with an assignment. He states it's just a program his made.
Also in the articles section Zatia has a post on 3D arrays:

http://cplusplus.com/forum/articles/7459/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#define HEIGHT 5
#define WIDTH 3
#define DEPTH 7

int main() {
  double ***p2DArray;

  // Allocate memory
  p2DArray = new double**[HEIGHT];
  for (int i = 0; i < HEIGHT; ++i) {
    p2DArray[i] = new double*[WIDTH];

    for (int j = 0; j < WIDTH; ++j)
      p2DArray[i][j] = new double[DEPTH];
  }

  // Assign values
  p2DArray[0][0][0] = 3.6;
  p2DArray[1][2][4] = 4.0;

  // De-Allocate memory to prevent memory leak
  for (int i = 0; i < HEIGHT; ++i) {
    for (int j = 0; j < WIDTH; ++j)
      delete [] p2DArray[i][j];

    delete [] p2DArray[i];
  }
  delete [] p2DArray;

  return 0;
}
My program crashes when using double matrix[][][]. Do I need the three * or what?
Also, which headers do you use?
In C and C++, a multidimensional array is really just a fancy way of indexing a unidimensional array. That is, the way to index an array is really something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
using namespace std;

void print( char *array, unsigned height, unsigned width )
  {
  for (unsigned h = 0; h < height; h++)
    {
    for (unsigned w = 0; w < width; w++)
      {
      // Here is the trick: this is pretty much the same as
      //   array[ h ][ w ]
      // where 'array' is
      //   char array[ height ][ width ]
      //
      cout << *(array + (h * width) + w);
      }
    cout << endl;
    }
  }

int main()
  {
  char greeting[ 2 ][ 6 ] =
    {
    { 'H', 'e', 'l', 'l', 'o', ',' },
    { 'w', 'o', 'r', 'l', 'd', '!' }
    };

  print( reinterpret_cast <char*> (greeting), 2, 6 );

  return 0;
  }

Every dimension is an additional multiplication. Given the array:

int x[ d1 ][ d2 ][ d3 ]

indexed as:

x[ i1 ][ i2 ][ i3 ]

is the same as:

*(x + (i1 * d2 * d3) + (i2 * d3) + i3)

Often, however, you can simplify it by simply using a base element pointer to iterate through the array. If you give more info on what you are trying to accomplish, perhaps I can help better.

Hope this helps.
I've edited the original post as I don't think I described it very well the first time.
Topic archived. No new replies allowed.