1

As per this https://stackoverflow.com/a/3912959/1814023 We can declare a function which accepts 2D array as

void func(int array[ROWS][COLS]).

And as per this, http://c-faq.com/aryptr/pass2dary.html they say "Since the called function does not allocate space for the array, it does not need to know the overall size, so the number of rows, NROWS, can be omitted. The width of the array is still important, so the column dimension NCOLUMNS (and, for three- or more dimensional arrays, the intervening ones) must be retained."

I tried this and it works... Note that I have changed the size of column.

#include <stdio.h>
#define ROWS 4
#define COLS 5

void func1(int myArray[][25])
{
    int i, j;

    for (i=0; i<ROWS; i++)
    {
        for (j=0; j<COLS; j++)
        {
            myArray[i][j] = i*j;
            printf("%d\t",myArray[i][j]);
        }
        printf("\n");
    }
}

int main(void)
{
    int x[ROWS][COLS] = {0};
    func1(x);
    getch();
    return 0;
}

My question is, why in the CFAQ link(http://c-faq.com/aryptr/pass2dary.html) they say "The width of the array is still important"? even though I have provided wrong column size. Can someone please explain?

Community
  • 1
  • 1
StackIT
  • 1,172
  • 2
  • 13
  • 25
  • That shouldn't compile, really. You're trying to pass a `int(*)[5]` (after decay, of course) as a `int(*)[25]`. – chris Oct 25 '13 at 11:58
  • 3
    Simple enough, actually. To index an element in the first row (row 0) you just need to know the column number. `index = col`. When row is 0, the width is unimportant. However to access an element on any other row, you must also know the number of columns wide it is, since the equation then becomes `index = row*numCols + col` - So, what you've done should crash. If it doesn't, it's just luck each time you execute it. The idea of setting COLS to 25 means that when i=ROWS-1 and j=COLS-1, means that for the last element, index is calculated as `index = (4-1)*25 + (5-1)`!! Baaaad! – enhzflep Oct 25 '13 at 12:07
  • @chris: it 'compiles' because the code is calling `func()` but defines `func1()`. So the called function isn't the defined function (aka 'there is a typo in the question'). You should still get warnings (at least) for calling an undeclared function, if you use a C99 or later compiler. Since the code uses `getch()`, it is probably running on Windows and therefore is using an antique C89 compiler (aka MSVC). – Jonathan Leffler Oct 25 '13 at 13:40
  • @JonathanLeffler, Oh, good catch, although I can say I use a modern C compiler on Windows when I have to use C :p – chris Oct 25 '13 at 13:43
  • @JonathanLeffler: Sorry for the mistake in function mismatch. I did modified the code and executed on (gcc)Mingw. and on Visual studio 2010. Both compilers are giving warning. But what I didn't understand is, why we need to pass the column size. Even I did pass 1 as the column size and it worked. I know when the compile does myArray[1][2], internally it will treat it as *(*(myArray+1)+2). I did not understand the concept of passing column size to function. – StackIT Oct 28 '13 at 04:16
  • @enhzflep: Sorry for the mistake in function mismatch. I did modified the code and executed on (gcc)Mingw. and on Visual studio 2010. Both compilers are giving warning. But what I didn't understand is, why we need to pass the column size. Even I did pass 1 as the column size and it worked. I know when the compile does myArray[1][2], internally it will treat it as *(*(myArray+1)+2). I did not understand the concept of passing column size to function. – StackIT Oct 28 '13 at 04:17
  • @Patil - It's no problem for mismatch. When you tell a person to write at the beginning of line 2 of a piece of lined paper, it's obvious where they should start - they can see the lines. For a computer dealing with an array however, there is not a visual cue. If we assume each letter needs a single cell, The computer must know how many cells make up a line, so it can count (cells_per_line * numLines) = starting cell of desired line. It is the same here - if the computer doesn't know how many elements are in each row, it doesn't know how to find the start of any given row. – enhzflep Oct 28 '13 at 06:08
  • Both compilers are correct to give a warning. Your function expects an array with 25 columns per row; you are passing an array with 5 columns per row. When you ignore the warning, the addresses end up such that the function treats the 20 integers in the array you pass as part of the first row of the array you claim to pass; it then goes on to access memory thoroughly out of bounds, with indeterminate results (you're invoking undefined behaviour; anything can happen). Usually, what happens is that the code reads other variables, or parts of the stack, getting addresses etc instead of numbers. – Jonathan Leffler Oct 28 '13 at 06:18
  • @Patil Compile with warnings enabled and you'll se that what you're doing is not "right" or "correct". –  Oct 28 '13 at 07:58

2 Answers2

1

This is what you get for using array notations to represent pointers. Contrived example:

#include <stdio.h>

void size(int myArray[][25], int rows, int cols)
{
    printf("sizeof(int [%d][%d]) = %d\n", rows, cols, sizeof(myArray));
}

int main(void)
{
    int arr1[4][4];
    int arr2[4][5];
    int arr3[5][5];

    size(arr1, 4, 4);
    size(arr2, 4, 5);
    size(arr3, 5, 5);

    printf("sizeof(int *) = %d\n", sizeof(int *));

    return 0;
}

If you try to run this, all 4 sizes will be the same, even though the arrays passed are of different sizes.
Array types in C is just syntactic sugar - multidimensional arrays make no sense in a linear memory model. With linear memory model to access an element of a simple array you must know 2 things: base address and index offset, so you can write *(base+indexOffset). To index an element in a two dimensional array you must know two additional things: size of your first dimension and its offset, so you can write *(base+dimensionSize*dimensionOffset+indexOffset). Array notation just does all this complicated math for you, but you must still provide the required data to the compiler. Its up to you to ensure data integrity :)

friendzis
  • 799
  • 6
  • 17
0

When I compile and run your program (after fixing the func/func1 confusion and altering the getch, on Ubuntu 12.04) this is what happens

$ gcc crashme.c -o crashme
crashme.c: In function ‘main’:
crashme.c:23:13: warning: passing argument 1 of ‘func1’ from incompatible pointer type [enabled by default]
crashme.c:4:6: note: expected ‘int (*)[25]’ but argument is of type ‘int (*)[5]’
jamie@jamie-Ideapad-Z570:~/temp$ ./crashme 
0   0   0   0   0   
0   1   2   3   4   
0   2   4   6   8   
0   3   6   9   12  
Segmentation fault (core dumped)

If you add a line

printf("%ld", sizeof(x));

Immediately after the int x[ declaration you will see that the size is that of a 4 x 5 x sizeof int ( 80 on my system ) so the declaration size is available to sizeof and so useful for malloc calls etc.

Vorsprung
  • 32,923
  • 5
  • 39
  • 63