Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pointer to 2D arrays in C

Tags:

arrays

c

pointers

I know there is several questions about that which gives good (and working) solutions, but none IMHO which says clearly what is the best way to achieve this. So, suppose we have some 2D array :

int tab1[100][280];

We want to make a pointer that points to this 2D array. To achieve this, we can do :

int (*pointer)[280]; // pointer creation
pointer = tab1; //assignation
pointer[5][12] = 517; // use
int myint = pointer[5][12]; // use

or, alternatively :

int (*pointer)[100][280]; // pointer creation
pointer = &tab1; //assignation
(*pointer)[5][12] = 517; // use
int myint = (*pointer)[5][12]; // use 

OK, both seems to work well. Now I would like to know :

  • what is the best way, the 1st or the 2nd ?
  • are both equals for the compiler ? (speed, perf...)
  • is one of these solutions eating more memory than the other ?
  • what is the more frequently used by developers ?
like image 521
Chrysotribax Avatar asked Feb 11 '13 09:02

Chrysotribax


People also ask

How do you declare a pointer to a 2D array?

A 2D array of pointers can be created following the way shown below. int *arr[5][5]; //creating a 2D integer pointer array of 5 rows and 5 columns. The element of the 2D array is been initialized by assigning the address of some other element.

Is pointer to pointer 2D array?

An array is treated as a pointer that points to the first element of the array. 2D array is NOT equivalent to a double pointer! 2D array is "equivalent" to a "pointer to row".

What is 2D pointer in C?

The first pointer is used to store the address of the variable. And the second pointer is used to store the address of the first pointer. That is why they are also known as double pointers.

What is pointer to an array in C?

When we allocate memory to a variable, pointer points to the address of the variable. Unary operator ( * ) is used to declare a variable and it returns the address of the allocated memory. Pointers to an array points the address of memory block of an array variable.


3 Answers

//defines an array of 280 pointers (1120 or 2240 bytes)
int  *pointer1 [280];

//defines a pointer (4 or 8 bytes depending on 32/64 bits platform)
int (*pointer2)[280];      //pointer to an array of 280 integers
int (*pointer3)[100][280]; //pointer to an 2D array of 100*280 integers

Using pointer2 or pointer3 produce the same binary except manipulations as ++pointer2 as pointed out by WhozCraig.

I recommend using typedef (producing same binary code as above pointer3)

typedef int myType[100][280];
myType *pointer3;

Note: Since C++11, you can also use keyword using instead of typedef

using myType = int[100][280];
myType *pointer3;

in your example:

myType *pointer;                // pointer creation
pointer = &tab1;                // assignation
(*pointer)[5][12] = 517;        // set (write)
int myint = (*pointer)[5][12];  // get (read)

Note: If the array tab1 is used within a function body => this array will be placed within the call stack memory. But the stack size is limited. Using arrays bigger than the free memory stack produces a stack overflow crash.

The full snippet is online-compilable at gcc.godbolt.org

int main()
{
    //defines an array of 280 pointers (1120 or 2240 bytes)
    int  *pointer1 [280];
    static_assert( sizeof(pointer1) == 2240, "" );

    //defines a pointer (4 or 8 bytes depending on 32/64 bits platform)
    int (*pointer2)[280];      //pointer to an array of 280 integers
    int (*pointer3)[100][280]; //pointer to an 2D array of 100*280 integers  
    static_assert( sizeof(pointer2) == 8, "" );
    static_assert( sizeof(pointer3) == 8, "" );

    // Use 'typedef' (or 'using' if you use a modern C++ compiler)
    typedef int myType[100][280];
    //using myType = int[100][280];

    int tab1[100][280];

    myType *pointer;                // pointer creation
    pointer = &tab1;                // assignation
    (*pointer)[5][12] = 517;        // set (write)
    int myint = (*pointer)[5][12];  // get (read)

    return myint;
}
like image 105
oHo Avatar answered Oct 16 '22 16:10

oHo


Both your examples are equivalent. However, the first one is less obvious and more "hacky", while the second one clearly states your intention.

int (*pointer)[280];
pointer = tab1;

pointer points to an 1D array of 280 integers. In your assignment, you actually assign the first row of tab1. This works since you can implicitly cast arrays to pointers (to the first element).

When you are using pointer[5][12], C treats pointer as an array of arrays (pointer[5] is of type int[280]), so there is another implicit cast here (at least semantically).

In your second example, you explicitly create a pointer to a 2D array:

int (*pointer)[100][280];
pointer = &tab1;

The semantics are clearer here: *pointer is a 2D array, so you need to access it using (*pointer)[i][j].

Both solutions use the same amount of memory (1 pointer) and will most likely run equally fast. Under the hood, both pointers will even point to the same memory location (the first element of the tab1 array), and it is possible that your compiler will even generate the same code.

The first solution is "more advanced" since one needs quite a deep understanding on how arrays and pointers work in C to understand what is going on. The second one is more explicit.

like image 20
Ferdinand Beyer Avatar answered Oct 16 '22 15:10

Ferdinand Beyer


int *pointer[280]; //Creates 280 pointers of type int.

In 32 bit os, 4 bytes for each pointer. so 4 * 280 = 1120 bytes.

int (*pointer)[100][280]; // Creates only one pointer which is used to point an array of [100][280] ints.

Here only 4 bytes.

Coming to your question, int (*pointer)[280]; and int (*pointer)[100][280]; are different though it points to same 2D array of [100][280].

Because if int (*pointer)[280]; is incremented, then it will points to next 1D array, but where as int (*pointer)[100][280]; crosses the whole 2D array and points to next byte. Accessing that byte may cause problem if that memory doen't belongs to your process.

like image 10
Jeyaram Avatar answered Oct 16 '22 15:10

Jeyaram