44

I am learning C and am having trouble passing the pointer of a 2D array to another function that then prints the 2D array. Any help would be appreciated.

int main( void ){
    char array[50][50];
    int SIZE;

    ...call function to fill array... this part works.

    printarray( array, SIZE );
}

void printarray( char **array, int SIZE ){
    int i;
    int j;

    for( j = 0; j < SIZE; j++ ){
        for( i = 0; i < SIZE; i ++){
            printf( "%c ", array[j][i] );
        }
        printf( "\n" );
    }
}
user1362058
  • 751
  • 1
  • 5
  • 14
  • 1
    void printarray( char array[][50], int SIZE ) – Lucas May 23 '13 at 21:41
  • 1
    While it is possible to do this, you're better off converting it to a 1D array and using `j*SIZE+i` to index it. – Dave May 23 '13 at 21:42
  • @Dave why? ...............................(just filler) – kotlomoy May 23 '13 at 21:48
  • 1
    @kotlomoy because C's n-D array syntax is ambiguous at best, and indexing it manually forces you to consider the memory order (often useful for caching performance). Also it means you can seamlessly switch to using a dynamic-sized array (via `malloc`) in the future. – Dave May 23 '13 at 21:55

5 Answers5

38

char ** doesn't represent a 2D array - it would be an array of pointers to pointers. You need to change the definition of printarray if you want to pass it a 2D array:

void printarray( char (*array)[50], int SIZE )

or equivalently:

void printarray( char array[][50], int SIZE )
Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • 1
    could you explain what the syntax "char *array[50]" means in plain english? – user1362058 May 23 '13 at 21:43
  • 3
    Running `cdecl explain 'char (*arr)[50]'` yields `declare arr as pointer to array 50 of char`. – Carl Norum May 23 '13 at 21:46
  • @CarlNorum: Pre-edit it was not a pointer to an array IIRC, but yeah – Ed S. May 23 '13 at 21:46
  • IF I pass the array this way am I making a copy of the array in memory for printarray() to use or am I using the original array? – user1362058 May 23 '13 at 21:52
  • 1
    @user1362058: No, no copy is taking place (aside from a pointer). You cannot pass arrays to functions; they degrade to pointers to their first element. Your problem is that your type declaration was simply wrong. A two dimensional array degrades to a pointer to another array. – Ed S. May 23 '13 at 21:53
  • No, arrays always decay to pointers in a function call context like this, so you're always passing a pointer. – Carl Norum May 23 '13 at 21:53
  • Thank you guys for your help. I learned JAVA first and now am having a hard time with the pointers and referencing in C. Is there a good website for people to reference that explains a lot of this stuff in more detail? – user1362058 May 23 '13 at 21:58
  • 2
    Great answer. `char (*array)[50]` declares a pointer, with the name `array` to a 1d array of 50 `char`s. I thought the explanation in the comment was a little ambiguous and i wanted to improve. – KeyC0de Feb 25 '17 at 01:56
  • 1
    What's the difference between (*array)[50] and *array[50] in the head of a function? – Jarkid Mar 24 '17 at 05:46
  • 2
    @Jarkid, the former is a pointer to a 50-element array, and the latter is an array of 50 pointers. – Carl Norum Mar 24 '17 at 15:49
  • If I have multiple arrays with varying shapes, declared as `char (*array)[M]`, M and SIZE being different each time, how can I pass them by reference to functions and access them? I can pass the `SIZE` as an argument, but what about `M`? How does it look in the function definition? – Karan Shah Oct 04 '20 at 17:38
11

In main(), the variable "array" is declared as

char array[50][50];

This is a 2500 byte piece of data. When main()'s "array" is passed about, it is a pointer to the beginning of that data. It is a pointer to a char expected to be organized in rows of 50.

Yet in function printarray(), you declare

 char **array

"array" here is a pointer to a char *pointer.

@Lucus suggestion of void printarray( char array[][50], int SIZE ) works, except that it is not generic in that your SIZE parameter must be 50.

Idea: defeat (yeech) the type of parameter array in printarray()

void printarray(void *array, int SIZE ){
    int i;
    int j;
    char *charArray = (char *) array;

    for( j = 0; j < SIZE; j++ ){
        for( i = 0; i < SIZE; i ++){
            printf( "%c ", charArray[j*SIZE + i] );
        }
        printf( "\n" );
    }
}

A more elegant solution is to make the "array" in main() an array of pointers.

// Your original printarray()
void printarray(char **array, int SIZE ){
    int i;
    int j;
    for( j = 0; j < SIZE; j++ ){
        for( i = 0; i < SIZE; i ++){
            printf( "%c ", array[j][i] );
        }
        printf( "\n" );
    }
}

// main()
char **array;
int SIZE;
// Initialization of SIZE is not shown, but let's assume SIZE = 50;
// Allocate table
array = (char **) malloc(SIZE * sizeof(char*));
  // Note: cleaner alternative syntax
  // array = malloc(sizeof *array * SIZE);
// Allocate rows
for (int row = 0; row<SIZE; row++) {
  // Note: sizeof(char) is 1. (@Carl Norum)
  // Shown here to help show difference between this malloc() and the above one.
  array[row] = (char *) malloc(SIZE * sizeof(char));
    // Note: cleaner alternative syntax
    // array[row] = malloc(sizeof(**array) * SIZE);
  }
