3

I'm having some trouble understanding how pointers work with two dimensional arrays. Even the error messages aren't helping me. I have a 2D array that I need a pointer for so I may manipulate it inside of functions (I think that's how you're supposed to do it anyway). Could someone please point out what I'm doing wrong and point me in the right direction?

Here's my code:

#include <stdio.h>
#include <time.h>

void init(char *array);

int main(int argc, char *argv[]) {
  char grid[21][80];
  char (*grid_ptr)[80];
  grid_ptr = grid;
  int i, j;
  init(*grid_ptr);

  for (i=0; i<21; i++) {
    for (j=0; j<80; j++) {
      printf("%c", grid_ptr[i][j]);
    }
    printf("\n");
  }

  return 0;
}

void init(char *array) {
  int i,j;
  for (i=0; i<21; i++) {
    for (j=0; j<80; j++) {
      *array[i][j] = ' ';
    }
  }
  for (i=0; i<21; i++) {
    *array[i][0] = '|';
    *array[i][79] = '|';
  }
  for (i=0; i<80; i++) {
    *array[0][i] = '-';
    *array[20][i] = '-';
  }
}

The errors are of this nature:

main.c:27:16: error: subscripted value is not an array, pointer, or vector
      *array[i][j] = ' ';
gsamaras
  • 71,951
  • 46
  • 188
  • 305

2 Answers2

4

Allow me to say that you are making your life hard for no reason at all! :) You see when one wants to manipulate a 2D array, he can work on the array directly, by passing the array itself to the function, like this:

#include <stdio.h>
#include <time.h>

void init(int n, int m, char array[n][m]);

int main(int argc, char *argv[]) {
  const int n = 21, m = 80;
  char grid[n][m];
  int i, j;
  init(n, m, grid);

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

  return 0;
}

void init(int n, int m, char array[n][m]) {
  int i,j;
  for (i = 0; i < n; i++) {
    for (j = 0; j < m; j++) {
      array[i][j] = ' ';
    }
  }
  for (i = 0; i < n; i++) {
    array[i][0] = '|';
    array[i][m - 1] = '|';
  }
  for (i = 0; i < m; i++) {
    array[0][i] = '-';
    array[n - 1][i] = '-';
  }
}

which gives this lovely rectangle:

C02QT2UBFVH6-lm:~ gsamaras$ gcc -Wall main.c
C02QT2UBFVH6-lm:~ gsamaras$ ./a.out 
--------------------------------------------------------------------------------
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
|                                                                              |
--------------------------------------------------------------------------------

Now notice the changes I made to your code:

  1. I got rid of the pointer that refers to the array, since it's redundant.
  2. I passed the array itself as a parameter to the function, as described here.
  3. Instead of using magic numbers (21 and 80) all over the place, I declared two new constant variables, n and m, which are the dimension of your 2D array, n rows x m columns.*
  4. I use the dimensions to implement the very same logic you had implemented so far. Notice that I have to pass them as function parameters too.

As for the error, it implies that you are not accessing what you think that you are accessing! But let me not expand on this and keep it minimal here. :)


*Now if you want to change the dimensions of your 2D array, you just need to change n and/or m once, not everywhere in your code (which is bug prone).

Community
  • 1
  • 1
gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • 1
    Thank you! Exactly what I was looking for! – Tyler McAnally Sep 07 '16 at 01:30
  • Well done, it may be worth introducing the OP to the syntax that allows you to specify the parameter `char array[n][m]` as `char (*array)[m]` which reflects the conversion of the first level of indirection to a pointer when the array is passed as a parameter. (and also makes clear why any attempt to use `sizeof` within the function will fail) – David C. Rankin Sep 07 '16 at 03:13
  • While I agree @DavidC.Rankin, M.M's answer seems to touch that and my answer is already big.. :) Thanks! – gsamaras Sep 07 '16 at 03:28
  • @DavidC.Rankin The language intentionally allows you to pass an array in this manner so that we don't need to worry our pretty heads about things like array decay, array pointers and pass by reference. Introducing an array pointer will just make the code ugly. – Lundin Sep 07 '16 at 09:05
0

In case anyone is using a C compiler that does not support the optional "variable length arrays" feature (e.g. the Microsoft compiler), here is another way:

void init( int rows, char (*array)[80] );

    // ... in main ...
    char grid[21][80];
    init(grid);          // use of grid_ptr is not required
    // ...

void init(int rows, char (*array)[80])
{
    int i,j;
    for (i = 0; i < rows; i++) {
      for (j = 0; j < 80; j++) {
        array[i][j] = ' ';

In the j loop you could replace 80 with sizeof *array. Or you could replace the entire j loop (in fact, both loops) with a call to memset.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • In the absence of a standard compiler, I think one should do either a "mangled" 2D array with variable dimensions, `init (int rows, int cols, char* array)`, or a hard-coded "magic number" array: `init (char [21][80])`. This seems like a hybrid of those two. – Lundin Sep 07 '16 at 09:15