1

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()?

2
  • col is the number of columns. It will be size in the above code Commented Dec 23, 2010 at 12:19
  • 2
    Don't use int for array index computations. size_t is meant for that. Commented Dec 23, 2010 at 13:39

4 Answers 4

5
void print_grid(int rows, int cols, char g[][cols]) { ... }
Sign up to request clarification or add additional context in comments.

15 Comments

Is the value of 'cols' in 'g[][cols]' passed by the calling statement? I did not understand how is this variable?
Yes, the caller is required to pass it. An array in itself does not contain any information about its type.
It does not even contain information that it is an array... and BTW the above answer does not compile. Only C++ compilers could deduce some cols as template argument; but that's another liga. I assume the function is supposed to be called as print_grid(2, 3, a) on some a def'd as a[2][3]. But why char g[][cols] declaration? a will decay into a char*, and the dimensions are always ignored. And this even makes a lot of sense, because the char* value is not a pointer-to-array, but a pointer-to-first-element.
@AndreasSpindler: char g[][cols] is equivalent to char (*)[cols] which is a pointer to an array of cols elements (a variably-modified type). g points to the first "row" of the grid, not to a single char.
cols is defined at runtime, and the compiler has no chance to declare print_grid. Each array you pass to a function decays into a pointer to its first element - known as the "K&R decay convention".
|
1
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);

3 Comments

Where does "input" come from? Why do you assign it to "inp" and then not use "inp" anywhere?
@eckes, I wrote a code then copying the OPs function, I have col and row by myself :)
I'm not the downvoter, but some people (whom I disagree with) would argue that your answer has Undefined Behavior. See: stackoverflow.com/questions/3766074/…
1

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.

1 Comment

In your original code, you've declared grid[1][1] so the compiler believes the width of each row in the grid to be 1. So, accessing the cell at grid[x][y] presumably will not work. For example, grid[0][3] would seem to yield the same cell as grid[1][2] (and more generally every grid[x][y] where x+y=3). To make this work, would you not have to access cells by grid[0][x + y*cols]?
0

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.

1 Comment

it's not the actual array what one would want to see in a 'print' function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.