// Initialize each element.
for (int row = 0; row<SIZE; row++) {
  for (int col = 0; col<SIZE; col++) {
    array[row][col] = 'a';  // or whatever value you want
  }
}
// Print it
printarray(array, SIZE);
...
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 3
    @CarlNorum Just because it is doesn't mean you have to ruthlessly replace it with 1 (or remove it altogether). `sizeof` statements can go a long way in making your code self-documenting. – Thomas May 23 '13 at 22:16
  • @Thomas, if you want to make your code self-documenting, you can do so without being redundant. Use `sizeof **array`, for example. Then at least if you change the data type later, you get the size adjustment for free. – Carl Norum May 23 '13 at 22:36
  • 3
    Array dimensions do not need to be fixed when passing to functions; a function can be declared `void printarray(size_t Rows, size_t cols, char array[][cols])`, for example. (I have no idea why this is not better known after it has been in the standard for 14 years.) – Eric Postpischil May 24 '13 at 00:32
  • @Eric Postpischil: Declaring a function with "void printarray(size_t Rows, size_t cols, char array[][cols]);" fails my compiler. Is this a correct test of your suggestion? – chux - Reinstate Monica May 24 '13 at 15:26
  • @chux: You would need to specify what “my compiler” is before anybody else could really help. It is GCC? Clang? Some Microsoft thing? What was the error message? Some compilers may default to a language version that is old (such as GCC’s c89) or non-standard (such as gnu89). For GCC or clang, try “-std=c99” or “-std=c1x”. For a Microsoft compiler, try GCC or clang. Did you include `` to define `size_t`? (You can use other integer types for dimensions in the declaration; it can be `int` instead of `size_t`.) – Eric Postpischil May 24 '13 at 15:32
  • @Eric Postpischil: Thanks for the ideas and quick reply. My gcc 4.5.3 had no trouble with "void printarray(size_t Rows, size_t cols, char xarray[][cols]);". My Microsoft thing (VS10) complained with "error C2057: expected constant expression" but worked fine with "void printarray(size_t Rows, size_t cols, char xarray[][50]);" Maybe some option in VS would compile this. – chux - Reinstate Monica May 24 '13 at 16:08
  • @chux That's because the MS C compiler *still* doesn't support VLA's, even today, five years and three major revisions to their tool chain after your posted answer and comment. Sad reality, but true. – WhozCraig Sep 19 '18 at 01:04
5

Since C99 supports dynamic-sized arrays, the following style is simply more convenient to pass a 2-dim array:

void printarray( void *array0, int SIZE ){
    char (*array)[SIZE] = array0;
    int i;
    int j;
    for( j = 0; j < SIZE; j++ ){
        for( i = 0; i < SIZE; i ++){
            printf( "%c ", array[j][i] );
        }
        printf( "\n" );
    }
}
Simon Woo
  • 474
  • 3
  • 5
  • 1
    This is the answer I like, because it works in the case that you don't know the size at compile time. However, I'd like to make 2 notes: (1.) If you pass both dimension sizes (say, rows and columns), then `array` should be declared as `char (*array)[columns] = array0;` (2.) If you use const correctness (in this case you aren't changing any of the values in the array, so it's appropriate), then you'd want to have the `array0` param declared as `const void *array0`, and `array` declared in the body as `char const (*array)[columns] = array0;` – Tynach Oct 06 '18 at 19:04
  • 1
    An clean alternative without the `char (*array)[SIZE] = array0;` is `printarray(int SIZE, char array[SIZE][SIZE])` – chux - Reinstate Monica Aug 13 '20 at 17:45
2

none of the answers here were what I was looking for, so I'm posting my simple solution to the problem

#include <iostream>

using namespace std;

void example(int* mat, int dim0, int dim1){
    
    for(int i = 0; i < dim0; ++i) {
         for(int j = 0; j < dim1; ++j) {
             auto cur_index = i * dim1 + j;
            cout<< *(mat + cur_index) << endl;
        }
    }
}

int main()
{
    const int dim0 = 3;
    const int dim1 = 2;

    int mat[dim0][dim1];
    
    for(int i = 0; i < dim0; ++i) {
         for(int j = 0; j < dim1; ++j) {
            mat[i][j] = i * dim1 + j;
        }
    }
    
    example(&(mat[0][0]), dim0, dim1);
    return 0;
}
-2

You can easily pass the 2d array using double pointer.

  void printarray( char **array, int n)
  {
     int i, j;
     for(i=0; i<n; i++ )
     {
         for(j=0; j<n; j++)
         {
            printf("%c ", array[i][j] );
         }
        printf( "\n" );
     }
  }

  int main()
  {
      int n = 2;
      int i, j;

      char **array = (char **) malloc(n * sizeof(char*));

      for (i=0; i<n; i++) 
      {
        array[i] = (char *) malloc(n* sizeof(char));
      }

     for (i=0; i<n; i++)
     {
       for (j=0; j<n; j++)
       {
           scanf("%c ", &array[i][j]);
       }
     }

     printarray(array, n);

     return 0;
  }

Full Code : Ideone

rashedcs
  • 3,588
  • 2
  • 39
  • 40