c - How memory address for pointer to arrays is same as an element in 2D array? - Stack Overflow

Consider the following code:#include <stdio.h>int main(){int **s = (int**)malloc(3 * sizeof(int

Consider the following code:

#include <stdio.h>

int main()
{
    int **s = (int**)malloc(3 * sizeof(int*));
    for (int i = 0; i < 3; i++)
    {
        printf("%d\n", s+i);
    }

    for (int i = 0; i < 3; i++)
    {
        s[i] = (int*)malloc(3 * sizeof(int));
    }

    for (int i = 0; i < 3; i++)
    {
        printf("%d\n", s+i);
    }
    printf("\n");
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            printf("%d\n", *(s+i)+j);
        }
    }
    printf("\n");
    int s2[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    for (int i = 0; i < 3; i++)
    {
        printf("%d\n", s2+i);
    }
    printf("\n");
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            printf("%d\n", *(s2+i)+j);
        }
    }
}

The output in terminal was:

You can see when I dynamically allocated memory, the memory address where the pointer to each row was stored is different from the address of the first element of each of those rows, which seems expected to me. But in case of defining a 2D array, the address where the pointer to each row array is stored is same as the address of the first element of each of the row. It seems to me that in the same memory location, a pointer to array and an element is kept, which seems unexpected to me. Can anyone explain it in detail?

Consider the following code:

#include <stdio.h>

int main()
{
    int **s = (int**)malloc(3 * sizeof(int*));
    for (int i = 0; i < 3; i++)
    {
        printf("%d\n", s+i);
    }

    for (int i = 0; i < 3; i++)
    {
        s[i] = (int*)malloc(3 * sizeof(int));
    }

    for (int i = 0; i < 3; i++)
    {
        printf("%d\n", s+i);
    }
    printf("\n");
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            printf("%d\n", *(s+i)+j);
        }
    }
    printf("\n");
    int s2[3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    for (int i = 0; i < 3; i++)
    {
        printf("%d\n", s2+i);
    }
    printf("\n");
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            printf("%d\n", *(s2+i)+j);
        }
    }
}

The output in terminal was:

You can see when I dynamically allocated memory, the memory address where the pointer to each row was stored is different from the address of the first element of each of those rows, which seems expected to me. But in case of defining a 2D array, the address where the pointer to each row array is stored is same as the address of the first element of each of the row. It seems to me that in the same memory location, a pointer to array and an element is kept, which seems unexpected to me. Can anyone explain it in detail?

Share Improve this question edited Mar 2 at 14:52 chqrlie 145k12 gold badges135 silver badges213 bronze badges asked Mar 2 at 13:41 M. Saamin RahmanM. Saamin Rahman 2033 bronze badges 3
  • Then answer to your question is simple. Because heap allocator allocates the amount of memory you requested, by finding the continuous blocks which are available meaning not in use and marked it use and return starting address of the block. Note: heap is unanised memory pool, unlike stack. So malloc always searches for a block with requested memory size which is available (not in use) and marked it allocates, this need not be continuous, because the continuous might be already in use so it always find a free continuous blocks of memory (not in use). – Nalan PandiKumar Commented Mar 2 at 14:31
  • While stack in the other hand, is anised memory region. It allocates the memory contiguously unlike heap, so you're seeing that statically allocated dynamic array contains same address for row pointers and their first elements, while the dynamically allocated arrays are not. – Nalan PandiKumar Commented Mar 2 at 14:33
  • Your first example is allocating an array of pointers in segmented memory, each pointing at the first item in an array. Your second example is allocating a 2D array. These are different things. See Correctly allocating multi-dimensional arrays. – Lundin Commented Mar 3 at 10:10
Add a comment  | 

3 Answers 3

Reset to default 3

The correct conversion format specification for printing a pointer is %p, not %d. By using the wrong conversion format specification, your program is invoking undefined behavior. Using %d may work on some platforms, but may fail on other platforms.

Also, in C, there is no reason to cast the result of malloc. See the following question for further information:

Should I cast the result of malloc (in C)?


In your question, you wrote:

But in case of defining a 2D array, the address where the pointer to each row array is stored is same as the address of the first element of each of the row.

When you define a 2D array, there is no such thing as a "pointer to each row".

The difference between a 2D array and an array of pointers to rows is that the latter has a layer of indirection (i.e. a layer of pointers which must be dereferenced), while the former does not. A 2D array is simply an array of arrays, which is stored contiguously.

