0

I'm a beginner and am trying to understand how multidimensional arrays work

Please look at this code:

#include<stdio.h>

void getData(int c;int *a,int r,int c)
{
    for(int i=0;i<r;i++)
        for(int j=0;j<c;j++)
            scanf("%d",(*(a+i)+j)); //warning 
    return;
}

void putData(int c;int *a,int r,int c)
{
    for(int i=0;i<r;i++)
        for(int j=0;j<c;j++)
            printf("%d",*(*(a+i)+j));  //error
    printf("\n");
}

int main(void)
{
    int r1,r2,c1,c2;
    printf("Enter order of A:\n");
    scanf("%d %d",&r1,&c1);
    printf("Enter order of B:\n");
    scanf("%d %d",&r2,&c2);
    int a[r1][c1],b[r2][c2];
    getData((int *)a,r1,c1);
    getData((int *)b,r2,c2);
    putData((int *)b,r2,c2);
}

I'm having trouble with understanding how the pointers are passed to the functions and the cause for the errors. But I think if i can understand how the pointers work then I might be able to debug it. Please help! Thanks!

Edit: I really want to understand how the pointer works with the addressed and stuff. So if there is some sort of tracing, it might help me

bobthebuilder
  • 184
  • 14
  • 1
    When indexing a 1D array the function knows how to index the array based on the type of the data. For example when you use an integer, let’s say one integer takes up 4 bytes (machine dependent) when you pass array, you pass a pointer to the first element in the array, the function can then find arr[1] by incrementing the pointer by the size of an integer, for example 4 bytes. Think of what extra info the function might need if it is a 2D array and you try to access arr[0][1] – liamcomp Apr 12 '19 at 01:26
  • so should it be `*(*(a*i)+j)` ? – bobthebuilder Apr 12 '19 at 01:29
  • unfortunately I don’t have time right now. Hopefully someone will help, if not I’ll come back tomorrow. I would look up something like “how a 2D array is passed to a function”. – liamcomp Apr 12 '19 at 01:37
  • Possible duplicate of [How to pass 2D array (matrix) in a function in C?](https://stackoverflow.com/questions/3911400/how-to-pass-2d-array-matrix-in-a-function-in-c) – Mark Benningfield Apr 12 '19 at 01:49
  • none of the answers talk about how the pointers are used to access elements – bobthebuilder Apr 12 '19 at 01:55
  • You must recognize the `int a[r1][c1],b[r2][c2];` declare `a` and `b` as *Variable Length Arrays* (VLAs). In order to pass the VLA you need `void getData(int r,int c, a[r][c])` so that `r` and `c` are defined before the paramenter `a[r][c]` in the parameter-list. – David C. Rankin Apr 12 '19 at 02:01
  • what if I want to use pointers in the getData function? – bobthebuilder Apr 12 '19 at 02:03
  • No problem -- up to you, e.g. `void putData (int r, int c, int (*a)[c])` and `printf (" %2d", *(*(a + i) + j));` – David C. Rankin Apr 12 '19 at 02:14
  • 1
    `void getData(int c;int *a,int r,int c)` is a syntax error – M.M Apr 12 '19 at 02:30
  • when compiling, always enable the warnings, then fix those warnings. ( for `gcc`, at a minimum use: `-Wall -Wextra -Wconversion -pedantic -std=gnu11` ) Note: other compilers use different options to produce the same results. – user3629249 Apr 12 '19 at 21:31

1 Answers1

3

When you pass a VLA as a parameter (or any 2D array for that matter), you must at minimum pass the number of elements per-row so you can declare a complete type for your VLA (2D array).

While you can pass:

void getData (int r, int c, int a[r][c])

You can also pass:

void getData (int r, int c, int (*a)[c])

(as the first level of indirection is converted to a pointer, see: C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3) -- and note the exceptions)

c must be included in the parameter list before a or the type for a will be incomplete as c is not yet defined.

While you can write *(*(a + i) + j) as equivalent pointer notation for a[i][j] -- don't, it is less readable (but totally equivalent).

Always, ALWAYS, always validate EVERY input. Otherwise you risk invoking Undefined Behavior following in input or matching failure with scanf, e.g.

    printf("Enter order of A:\n");
    if (scanf ("%d %d", &r1, &c1) != 2) {   /* validate EVERY input */
        fputs ("error: invalid input (r1, c1).\n", stderr);
        return 1;
    }

Putting it altogether, you could do:

#include <stdio.h>
#include <stdlib.h> /* for EXIT_FAILURE */

void getData (int r, int c, int (*a)[c])
{
    for (int i = 0; i < r; i++)
        for (int j = 0; j < c; j++)
            if (scanf ("%d", &a[i][j]) != 1) {
                fputs ("error: invalid input a[i][j].\n", stderr);
                exit (EXIT_FAILURE);
            }
}

void putData (int r, int c, int (*a)[c])
{
    for (int i = 0; i < r; i++) {
        for(int j = 0; j < c; j++)
            printf (" %2d", a[i][j]);   /* more readable */
            /* printf (" %2d", *(*(a + i) + j)); */
        putchar ('\n');  /* use putchar for a single char, instead of printf */
    }
}

int main(void)
{
    int r1, r2, c1, c2;

    printf ("Enter order of A:\n");
    if (scanf ("%d %d", &r1, &c1) != 2) {   /* validate EVERY input */
        fputs ("error: invalid input (r1, c1).\n", stderr);
        return 1;
    }

    printf ("Enter order of B:\n");
    if (scanf ("%d %d", &r2, &c2) != 2) {   /* validate EVERY input */
        fputs ("error: invalid input (r2, c2).\n", stderr);
        return 1;
    }
    int a[r1][c1], b[r2][c2];

    getData (r1, c1, a);
    getData (r2, c2, b);

    puts ("a");
    putData (r1, c1, a);
    puts ("\nb");
    putData (r2, c2, b);
}

(note: the inclusion of stdlib.h for the EXIT_FAILURE macro, and note the additional spacing in the code -- helps older eyes)

Example Use/Output

$ echo "2 3 2 3 1 2 3 4 5 6 7 8 9 10 11 12" | ./bin/scanfvla
Enter order of A:
Enter order of B:
a
  1  2  3
  4  5  6

b
  7  8  9
 10 11 12

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85