Pass static two dimensional struct array to function by reference - c

I try to pass a static two dimensional struct as a reference to a function.
But I don't know how to get that done in correct way.
From my understanding, I pass a pointer to the first element of struct test to initfield(). C does know the size of the struct test so I can jump to the specific requested locations of the data. I just don't know how to adress the required data.
Here's my code that hopefully describes what I am looking for.
struct test{
int i;
double d;
};
void initfield(struct test *a, int structsize)
{
int i, j;
for (i = 0; i < structsize; i++)
{
for (j = 0; j < structsize; j++)
{
a[i][j]->i = 1;
a[i][j]->d = 1.0;
}
}
}
int main(void)
{
int i, j;
struct test field[8][8];
initfield(field, 8);
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
printf("test[%i][%i].i = %i", i, j, test.i);
printf("test[%i][%i].d = %i", i, j, test.d);
}
}
return 0;
}
Update :
I've replaced both printf's with the following :
printf("test[%i][%i].i = %i", i, j, field[i][j].i);
printf("test[%i][%i].d = %lf", i, j, field[i][j].d);
However, I still encounter errors with initfield.

The problem, is actually, in your initfield() code,
void initfield(struct test *a, int structsize)
a is of type struct test *, and later, you're doing
a[i][j]->i = 1;
which expects a to be struct test **
That said,
for (j = 0; j < 8; j++)
{
printf("test[%i][%i].i = %i", i, j, test.i);
printf("test[%i][%i].d = %i", i, j, test.d);
}
is completely wrong. Neither is there any variable called test, nor you can access a 2-D array using structVar.membervar format. Moreover, you are using %d to print a double, which in turn invokes undefined behaviour.
Solution: You can make use of array properties and pointer arithmetic to achieve what you want.
You have to change the loop inside the initfield() code, like
for (i = 0; i < structsize; i++)
{
for (j = 0; j < structsize; j++)
{
((a+(i*structsize))+j)->i = 7; //I changed the value to store, just like that
((a+(i*structsize))+j)->d = 2.0; //I changed the value to store, just like that
}
}
and, in main(), use %f to print the values.
A Live variant

First, structsize is not a good identifier name. It's not the size of the struct, it's the size of one dimension of the array. I'd implement it with parameters x and y, or width and heigth, or any better names for the two dimensions.
field is also a bad name. A field is often used to call a member of a struct. It is very confusing to use the identifier field to call an array of array of structs.
Then to your problem: field is an array of array of structs. In function parameter, this is equivalent to a pointer to a pointer.
The first parameter of initfield should be of type struct test **. Then later in the function, you dereference twice with your [] operators:
a is of type struct test **
a[i] is of type struct test *
a[i][j] is of type struct test
To access the fields of a[i][j], you need the . operator since its a struct test: a[i][j].d. The operator -> would work if a[i][j] was of type struct test *, but it isn't.
In this case it doesn't matter: as other have said, you can't access the second dimension of the array without explicitly calculating with the help of the size of the first dimension. a[i][j] does not work, you need some kind of pointer arithmetic: struct test *p = a + i * structsize + j and use p->i and p->d.
In the main function however, the dimensions of field are know, so field[i][j].d works.

You're assuming C can figure out that a inside refers to a square array with side length structsize, although you clearly say that a has type "pointer to struct test", which is not the same.
You need to do the indexing manually, inside the function:
static void initfield(struct test *a00, size_t sidelength)
{
for(size_t i = 0; i < sidelength; ++i)
{
for(size_t j = 0; j < sidelength; ++j)
{
struct test *aij = a00 + i * sidelength + j;
aij->i = 1;
aij->j = 1.0;
}
}
}
I didn't test the above, but something like that should work. It basically just uses simple pointer arithmetic to compute the address of the 2D array element at (i, j) given the address of the one at (0, 0).

