# dynamic 2D array allocation

This is a discussion on dynamic 2D array allocation within the C Programming forums, part of the General Programming Boards category; So I am revisting some of my old code and I was creating 2D array dynamically in 2 different ways: ...

1. ## dynamic 2D array allocation

So I am revisting some of my old code and I was creating 2D array dynamically in 2 different ways:
Code:
```double **allocate_array(int row_dim, int col_dim){
double **result;
int i;
result=(double **)calloc(row_dim,sizeof(double *));
result[0]=(double *)calloc(row_dim*col_dim,sizeof(double));
for(i=1; i<row_dim; i++)
result[i]=result[i-1]+col_dim;
return result;
}
double **trainset;
trainset=allocate_array(5,5);```
This way works fine but it appears I over dimensionalize it(I can access trainset[1][100]).
And its really weird what is going on here, creating a pointer to an x*y array in the first array cell and then pointers to the start of each "row". I have no idea how C resolves a 2D call i.e. trainset[1][1].

Also in the same program I used an inline method, that i tried putting into the allocate_array function instead of the first method:
Code:
```double **allocate_array(int row_dim, int col_dim){
double **result;
int i;
result = (double **) calloc(row_dim,sizeof(double));
for(i=0;i<=row_dim;i++)
result[i]=(double *) calloc(col_dim,sizeof(double));
return result;
}
double **trainset;
trainset=allocate_array(5,5);```
But again the dimensions are off as I can access trainset[1][10000], and seg fault only at like trainset[1][1000000].

Not sure if I should just ignore the over declaration and go with it, but its bugging me that I don't know what is going on. Its also strange that I can access trainset[5][1], which is the 6th and potentially non-existant, but its seg faults at trainset[6][1].

2. Just because you don't (yet) segfault doesn't mean you own the memory, it just means you haven't walked off the end of the machine yet.

Since trainset is a double**, trainset[1] corresponds to a double* (specifically, the second double* you allocated with that first calloc in your code). Then double[1][1] is the double just past the double pointed to by trainset[1][1] (trainset[1][0] would be the double pointed to).

3. Originally Posted by deprekate
But again the dimensions are off as I can access trainset[1][10000], and seg fault only at like trainset[1][1000000].
Both times, you're invoking undefined behaviour.

One of the wonders of undefined behaviour is that anything is allowed to happen. That's what "undefined" is defined to mean in the C standard.

One of the possibilities in "anything" is that two instances of undefined behaviour - such as you have - can produce differing results or behaviour. And one of those two can appear to be correct.

4. In both cases you are getting lucky that the program does not segfault when you go out-of-bounds. The behavior is inconsistent and definitely not reproducible.
Originally Posted by deprekate
So I am revisting some of my old code and I was creating 2D array dynamically in 2 different ways:
Code:
```double **allocate_array(int row_dim, int col_dim){
double **result;
int i;
result=(double **)calloc(row_dim,sizeof(double *));
result[0]=(double *)calloc(row_dim*col_dim,sizeof(double));
for(i=1; i<row_dim; i++)
result[i]=result[i-1]+col_dim;
return result;
}
double **trainset;
trainset=allocate_array(5,5);```
This way works fine but it appears I over dimensionalize it(I can access trainset[1][100]).
And its really weird what is going on here, creating a pointer to an x*y array in the first array cell and then pointers to the start of each "row". I have no idea how C resolves a 2D call i.e. trainset[1][1].
The first calloc() sets aside memory for 5 pointers each of type double, casts the result to a double** pointer and points result at it. The second calloc() creates an array of 25 elements each of type double. It then sets each result[i] pointers to point to different locations of that array; for ex. result[0] points to the first element while result[1] points 5 elements beyond that.
Originally Posted by deprekate
Also in the same program I used an inline method, that i tried putting into the allocate_array function instead of the first method:
Code:
```double **allocate_array(int row_dim, int col_dim){
double **result;
int i;
result = (double **) calloc(row_dim,sizeof(double));
for(i=0;i<=row_dim;i++)
result[i]=(double *) calloc(col_dim,sizeof(double));
return result;
}
double **trainset;
trainset=allocate_array(5,5);```
But again the dimensions are off as I can access trainset[1][10000], and seg fault only at like trainset[1][1000000].

Not sure if I should just ignore the over declaration and go with it, but its bugging me that I don't know what is going on. Its also strange that I can access trainset[5][1], which is the 6th and potentially non-existant, but its seg faults at trainset[6][1].
Again you are getting lucky, this doesn't mean it will happen all the time so don't count on it.

5. Thanks for all the replies/help. So it appears I am allocating the correct way? but when I run something unexpected(line2[1][100000]) I am jsut getting a random event idiosyncracy?
So basically keep it the way it is as long as I use only those dimensions I allocated?

6. Originally Posted by deprekate
Thanks for all the replies/help. So it appears I am allocating the correct way? but when I run something unexpected(line2[1][100000]) I am jsut getting a random event idiosyncracy?
So basically keep it the way it is as long as I use only those dimensions I allocated?
What happens when you cross the road when you have a red light? It is not defined - you MAY have an accident with someone coming the other direction - but not every time. It is UNDEFINED - but you are certainly not guaranteed to get across without risk.

The same applies to arrays and pointer dereference. The application will crash if you access memory that you should not access. But what is not defined is how far beyond what you allocated you can go - that will depend on the actual amount of memory allocated by the C library - it may decide to allocate a megabyte at a time in it's bottom layer, and than dole out the smaller portions as needed. It may also allocate exactly what you asked for, or rounded up to the next 4K, 64K or 2GB limit - it is up to the OS and C library to decide such things. If you allocate (say) 200MB, and then free it, the next allocation of 1 byte, you can go 199.99MB beyond that and still have a good amount of memory that is "accessible", because there is 200MB of accessible memory at that time.

--
Mats