Finally if I want to dump the array, just:
int array[dim1][dim2]..;
A(array, dim1, dim2, dim3, dim4...);
Is it possible in C?
U开发者_开发技巧PDATE
How to define the type of array
in A(array, dim1, dim2, dim3, dim4...);
so that compiler won't give any warnings?
Yes
The call to A must indicate the number of dimensions, and provide the size of each dimension. Using some C99:
Code
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
extern void A(int *base, int ndims, ...);
extern void B(void);
void A(int *base, int ndims, ...)
{
assert(ndims > 0);
int dims[ndims];
int size = 1;
va_list args;
va_start(args, ndims);
for (int i = 0; i < ndims; i++)
{
dims[i] = va_arg(args, int);
size *= dims[i];
}
va_end(args);
int mods[ndims];
// I suspect this 'mods' loop is suboptimal, but it works.
for (int i = 0; i < ndims; i++)
{
int v = size;
for (int j = 0; j <= i; j++) {
v /= dims[j];
mods[i] = v;
}
}
for (int offset = 0; offset < size; offset++)
{
printf("%s", "array");
for (int i = 0; i < ndims; i++)
{
int p = offset / mods[i];
printf("[%d]", p % dims[i]);
}
printf(" = %d\n", base[offset]);
}
}
void B(void)
{
enum { dim1 = 4, dim2 = 6 };
int array1[dim1][dim2] =
{
{ 0, 1, 2, 3, 4, 5 },
{ 22, 21, 20, 19, 18, 17 },
{ 32, 31, 30, 39, 38, 37 },
{ 42, 41, 40, 49, 48, 47 },
};
int array2[dim2][dim1][dim2] =
{
{
{ 15, 68, 67, 16, 105, 4 },
{ 25, 58, 67, 16, 115, 4 },
{ 35, 48, 67, 16, 125, 4 },
{ 45, 38, 67, 16, 135, 4 },
},
{
{ 19, 69, 77, 16, 205, 5 },
{ 29, 59, 77, 16, 215, 5 },
{ 39, 49, 77, 16, 225, 5 },
{ 49, 39, 77, 16, 235, 5 },
},
{
{ 12, 64, 87, 16, 305, 6 },
{ 22, 54, 87, 16, 315, 6 },
{ 32, 44, 87, 16, 325, 6 },
{ 42, 34, 87, 16, 335, 6 },
},
{
{ 17, 63, 97, 16, 405, 7 },
{ 27, 53, 67, 16, 415, 7 },
{ 37, 43, 97, 16, 425, 7 },
{ 47, 33, 97, 16, 435, 7 },
},
{
{ 10, 60, 90, 10, 500, 97 },
{ 20, 50, 60, 20, 510, 87 },
{ 30, 40, 90, 30, 520, 77 },
{ 40, 30, 90, 40, 530, 67 },
},
{
{ 11, 63, 97, 36, 605, 39 },
{ 21, 53, 67, 46, 615, 38 },
{ 31, 43, 97, 56, 625, 27 },
{ 41, 33, 97, 66, 635, 26 },
},
};
A(&array1[0][0], 2, dim1, dim2);
putchar('\n');
A(&array2[0][0][0], 3, dim2, dim1, dim2);
}
int main(void)
{
B();
return(0);
}
Example output
array[0][0] = 0
array[0][1] = 1
array[0][2] = 2
array[0][3] = 3
array[0][4] = 4
array[0][5] = 5
array[1][0] = 22
array[1][1] = 21
array[1][2] = 20
array[1][3] = 19
array[1][4] = 18
array[1][5] = 17
array[2][0] = 32
array[2][1] = 31
array[2][2] = 30
array[2][3] = 39
array[2][4] = 38
array[2][5] = 37
array[3][0] = 42
array[3][1] = 41
array[3][2] = 40
array[3][3] = 49
array[3][4] = 48
array[3][5] = 47
array[0][0][0] = 15
array[0][0][1] = 68
array[0][0][2] = 67
array[0][0][3] = 16
array[0][0][4] = 105
array[0][0][5] = 4
array[0][1][0] = 25
array[0][1][1] = 58
array[0][1][2] = 67
array[0][1][3] = 16
array[0][1][4] = 115
array[0][1][5] = 4
array[0][2][0] = 35
array[0][2][1] = 48
array[0][2][2] = 67
array[0][2][3] = 16
array[0][2][4] = 125
array[0][2][5] = 4
array[0][3][0] = 45
array[0][3][1] = 38
array[0][3][2] = 67
array[0][3][3] = 16
array[0][3][4] = 135
array[0][3][5] = 4
array[1][0][0] = 19
array[1][0][1] = 69
array[1][0][2] = 77
array[1][0][3] = 16
array[1][0][4] = 205
array[1][0][5] = 5
array[1][1][0] = 29
array[1][1][1] = 59
array[1][1][2] = 77
array[1][1][3] = 16
array[1][1][4] = 215
array[1][1][5] = 5
array[1][2][0] = 39
array[1][2][1] = 49
array[1][2][2] = 77
array[1][2][3] = 16
array[1][2][4] = 225
array[1][2][5] = 5
array[1][3][0] = 49
array[1][3][1] = 39
array[1][3][2] = 77
array[1][3][3] = 16
array[1][3][4] = 235
array[1][3][5] = 5
array[2][0][0] = 12
array[2][0][1] = 64
array[2][0][2] = 87
array[2][0][3] = 16
array[2][0][4] = 305
array[2][0][5] = 6
array[2][1][0] = 22
array[2][1][1] = 54
array[2][1][2] = 87
array[2][1][3] = 16
array[2][1][4] = 315
array[2][1][5] = 6
array[2][2][0] = 32
array[2][2][1] = 44
array[2][2][2] = 87
array[2][2][3] = 16
array[2][2][4] = 325
array[2][2][5] = 6
array[2][3][0] = 42
array[2][3][1] = 34
array[2][3][2] = 87
array[2][3][3] = 16
array[2][3][4] = 335
array[2][3][5] = 6
array[3][0][0] = 17
array[3][0][1] = 63
array[3][0][2] = 97
array[3][0][3] = 16
array[3][0][4] = 405
array[3][0][5] = 7
array[3][1][0] = 27
array[3][1][1] = 53
array[3][1][2] = 67
array[3][1][3] = 16
array[3][1][4] = 415
array[3][1][5] = 7
array[3][2][0] = 37
array[3][2][1] = 43
array[3][2][2] = 97
array[3][2][3] = 16
array[3][2][4] = 425
array[3][2][5] = 7
array[3][3][0] = 47
array[3][3][1] = 33
array[3][3][2] = 97
array[3][3][3] = 16
array[3][3][4] = 435
array[3][3][5] = 7
array[4][0][0] = 10
array[4][0][1] = 60
array[4][0][2] = 90
array[4][0][3] = 10
array[4][0][4] = 500
array[4][0][5] = 97
array[4][1][0] = 20
array[4][1][1] = 50
array[4][1][2] = 60
array[4][1][3] = 20
array[4][1][4] = 510
array[4][1][5] = 87
array[4][2][0] = 30
array[4][2][1] = 40
array[4][2][2] = 90
array[4][2][3] = 30
array[4][2][4] = 520
array[4][2][5] = 77
array[4][3][0] = 40
array[4][3][1] = 30
array[4][3][2] = 90
array[4][3][3] = 40
array[4][3][4] = 530
array[4][3][5] = 67
array[5][0][0] = 11
array[5][0][1] = 63
array[5][0][2] = 97
array[5][0][3] = 36
array[5][0][4] = 605
array[5][0][5] = 39
array[5][1][0] = 21
array[5][1][1] = 53
array[5][1][2] = 67
array[5][1][3] = 46
array[5][1][4] = 615
array[5][1][5] = 38
array[5][2][0] = 31
array[5][2][1] = 43
array[5][2][2] = 97
array[5][2][3] = 56
array[5][2][4] = 625
array[5][2][5] = 27
array[5][3][0] = 41
array[5][3][1] = 33
array[5][3][2] = 97
array[5][3][3] = 66
array[5][3][4] = 635
array[5][3][5] = 26
Comment: it was actually easier to get the 3D case right and then specialize to the 2D case than to get the 2D case right and then generalize to the 3D case.
Note that this technique works for any contiguous array (like the statically allocated example). There are ways of dynamically allocating arrays where the data is not contiguous, and this will not work on such pseudo-arrays. This is a problem if you allocate an array of pointers, and each pointer then points to a vector of integers, or any similar scheme. Such 'arrays' can be accessed using the double subscript notation, but the code generated is quite different from accessing a true multi-dimensional (contiguous) array.
The code in function A()
won't handle an 'array' allocated like this (error checking omitted for brevity), even though the initialization loop looks much the same as an initialization loop for a regular (contiguous) 2D array:
int **base = malloc(4 * sizeof(*base));
for (int i = 0; i < 4; i++)
base[i] = malloc(6 * sizeof(*base[i]));
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 6; j++)
base[i][j] = 0;
}
for (int i = 0; i < 4; i++)
free(base[i]);
free(base);
There is no way to inspect a variable argument list and get the size, so you have to pass a length argument.
Here's a recursive example that can support arbitrary dimensional int array:
#include <stdint.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
void print_array_v(void *a, int cnt, va_list args) {
va_list nw;
int i, j;
i = va_arg(args, int);
if(cnt > 1) {
for(j=0; j != i; ++j) {
va_copy(nw, args);
printf("[%d %d]\n", cnt-1, j);
print_array_v(((int **)a)[j], cnt - 1, nw);
va_end(nw);
}
} else {
printf("(%d, %p) ", i, a);
for(j = 0; j != i; ++j) { printf("%d ", ((int *)a)[j]); }
printf("\n");
}
}
void print_array(void *a, int cnt, ...) {
va_list lst;
va_start(lst, cnt);
print_array_v(a, cnt, lst);
va_end(lst);
}
Here is a sample driver:
int main(int argc, char ** argv) {
int i,j,k,l;
l = 0;
int ***a = malloc(2 * sizeof(int **));
for (i=0;i!=2;++i) {
a[i] = malloc(2 * sizeof(int *));
for(j=0;j!=2;++j) {
a[i][j] = malloc(2 * sizeof(int));
for(k=0;k!=2;++k) {
a[i][j][k] = ++l;
printf("(%d %d %d) %d\n", i, j, k, a[i][j][k]);
}
}
}
print_array(a, 3, 2, 2, 2);
return 0;
}
精彩评论