It works fine i din't thought about doing calculation the adresses myself.
Thanks very much!
Here's my final adapted code which just works perfectly!
struct test{
int i;
double d;
};
void initfield(struct test *a00, int structsize)
{
int i, j;
for (i = 0; i < structsize; i++)
{
for (j = 0; j < structsize; j++)
{
struct test *acurrent = a00 + i * structsize + j;
acurrent->i = 1;
acurrent->d = 1.0;
}
}
}
int main(void)
{
int i, j;
struct test field[8][8];
initfield(&field[0][0], 8);
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
printf("test[%i][%i].i = %i\n", i, j, field[i][j].i);
printf("test[%i][%i].d = %lf\n", i, j, field[i][j].d);
}
}
return 0;
}

Best way to do this:
void initfield(size_t x, size_t y, struct test a[x][y]);
Be aware though, C is strange, the above is still a pointer, equivalent to struct test*. If you wish to have a true array pointer type, you'd have to do:
void initfield(size_t x, size_t y, struct test a[x][y])
{
struct test (*ptr)[x][y] = (void*)a;
or preferably:
struct test (*ptr)[y] = *a;
ptr[i][j] = something; // use the array pointer with sane syntax

Related

C - Having trouble with passing NxN array as an argument. I keep getting warning: incompatible pointer type [duplicate]

This question already has answers here:
Why can't we use double pointer to represent two dimensional arrays?
(6 answers)
Closed 13 days ago.
I wrote this program that is supposed to sort NxN array. It gets compiled but doesn't work because the pointer type is incompatible.
I just need help with the pointers as argument. I get incompatible pointer type warning for both functions swap and dblArraySort. Any idea why is that ?
thanks in advance !
#include <stdio.h>
#include <stdlib.h>
void
swap(int **a, int **b)
{
int temp;
temp = **a;
**a = **b;
**b = temp;
}
void
dblArraySort(int **dblArray, int arrLen)
{
int chkIndex;
int i, j, k;
for (i = 0; i < arrLen; i++) {
if ((i + 1) % 2 == 0) {
for (j = 0; j < arrLen; j++) {
chkIndex = dblArray[i][j];
for (k = 1; k + j < arrLen; k++)
if (chkIndex < dblArray[i][k + j])
swap(&dblArray[i][j], &dblArray[i][k + j]);
else
continue;
}
} else {
for (j = 0; j < arrLen; j++) {
chkIndex = dblArray[i][j];
for (k = 1; k + j < arrLen; k++)
if (chkIndex >= dblArray[i][k + j])
swap(&dblArray[i][j], &dblArray[i][k + j]);
else
continue;
}
}
}
}
int
main()
{
unsigned int arrayLength;
printf("Provide array size: \n");
scanf("%d", &arrayLength);
int doubleArray[arrayLength][arrayLength];
for (int i = 0; i < arrayLength; i++) {
for (int j = 0; j < arrayLength; j++) {
scanf("%d", &doubleArray[i][j]);
}
}
dblArraySort(doubleArray, arrayLength);
for (int i = 0; i < arrayLength; i++) {
for (int j = 0; j < arrayLength; j++) {
printf("%d ", doubleArray[i][j]);
}
printf("\n");
}
return 0;
}
I tried the code mentioned above
Arrays in C can be confusing. The thing you need to worry about is element type.
The element type of int ** dblArray is int *. In other words, dblArray is an array of int *s.
However, the element type of int doubleArray[arrayLength][arrayLength] is int row_type[arrayLength]. That is not an int *, that is an array, which is a totally different thing.
Moreover, when you use an array⟶pointer conversion, as happens when you say:
dblArraySort(doubleArray, arrayLength); // doubleArray is converted to a pointer
You get a pointer to the array, which in this case is a pointer to the innermost element type, an int — which is also not an int *.
tl;dr: You are trying to pass an array of array of int to a function taking an array of pointer to int. That won’t work.
I would like to comment on your variable naming as well. When you say “double” or “dbl”, as in doubleArray and dblArray the very first thing people will think is that you are handling a linear array of type double, which is also not what the array is.
You have there a two-dimensional array. Not a “double” array. Common naming for such thing would be array2D or matrix.
To make it work you need either C11, which allows you to pass a VLA as:
void sort_array2D( size_t rows, size_t columns, int array[rows][columns] )
{
...
int value = array[i][j];
...
}
int main(void)
{
int array2D[Array_Length][Array_Length];
...
sort_array2D( Array_Length, Array_Length, array2D );
Or you need to simply assume you must compute the index manually. A little function will help:
size_t index2D( size_t rows, size_t columns, size_t r, size_t c )
{
(void)rows; // (quiet the compiler about not using this argument)
return r * columns + c;
}
Then you can write your function as:
void sort_array2D( int * array, size_t rows, size_t columns )
{
...
int value = array[index2D( rows, columns, i, j )];
...
}
int main(void)
{
int array2D[Array_Length][Array_Length];
...
sort_array2D( (int *)array2D, Array_Length, Array_Length );
I haven’t bothered to analyze your sort function. It doesn’t look right to me, but honestly, I’ve barely glanced at it. Calling a value from the array chkIndex looks fishy, since the values of the array are not indices per se, at least not in the context of sorting them.
Remember, when messing with arrays in C you need to keep strict care to not mix up the type of the elements. (Or the types of things in general, whether syntactic or conceptual.)

C allocate 'array pointer' inside a function

Related to dynamic allocation inside a function, most questions & answers are based on double pointers.
But I was recommended to avoid using double pointer unless I have to, so I want to allocate a 'array pointer' (not 'array of pointer') and hide it inside a function.
int (*arr1d) = calloc(dim1, sizeof(*arr1d));
int (*arr2d)[dim2] = calloc(dim1, sizeof(*arr2d));
Since the above lines are the typical dynamic-allocation of pointer of array, I tried the following.
#include <stdio.h>
#include <stdlib.h>
int allocateArray1D(int n, int **arr) {
*arr = calloc(n, sizeof(*arr));
for (int i = 0; i < n; i++) {
(*arr)[i] = i;
}
return 0;
}
int allocateArray2D(int nx, int ny, int *(*arr)[ny]) {
*arr[ny] = calloc(nx, sizeof(*arr));
for (int i = 0; i < nx; i++) {
for (int j = 0; j < ny; j++) {
(*arr)[i][j] = 10 * i + j;
}
}
return 0;
}
int main() {
int nx = 3;
int ny = 2;
int *arr1d = NULL; // (1)
allocateArray1D(nx, &arr1d);
int(*arr2d)[ny] = NULL; // (2)
allocateArray2D(nx, ny, &arr2d);
for (int i = 0; i < nx; i++) {
printf("arr1d[%d] = %d \n", i, arr1d[i]);
}
printf("\n");
printf("arr2d \n");
for (int i = 0; i < nx; i++) {
for (int j = 0; j < ny; j++) {
printf(" %d ", arr2d[i][j]);
}
printf("\n");
}
return 0;
}
And the error message already comes during the compilation.
03.c(32): warning #167: argument of type "int (**)[ny]" is incompatible with parameter of type "int *(*)[*]"
allocateArray2D(nx, ny, &arr2d);
^
It is evident from the error message that it has been messed up with the argument types (that I wrote as int *(*arr)[ny]) but what should I have to put there? I tried some variants like int *((*arr)[ny]), but didn't work).
And if I remove the 2D parts, then the code well compiles, and run as expected. But I wonder if this is the right practice, at least for 1D case since there are many examples where the code behaves as expected, but in fact there were wrong or un-standard lines.
Also, the above code is not satisfactory in the first place. I want to even remove the lines in main() that I marked as (1) and (2).
So in the end I want a code something like this, but all with the 'array pointers'.
int **arr2d;
allocateArray2D(nx, ny, arr2d);
How could this be done?
You need to pass the array pointer by reference (not pass an array pointer to an array of int*):
int *(*arr)[ny] -> int (**arr)[ny]
The function becomes:
int allocateArray2D(int nx, int ny, int (**arr)[ny]) {
*arr = calloc(nx, sizeof(int[ny])); // or sizeof(**arr)
for (int i = 0; i < nx; i++) {
for (int j = 0; j < ny; j++) {
(*arr)[i][j] = 10 * i + j;
}
}
return 0;
}
For details, check out Correctly allocating multi-dimensional arrays
Best practices with malloc family is to always check if allocation succeeded and always free() at the end of the program.
As a micro-optimization, I'd rather recommend to use *arr = malloc( sizeof(int[nx][ny]) );, since calloc just creates pointless overhead bloat in the form of zero initialization. There's no use of it here since every item is assigned explicitly anyway.
Wrong parameter type
Strange allocation
Wrong size type
I would return the array as void * too (at least to check if allocation did not fail).
void *allocateArray2D(size_t nx, size_t ny, int (**arr)[ny]) {
//*arr = calloc(nx, sizeof(**arr)); calloc is not needed here as you assign values to the array
*arr = malloc(nx * sizeof(**arr));
for (size_t i = 0; i < nx; i++) {
for (size_t j = 0; j < ny; j++) {
(*arr)[i][j] = 10 * i + j;
}
}
return *arr;
}

Attempt to access elements of a 2d struct array failing

typedef struct{
unsigned long a;
unsigned long b;
unsigned long c;
} mini_struct;
struct ministruct** build_2Dstruct(unsigned long x, unsigned long y){
double x_squared = pow(2, x);
struct ministruct** temp = (mini_struct**)malloc(x*sizeof(mini_struct*));
for(int i = 0; i < x_squared; i++){
temp[i] = (mini_struct*)malloc(y*sizeof(mini_struct));
for(int j = 0; j < y; j++){
temp[i][j].a = 0;
etc....
}
}
return temp;
}
In the code above I am trying to create a 2D array of ministructs**, with the whole struct being made out of 2^x ministructs*, and each ministruct* has y amount of ministructs.
aka:
x = 2,
y = 2,
[[struct, struct], [struct, struct], [struct, struct], [struct, struct]]
However, for some reason when I try to access the second element or index 1 of the struct inside each struct*, it says there is an error: "expression must be pointer to complete object".
I just do not understand why the code is not allowing me to access each individual element of the elements of the array?
Thanks
You are trying to make an x by y array of structs. So:
// create array of x pointers
mini_struct **temp = malloc(x*sizeof(mini_struct*));
for (int i=0; i<x; i++) {
// to array of y structs
temp[i] = malloc(y*sizeof(mini_struct));
for (int j=0; j < y; j++) {
temp[i][j].a = 0;
... etc.
Question is incomplete so I will be making asumptions.
You seem to be wanting to allocate a 2D array of structs and initialize all members to 0. Here is a possible solution:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
typedef struct mini_struct{
unsigned long a;
unsigned long b;
unsigned long c;
} mini_struct;
struct mini_struct** build_2Dstruct(unsigned long x, unsigned long y){
double x_squared = pow(x, 2);
mini_struct **temp = (mini_struct **) malloc(x_squared * sizeof(mini_struct*));
for(int i = 0; i < x_squared; i++){
temp[i] = (mini_struct *) calloc(y, sizeof(mini_struct));
}
return temp;
}
int main () {
int x = 3;
int y = 4;
mini_struct **struct2D = build_2Dstruct(x, y);
int x_squared = pow(x,2);
for (int i = 0; i < x_squared; ++i) {
for (int j = 0; j < y; ++j) {
printf("Value of data stored at struct[%d][%d] is: %d\n", i, j, struct2D[i][j]);
}
}
for (int i = 0; i < x_squared; ++i) {
free(struct2D[i]);
}
free(struct2D);
}
As you can see, this contains the whole program, not just the snippet you showed. In this case, a main function would have been useful so that we don't have to guess what you want to do. My solution creates the 2D array with all elements initialized to 0 (you can use calloc to do that, no need for a second for loop).
Another important point is that, because the function returns a newly heap allocated 2D array, you need to free it to avoid a memory leak (end of main function).
You allocate x pointers to mini_struct:
mini_struct **temp = (mini_struct **) malloc(x_squared * sizeof(mini_struct*));
But then when you initialize them:
for(int i = 0; i < x_squared; i++){
temp[i] = (mini_struct *) calloc(y, sizeof(mini_struct));
}
You index temp based on upto x_squared.
Consider if x is 2. You would allocate temp to be an array of two pointers to mini_struct. But then your for loop would attempt to initialize four elements in temp.

int** vs int[const][const] differences

I was writing a code the other day and I found it rather strange, that int** and int[][] does not behave the same way. Can anyone point out the differences between them? Below is my sample code, which fails with a segmentation fault, if I pass constant size 2d array, while it does work fine when I pass a dinamically allocated 2d array.
I am confused mainly because ant int[] array works the same as int*.
#include<stdio.h>
#include<stdlib.h>
void sort_by_first_row(int **t, int n, int m)
{
int i, j;
for(i = m-1 ; i > 0 ; --i)
{
for(j = 0 ; j < i; ++j)
{
if(t[0][j] < t[0][j+1])
{
int k;
for(k = 0 ; k < n ;++k)
{
int swap;
swap = t[k][j];
t[k][j] = t[k][j+1];
t[k][j+1] = swap;
}
}
}
}
}
int main(void) {
int i, j;
/* Working version */
/*int **t;
t =(int**) malloc(3*sizeof(int*));
for(i = 0; i < 3; ++i)
{
t[i] = (int*) malloc(6*sizeof(int));
}*/
/*WRONG*/
int t[3][6];
t[0][0] = 121;
t[0][1] = 85;
t[0][2] = 54;
t[0][3] = 89;
t[0][4] = 879;
t[0][5] = 11;
for( i = 0; i < 6; ++i )
t[1][i] = i+1;
t[2][0] = 2;
t[2][1] = 4;
t[2][2] = 5;
t[2][3] = 3;
t[2][4] = 1;
t[2][5] = 6;
sort_by_first_row(t, 3, 6);
for(i = 0; i < 3; ++i)
{
for(j = 0; j < 6; ++j)
printf("%d ", t[i][j]);
printf("\n");
}
return 0;
}
So based on the below answers I realize, that a multidimensional array is stored continuously in a row major order. After some modification, the below code works:
#include<stdio.h>
#include<stdlib.h>
void sort_by_first_row(int *t, int n, int m)
{
int i, j;
for(i = m-1 ; i > 0 ; --i)
{
for(j = 0 ; j < i; ++j)
{
if(t[j] < t[j+1])
{
int k;
for(k = 0 ; k < n ;++k)
{
int swap;
swap = t[k*m + j];
t[k*m + j] = t[k*m + j+1];
t[k*m + j+1] = swap;
}
}
}
}
}
int main(void) {
int i, j;
/* Working version */
/*int **t;
t =(int**) malloc(3*sizeof(int*));
for(i = 0; i < 3; ++i)
{
t[i] = (int*) malloc(6*sizeof(int));
}*/
/*WRONG*/
int t[3][6];
t[0][0] = 121;
t[0][1] = 85;
t[0][2] = 54;
t[0][3] = 89;
t[0][4] = 879;
t[0][5] = 11;
for( i = 0; i < 6; ++i )
t[1][i] = i+1;
t[2][0] = 2;
t[2][1] = 4;
t[2][2] = 5;
t[2][3] = 3;
t[2][4] = 1;
t[2][5] = 6;
sort_by_first_row(t, 3, 6);
for(i = 0; i < 3; ++i)
{
for(j = 0; j < 6; ++j)
printf("%d ", t[i][j]);
printf("\n");
}
return 0;
}
My new question is this: How to modify the code, so that the procedure works with int[][] and int** also?
Realize that int **t makes t a pointer to a pointer, while int t[3][6] makes t an array of an array. In most cases, when an array is used in an expression, it will become the value of the address of its first member. So, for int t[3][6], when t is passed to a function, the function will actually be getting the value of &t[0], which has type pointer to an array (in this case, int (*)[6]).
The type of what is being pointed at is important for how the pointer behaves when indexed. When a pointer to an object is incremented by 5, it points to the 5th object following the current object. Thus, for int **t, t + 5 will point to the 5th pointer, while for int (*t)[M], t + 5 will point to the 5th array. That is, the result of t + 5 is the same as the result of &t[5].
In your case, you have implemented void sort_by_first_row(int **t, int n, int m), but you are passing it an incompatible pointer. That is, the type of &t[0] (which is what t will become in main) is not the same as what the function wants, a int **t. Thus, when the sorting function starts to use that address, it will think its indexing into pointers, when the underlying structure is an array of arrays.
int** is quite different from int[][]. int** is simply a pointer to a pointer and would appear like the following:
in reality, you can access the entire multidimensional array with simply int* pointing to the first element, and doing simple math from that.
Here is the result of the separate allocations (in your commented code):
However when you allocate a multidimensional array, all of the memory is contiguous, and therefore easy to do simple math to reach the desired element.
int t[3][6];
int *t = (int*) malloc((3 * 6) * sizeof(int)); // <-- similarly
This will result in a contiguous chunk of memory for all elements.
You certainly can use the separate allocations, however you will need to walk the memory differently.
Hope this helps.
int t[3][6] is very nearly the same thing as int t[18]. A single contiguous block of 18 integers is allocated in both cases. The variable t provides the address of the start of this block of integers, just like the one-dimensional case.
Contrast this with the case you have marked as "working", where t gives you the address of a block of 3 pointers, each of which points to a block of memory with 6 integers. It's a totally different animal.
The difference between t[3][6] and t[18] is that the compiler remembers the size of each dimension of the array, and automatically converts 2D indices into 1D offsets. For example, the compiler automatically converts t[1][2] into *(t + 1*6 + 2) (equivalent to t[8] if it were declared as a one-dimensional array).
When you pass a multi-dimensional array to a function, there are two ways to handle it. The first is to declare the function argument as an array with known dimension sizes. The second is to treat your array like a 1D array.
If you are going to declare the size of your array, you would declare your function like this:
void sort_by_first_row(int t[][6], int n)
or this
void sort_by_first_row(int t[3][6])
You either have to declare all array dimension sizes, or you can leave out the first size. In both cases, you access elements of t using t[i][j]; you've given the compiler enough information to do the offset math that converts from 2D notation to a 1D index offset.
If you treat it as a 1D array, you have to pass the array dimensions and then do the offset math yourself.
Here's a full working example, where f and f2 both generate the same output:
void f(int* t, int m, int n)
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
std::cout << t[i * n + j] << " ";
std::cout << std::endl;
}
void f2(int t[][6], int m)
{
for (int i = 0; i < m; i++)
for (int j = 0; j < 6; j++)
std::cout << t[i][j] << " ";
std::cout << std::endl;
}
int main()
{
int t[3][6];
int val = 1;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 6; j++)
{
t[i][j] = val;
val++;
}
}
f(&(t[0][0]), 3, 6);
f2(t, 3);
return 0;
}
One thing to note is the hack-ish way I had to pass t to f. It's been a while since I wrote in C/C++, but I remember being able to pass t directly. Maybe somebody can fill me in on why my current compiler won't let me.
A int ** is a pointer to a pointer to an int, and can be a pointer to an array of pointers to arrays of ints. A int [][] is a 2-dimensional array of ints. A two-dimensional array is exactly the same as a one-dimensional array in C in one respect: It is fundamentally a pointer to the first object. The only difference is the accessing, a two-dimensional array is accessed with two different strides simultaneously.
Long story short, a int[][] is closer to an int* than an int**.

Passing variable sized multi-dimensional array by pointer in C

I am trying to pass a 2D array of variable size to a function to print it. I know how it's done when one has fixed sized arrays. But how does one do this with variable sized arrays? Here is some code that'll give you an idea what I am trying to do:
void print_grid(char (*g)[9], int size) // the array subscript (9 here) be variable
{
int i, j;
for (i=0; i<size; i++)
{
for (j=0; j<size; j++)
printf("%c ", g[i][j]);
printf("\n");
}
}
I'll call this function using the following code:
char a[3][3], b[9][9];
// assign a, b
print_grid(a, 3);
print_grid(b, 9);
Is there any way to do this without allocating any dynamic memory in print_grid()?
void print_grid(int rows, int cols, char g[][cols]) { ... }
void print_grid(char *g, int size)
{
int i, j;
for( i = 0; i < size; i++)
for( j = 0; j < size; j++)
{
printf("%c ", *(g + i*size + j));
printf("\n");
}
}
print_grid(a, 3);
When you pass an array in C it is always passed by reference, i.e. through a pointer. The type of this pointer is not pointer-to-array, but pointer-to-first-element. For example, the code generator will handle void f(char[][10]) as if it where void f(char*). The array dimensions are lost. The parser, however, will complain if it sees f declared twice so.
The motivation behind C was to have a powerful and portable assembler, not a new programming language. Multidimensional arrays are logical constructs that do not exist in the machine. Arrays are a way of thinking.
To pass the dimensions of arrays to functions C programmers traditionally use structs:
typedef struct array_tag {
int count;
char data[1]; /* actually data[count] */
} ARRAY;
typedef struct grid_tag {
int rows, columns;
char grid[1][1]; /* actually grid[rows][columns] */
} GRID;
void f(ARRAY* x)
{
int i;
for (i = 0; i < x->count; ++i) {
char c = x->data[i];
}
}
void g(GRID* x)
{
int i, j;
for (i = 0; i < x->rows; ++i)
for (j = 0; j < x->columns; ++j) {
char c = x->grid[i][j];
}
}
void h()
{
{
const int len = 100;
ARRAY* x = (ARRAY*) malloc(sizeof(ARRAY) + len * sizeof(char));
x->count = len;
f(x);
}
{
const int rows = 2, cols = 3;
GRID* x = (GRID*) malloc(sizeof(GRID) + rows * cols * sizeof(char));
x->rows = rows;
x->columns = cols;
g(x);
}
}
Yes, the malloc expression in this example allocates few bytes too much. Therefore the GNU-compiler supports arrays of zero length for a long time, which are not allowed in C90.
C99 has gone one step further with flexible arrays. From ISO/IEC 9899:1999, Section 6.7.2.1, paragraph 16: "As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member." In C99 the ARRAY and GRID types can be declared as:
typedef struct array_tag {
int count;
char data[]; /* actually data[count] */
} ARRAY;
typedef struct grid_tag {
int rows, columns;
char grid[][1]; /* actually grid[rows][columns] */
} GRID;
and you can
assert(1*sizeof(int) == sizeof(ARRAY));
assert(2*sizeof(int) == sizeof(GRID));
Many people think C arrays are quirky. But they're also an elegant solution which allows the declaration of indefinitely complex arrays. It is known as the "K&R array equation". A good explanation can be found here.
Hope this helps.
This one does it, assuming a squared grid:
void print_grid(void* g, int size)
{
char* my = (char*) g;
int i, j;
for (i=0; i<size; i++)
{
for (j=0; j<size; j++)
printf("%c ", my[i+j]);
printf("\n");
}
}
If you want to use non-squared grids, replace size with a rows and columns parameter and adjust counting: i<rows and j<columns.

Resources