Unless you have a jagged array, there is no reason for this level of indirection and you can use a 2D array instead.

When using an array in an expression, in most situations, this array will decay to a pointer to the first element of the array. This is what is happening in this line of your code:

printf("%d\n", s2+i);

In that line, writing s2 is equivalent to writing &s2[0].

The same applies to this line:

printf("%d\n", *(s2+i)+j);

You appear to be under the impression that when dynamic memory allocation is used, you can't create a 2D array and must create an array of pointers to rows instead. However, this impression is incorrect. You can dynamically allocate memory for a 2D array of size 3x3 like this:

int (*s)[3] = malloc(sizeof(int[3][3]));

The declaration int (*s)[3] may be hard to understand at first. But if we read it inside out, it is easy:

  • *s means that you can apply the * dereference operator on s, so s must be a pointer.

  • (*s)[3] means that you can index into (*s) using the [] subscript operator, so (*s) must be an array. The value 3 specifies the size of the array.

  • int (*s)[3] means that (*s)[3] is an int. This is not quite correct because using the index 3 would be an out of bounds access. However, it is correct if you ignore the invalid index value.

This means that the declared pointer s is of type "pointer to array of 3 elements of type int". So it is a pointer to the first row of the 3x3 2D array. This means that you can use this pointer to index into the 2D array, for example like this:

s[2][2]

This works because s[2] will yield a (one-dimensional) sub-array which represents a single row. You can index into this sub-array like any other one-dimensional array.

Note that the parentheses in (*s) are necessary, because int *s[3] would declare an array of 3 elements of type int *, whereas int (*s)[3] declares a pointer to an array of 3 elements of type int. This is because the [] subscript operator has higher precedence than the * dereference operator.

You may find the web site cdecl. useful in decoding complex C declarations.

But in case of defining a 2D array, the address where the pointer to each row array is stored is same as the address of the first element of each of the row

There are no pointers to rows stored in a 2D array. All arrays, whether they have one or more dimensions are a contiguous sequence of elements. Arrays and pointers are somewhat related to each other however, an an array decays to a pointer to its first element when used in an expression.

In the case of int s2[3][3], we have a sequence of 3 array elements of type int [3], and each of those in turn is a sequence of elements of type int. This means that &s2, &s2[0], and &s2[0][0] all have the same address (although the their types are different), and that &s2[1] and &s2[1][0] have the same address, as do &s2[2] and &s2[2][0].

A diagram will make this more apparent:

|               s2                  |
|   s2[0]   |   s2[1]   |   s2[2]   |
-------------------------------------
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
-------------------------------------

Also, when printing pointer values, you should use the %p format specifier, as the %d format specifier expects an int (or a type that gets promoted to int) as its argument.

s is an array of pointers.

                       +-------+             +-------+             +-------+
                   +-->|       | 12'20   +-->|       | 12'52   +-->|       | 12'84
                   |   +-------+         |   +-------+         |   +-------+
                   |   |       | 12'24   |   |       |         |   |       |
                   |   +-------+         |   +-------+         |   +-------+
                   |   |       | 12'28   |   |       |         |   |       |
                   |   +-------+         |   +-------+         |   +-------+
        s          |                     |                     |
       +-------+   |                     |                     |
       |      -----+                     |                     |
       +-------+                         |                     |
       |      ---------------------------+                     |
       +-------+                                               |
       |      -------------------------------------------------+
       +-------+

There are four memory blocks.


s2 is a 2d array.

        s2
       +-----------+
       | +-------+ |
64'52  | |       | |
       | +-------+ |
64'56  | |       | |
       | +-------+ |
64'60  | |       | |
       | +-------+ |
       +-----------+
       | +-------+ |
64'64  | |       | |
       | +-------+ |
       | |       | |
       | +-------+ |
       | |       | |
       | +-------+ |
       +-----------+
       | +-------+ |
64'76  | |       | |
       | +-------+ |
       | |       | |
       | +-------+ |
       | |       | |
       | +-------+ |
       +-----------+

There's a single memory block.


To dynamically allocate a 2d array, you'd need the following:

int (*s3)[ num_cols ] = malloc( num_rows * sizeof( int (*)[ num_cols ] ) );

s3[ y ][ x ]

Or you could create a flat array.

int *s4 = malloc( num_rows * num_cols * sizeof( int ) );

s4[ y * num_cols + x ]

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745121451a4612437.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信