I would like to create a dynamic array which store permutation sequence, such that
order[0][]={1,2,3}
order[1][]={2,1,3}
order[2][]={2,3,1}
Source Code:
The code will be something like:
#include <stdlib.h>
int **array;
array = malloc(nrows * sizeof(int *));
if(array == NULL)
{
fprintf(stderr, "out of memory\n");
/*exit or return*/
}
for(i = 0; i < nrows; i++)
{
array[i] = malloc(ncolumns * sizeof(int));
if(array[i] == NULL)
{
fprintf(stderr, "out of memory\n");
/*exit or return*/
}
}
Concept:
array
is a pointer-to-pointer-to-int: at the first level, it points to a block of pointers, one for each row. That first-level pointer is the first one to be allocated; it has nrows
elements, with each element big enough to hold a pointer-to-int
, or int *
. If the allocation is successful then fill in the pointers (all nrows
of them) with a pointer (also obtained from malloc
) to ncolumns
number of ints, the storage for that row of the array.
Pictorial Depiction:
It is simple to grasp if you visualize the situation as:
Taking this into account, the sample code could be rewritten as:
void permute(int num_permute, int num_term, int** order) {
int x, y;
int term[5];
int* ptr = NULL;
for (y=num_term, x=0; y>0; y--, x++) {
term[x] = y;
}
printf("\n");
printf("order%12c", ' ');
for (x=0; x<num_permute; ++x) {
printf(" %2d ", x);
}
printf("\n");
for (y=0; y<num_permute; y++) {
ptr = order[y];
memcpy(ptr, term, sizeof(term));
printf("%-5d%12p", y, ptr);
for (x=0; x<num_term; x++) {
printf(" %2d ", ptr[x]);
}
printf("\n");
}
}
int main() {
int y, z;
int** x = NULL;
int num_term = 5;
int num_permutation = 5;
int* pchk = NULL;
x = (int**) malloc(num_permutation * sizeof(int*));
for (y=0; y<num_permutation; y++){
x[y] = (int*) malloc(num_term * sizeof(int));
printf("x[%d]: %p\n", y, x[y]);
}
permute(num_permutation, num_term, x);
printf("\nx: ");
for(z=0; z<5; z++){
printf(" %2d ", z);
}
printf("\n");
for(y=0; y<num_permutation; y++){
pchk = x[y];
printf("%-4d", y);
for(z=0; z<num_term; z++){
printf(" %2d ", pchk[z]);
}
printf("\n");
}
for (y=0; y<num_permutation; y++) {
free(x[y]);
}
free(x);
return 0;
}
The code sample only simulates a multidimensional array, and does it incorrectly. To see what's going wrong, start by considering what happens when you declare a multidimensional array:
int foo[3][5];
This allocates a contiguous region of memory of size 3*5*sizeof(int). In an expression such as foo[i]
, the foo
is converted to a int [5]
pointer, then the index operator is applied. In other words, foo[i]
is equivalent to *( (int (*)[5])foo) + i)
. Each foo[i]
would be considered as having size 5*sizeof(int).
x,y: 0,0 0,1 0,2 0,3 0,4 1,0 foo --> | 1 | 2 | 3 | 4 | 5 | 1 |... <- 5 * sizeof(int) ->
When you create x
in the sample code, you're replicating this type of multidimensional array. The index expression you're using (*(order + y + x)
) is thus wrong, as it doesn't properly handle the size of order[y]
: order + 1 + 0 == order + 0 + 1
, which is the problem you're seeing in the sample output.
The correct expressions are: (order + num_term * y)
for the yth permutation and *(order + num_term * y + x)
for element order[y][x]
.
This suggests another class of error in the sample. For this kind of simulated multidimensional array, the array types are actually pointers to single dimensional arrays. The declared types of x
and order
should be int*
, not int**
. This should be reinforced by the type warnings the sample code should generate:
x
, the type of the pointer (int*
) doesn't match the type of x
x
, the type of *(x+y+z)
doesn't match the format "%d".However, while simulating a multidimensional array saves space, it's more error prone when used (unless you write a function to handle indexing). A solution such as Als' may be safer, as you can use the standard indexing operator.
Emulating a 2D array with pointer arrays is a complete overkill if you have C99 (or C11). Just use
void permute(size_t num_permute, size_t num_term, unsigned order[][num_term]);
as your function signature and allocate your matrix in main
with something like
unsigned (*order)[m] = malloc(sizeof(unsigned[n][m]));
Also, as you can see in the examples above, I'd suggest that you use the semantically correct types. Sizes are always best served with size_t
and your permutation values look to me as if they will never be negative. Maybe for these you also should start counting from 0
.
The following code snippet creates a 2d matrix for a given row and column. Please use this as a reference to debug your program.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int row, column;
int **matrix;
int i, j, val;
printf("Enter rows: ");
scanf("%d", &row);
printf("Enter columns: ");
scanf("%d", &column);
matrix = (int **) malloc (sizeof(int *) * row);
if (matrix == NULL) {
printf("ERROR: unable to allocate memory \n");
return -1;
}
for (i=0 ; i<row ; i++)
matrix[i] = (int *) malloc (sizeof(int) * column);
val=1;
for (i=0 ; i<row ; i++) {
for (j=0 ; j<column; j++) {
matrix[i][j] = val++;
}
}
for (i=0 ; i<row ; i++) {
for (j=0 ; j<column; j++) {
printf("%3d ", matrix[i][j]);
}
printf("\n");
}
return 0;
}
/*
Allocation of 2d matrix with only one call to malloc and
still get to access the matrix with a[i][j] format
the matrix is divided into headers and data.
headers = metadata to store the rows
data = actual data storage - buffer
allocate one contigious memory for header and data
and then make the elements in the header to point to the data are
<- headers -----><----------- data -----------
-----------------------------------------------------------------
| | | | | | .. |
| | | | | | .. |
-----------------------------------------------------------------
| ^
| |
|-----------------|
header points to data area
*/
/*
Output:
$ gcc 2darray.c
$ ./a.out
Enter rows: 10
Enter columns: 20
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 153 154 155 156 157 158 159 160
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
$
*/