2

Consider the following:

typedef struct node
{
    int number;
    struct node *left;
    struct node *right;
} node;


node  test[511];
node  *test1 = malloc(511 * sizeof(node));
node  (*test2)[511] = malloc(511 * sizeof(node));

is the following correct:

  1. test is an array of 511 nodes. we can access each node with test[i] where i is the node we want
  2. test1 is a pointer where we malloc space for 511 nodes. we can access each node with test1[i]

so are test and test1 basically the same except test is on the stack and test1 on the heap?

test2 looks like a pointer to an array. does malloc allocate 511 * sizeof(node) to each pointer or to the entire array? if the later then can we access each node with test2[i] and if the former can do the following:

node  (*test2)[511] = malloc(sizeof(node));

and then access each node with test2[i]?

in general whats the difference between *test1 and (*test2)?

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
DCR
  • 14,737
  • 12
  • 52
  • 115
  • Why have you chosen the [tag:operator-precedence] tag? – Fabio says Reinstate Monica Sep 01 '20 at 22:35
  • `test1` and `test` have the same storage class. What's different is the storage of the block to which `test1` points. Don't make the mistake of conflating a pointer with the block it points to. Similarly, `malloc` allocates a block of memory, it does not make sense to say "allocate to (a pointer)" as you write – M.M Sep 01 '20 at 22:39
  • Read section 6 of the [comp.lang.c FAQ](http://www.c-faq.com/). – Keith Thompson Sep 02 '20 at 01:14

6 Answers6

1

The difference is that test1 one is referring the node. test2 is referring the array of 511 node elements.

test1 + 1 will reference the next node object

test2 + 1 will reference the next array of 511 node objects

so are test and test1 basically the same except test is on the stack and test1 on the heap?

No one is an array which can decay to pointer, another is pointer referencing object of type node

When you malloc memory it is better to use objects instead of types

node  test[511];
node  *test1 = malloc(511 * sizeof(*test1));
node  (*test2)[511] = malloc(511 * sizeof(*test2));
{
    int number;
    struct node *left;
    struct node *right;
} node;

int main(void)
{
    node  test[511];
    node  *test1;
    node  (*test2)[511];

    printf("sizeof test = %zu\n", sizeof(test));
    printf("sizeof *test1 = %zu\n", sizeof(*test1));
    printf("sizeof *test2 = %zu\n", sizeof(*test2));
}
typedef struct node
{
    int number;
    struct node *left;
    struct node *right;
} node;

int main(void)
{
    node  test[511];
    node  *test1;
    node  (*test2)[511];

    printf("sizeof test = %zu\n", sizeof(test));
    printf("sizeof *test1 = %zu\n", sizeof(*test1));
    printf("sizeof *test2 = %zu\n", sizeof(*test2));
}
0___________
  • 60,014
  • 4
  • 34
  • 74
1

in general whats the difference between *test1 and (*test2)?

In this declaration

node  *test1 = malloc(511 * sizeof(node));

there is declared a pointer to an object of the type node. So dereferencing the pointer like *test1 you will get an object of the type node. That is you will get access to the first object of the dynamically allocated array.

In this declaration

node  (*test2)[511] = malloc(511 * sizeof(node));

there is declared a pointer to an object of the type node[511]. That is the pointed object has the array type node[511]. Dereferencing the pointer you will get the pointed array that is dynamically allocated.

So sizeof( *test1 ) is equal to sizeof( node ). While sizeof( *test2 ) is equal to sizeof( node[511] ) that is the same as 511 * sizeof( node ).

To access the first element of the allocated array using the pointer test2 you need at first to dereference it to get the pointed array that in turn used in an expression with the member access operator -> is converted implicitly to pointer to its first element.

Here is a demonstrative program.

#include <stdio.h>
#include <stdlib.h>

typedef struct node
{
    int number;
    struct node *left;
    struct node *right;
} node;

int main(void) 
{
    node  *test1 = malloc(511 * sizeof(node));
    node  (*test2)[511] = malloc(511 * sizeof(node));
    
    printf( "sizeof( *test1 ) = %zu\n", sizeof( *test1 ) ); 
    printf( "sizeof( *test2 ) = %zu\n", sizeof( *test2 ) ); 
    
    ( *test1 ).number  = 10;
    ( **test2 ).number = 20;
    
    printf( "test1->number = %d\n", test1->number );
    printf( "( *test2 )->number = %d\n", ( *test2 )->number );
    
    free( test1 );
    free( test2 );
    
    return 0;
}

The program output is

sizeof( *test1 ) = 24
sizeof( *test2 ) = 12264
test1->number = 10
( *test2 )->number = 20

The pointer test2 could be also initialized for example the following way

node  test[511];
node  (*test2)[511] = &test;

While the pointer test1 could be initialized like

 node *test1 = test;
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • but you -> node *test1 = malloc(511 * sizeof(node)); so we've allocated enough space for 511 nodes and can access each one with test[i] . and in node (*test2)[511] = malloc(511 * sizeof(node));; we have an array of 511 pointers, each one pointing to an array of 511 nodes but we only allocated enough for the first pointer – DCR Sep 01 '20 at 22:28
  • @DCR I am sorry I do not see a difference between these two declarations in your comment node *test1 = malloc(511 * sizeof(node)); and node *test1 = malloc(511 * sizeof(node)); – Vlad from Moscow Sep 01 '20 at 22:31
  • sorry about that. node *test1 = malloc(511 * sizeof(node)); so we've allocated enough space for 511 nodes and can access each one with test[i] . and in node (*test2)[511] = malloc(511 * sizeof(node));; we have an array of 511 pointers, each one pointing to an array of 511 nodes but we only allocated enough for the first pointer – DCR Sep 01 '20 at 23:25
  • hence if we do (*test2)[1] = malloc(511 * sizeof(node)) we now have an array with enough memory and can't we access test2[300]? – DCR Sep 01 '20 at 23:27
  • @DCR Careful: `node (*test2)[511]` declares *one* pointer (`test 2`) to an array of 511 nodes. There's no array of 511 pointers. The syntax is confusing. The rule to understand these declarations is called the "right-left" rule (and sometimes the "spiral rule", but [the spiral approach fails in some cases](https://stackoverflow.com/q/16260417/3982001)). I recommend these questions: [How do I understand complicated function declarations?](https://stackoverflow.com/q/1448849/3982001) and [C isn't that hard](https://stackoverflow.com/q/34548762/3982001) – Fabio says Reinstate Monica Sep 01 '20 at 23:48
  • what about node (*test2)[1] = malloc(511 * sizeof(node))? I have a pointer to an array that contains 1 node but i create space for 511 nodes. thus I can access test2[200][0]? – DCR Sep 02 '20 at 00:03
  • @DCR You can consider the following declarations node test[511][1]; node ( *test2 )[1] = test; Or node ( *test2 )[1] = malloc( sizeof( node[511][1] ) ); That is as a pointer to the first element of a two dimensional array. – Vlad from Moscow Sep 02 '20 at 08:24
1

So are test and test1 basically the same except test is on the stack and test1 on the heap?

Yes, freely speaking, we can say that. With a disclaimer, these are different types.

test2 looks like a pointer to an array. does malloc allocate 511 * sizeof(node) to each pointer or to the entire array?

Again, freely speaking we can say to each pointer, wich in this case also happens to be the entire array, as you only allocate 1 block of 511 nodes.

This is a pointer to array of 511, as such you should only assing to it blocks of memory that are multiples of 511 * sizeof(node). You could assign to it something like:

node (*test2)[511] = malloc(sizeof(node) * 511 * 5);

In which case you would have an array of 5 node (*test2)[511]. You can equate this to node test2[5][511] as the access notation is the same.

If the later then can we access each node with test2[i] and if the former can do the following:

node  (*test2)[511] = malloc(sizeof(node));

and then access each node with test2[i]?

This allocation is not correct. test2[0] points to the first block of 511 nodes, specifically to the first element of each block of 511 nodes, test2[1] points to the first element of the next block of 511 nodes, you can't use this pointer to access individual nodes, with the exception of each first node of every block of 511 nodes.

The access to individual nodes must be made with, for instance test2[0][1], for the second node (index 1) of the first block of 511 nodes.

So, again, the allocation must be of blocks of multiples of 511 * sizeof(node).

In general whats the difference between *test1 and (*test2)?

That's it, test1 is a pointer to node, test2 is a pointer to array of 511 nodes. The previous explanations should make the difference noted.

test1 is used to access any member of each block of the node array, test2 is used to access each block of 511 nodes.

anastaciu
  • 23,467
  • 7
  • 28
  • 53
0

is the following correct:

  1. test is an array of 511 nodes. we can access each node with test[i] where i is the node we want

Yes

  1. test1 is a pointer where we malloc space for 511 nodes. we can access each node with test1[i]

Yes.

so are test and test1 basically the same except test is on the stack and test1 on the heap?

There is no concept of stack or heap in C standard, however, keeping that aside, they are not the same. test is an array and test1 is a pointer, they are different types altogether.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
0

I took your code and added also a 4th alternative. And I will post a program and discussion that can be useful on making this a bit more clear.

I believe that this line

    Node*   test1 = malloc(_SIZE_ * sizeof(Node));

is key to understand how things can get confused. malloc() returns just a pointer to an area of the size of the argument. In fact these 2 lines are similar

   int* example =  malloc(511);
   Node*   test1 = malloc(_SIZE_ * sizeof(Node));

and it illustrates why people from C++ make it mandatory to cast a type for the return of malloc() like in

   int*  example =  (int*) malloc(511);
   Node*   test1 = (Node*) malloc(_SIZE_ * sizeof(Node));

it makes things clearer, they said. And I believe. This way we see that test1 is just a pointer to Node and it can warn us that maybe things are going wrong, or may be not as we expected: it makes no difference the number of bytes allocated, it will be a NODE*. A pointer to an area.

back to the test[123] stuff here

test1 as

    Node*   test1 = malloc(_SIZE_ * sizeof(Node));

test1 is just a pointer to Node. malloc() will happily assign how many bytes as it evaluates from the argument. Even less than the size of one Node, and the program may crash real fast... or 511 bytes, making no practical difference in the test but bringing it to this topic in SO :)

test

    #define _SIZE_ 16
    Node    test[_SIZE_];

test is just an array of Node

typedef struct node
{
    int number;
    struct node* left;
    struct node* right;
}   Node;

test2

Node    (*test2)[_SIZE_] = malloc(_SIZE_ * sizeof(Node));

This is not frequently seen because it is not flexible: test2 is a pointer to an array of [_SIZE_] elements of Node. A thing just like test. In fact I will show below that is perfectly ok to write

Node    test[_SIZE_];
Node    (*test2)[_SIZE_] = &test;

because this is just the definition of the thing test2 points to.But as the _SIZE_ must the known at compile time it is rarely used. Instead we have things much more flexible like the familiar

int main(int argc, char** argv);

And introducing test3

Node** test3;

Here test3 is a pointer to an array of pointers to Node, and this is the useful way, as every C or C++ or any program knows about. Let us fill it in

    Node** test3 = (Node**)malloc(sizeof(Node*) * _SIZE_);
    for (int i = 0; i < _SIZE_; i += 1)
    {
        test3[i] = (Node*)malloc(sizeof(Node));
        test3[i]->number = 1000 + i;
    };

Now test3 points to an area of _SIZE_ times the sizeof() of a pointer to NODE. And we go into the area and set up the individual pointers to a real NODE, each and every one. And we put a value into the number member of each Node so we can print it later in the example program.

  • What is the difference? Now we can iterate over the Nodes just like we do over and over again on argv[i]
  • What is missing? The size information. This is why we have argc in every program. We could write
// now to iterate over Nodes: should be as familiar as
typedef struct 
{
    int     nodec;
    Node**  nodev;

}   NodeArray;

so familiar... And we can pass over NodeArrays, iterable arrays of structures, just like the command line arguments...

output of the example

sizeof(test) = 384
sizeof(test1) = 8
sizeof(test2) = 8

test is Node[_SIZE_]. Values are
     0     1     2     3     4     5     6     7     8     9    10    11    12    13    14    15

test2 is a pointer to Node[_SIZE_]. So we can assign &test to it

Done. Now the values of test2:
     0     1     2     3     4     5     6     7     8     9    10    11    12    13    14    15

test2 restored. Now set up from 500
   500   501   502   503   504   505   506   507   508   509   510   511   512   513   514   515

test1 is just a pointer to Node. Let's set it to 300
*test1 is 300

test3 is an array of pointers to Node, set up from 1000:
  1000  1001  1002  1003  1004  1005  1006  1007  1008  1009  1010  1011  1012  1013  1014  1015

Sample code

#define _SIZE_ 16
#include <stdio.h>
#include <stdlib.h>

typedef struct node
{
    int number;
    struct node* left;
    struct node* right;
}   Node;

int main(void)
{
    Node    test[_SIZE_];
    Node*   test1 = malloc(_SIZE_ * sizeof(Node));
    int*    example = malloc(511); // no meaning
    Node    (*test2)[_SIZE_] = malloc(_SIZE_ * sizeof(Node));
    // test2 points to Node[_SIZE_]
    for (int i = 0; i < _SIZE_; i += 1) test[i].number = i;

    printf("sizeof(test) = %zd\n", sizeof(test));
    printf("sizeof(test1) = %zd\n", sizeof(test1));
    printf("sizeof(test2) = %zd\n", sizeof(test2));

    // test is an array of Node
    printf("\ntest is Node[_SIZE_]. Values are \n");
    for (int i = 0; i < _SIZE_; i += 1)
        printf("%6d", test[i].number);
    printf("\n");

    // test2 points to an array of Node
    printf("\ntest2 is a pointer to Node[_SIZE_]. So we can assign &test to it\n");
    void* save = test2; // or it will leak
    test2 = &test;
    printf("\nDone. Now the values of test2:\n");
    for (int i = 0; i < _SIZE_; i += 1)
        printf("%6d", (*test2)[i].number);
    printf("\n");

    test2 = save; // restored
    printf("\ntest2 restored. Now set up from 500\n");
    for (int i = 0; i < _SIZE_; i += 1) (*test2)[i].number = 500 + i;
    for (int i = 0; i < _SIZE_; i += 1)
        printf("%6d", (*test2)[i].number);
    printf("\n");

    // test1 is just a pointer to node
    printf("\ntest1 is just a pointer to Node. Let's set it to 300\n");
    test1->number = 300;
    printf("*test1 is %d\n", test1->number);

    // now to iterate over Nodes: should be as familiar as
    typedef struct 
    {
        int     nodec;
        Node**  nodev;

    }   NodeArray;

    //Node** test3;
    Node** test3 = (Node**)malloc(sizeof(Node*) * _SIZE_);
    for (int i = 0; i < _SIZE_; i += 1)
    {
        test3[i] = (Node*)malloc(sizeof(Node));
        test3[i]->number = 1000 + i;
    };
    // test3 is an array of Node
    printf("\ntest3 is an array of pointers to Node, set up from 1000:\n");
    for (int i = 0; i < _SIZE_; i += 1)
        printf("%6d", test3[i]->number);
    printf("\n");

    // now free() all this
    // test is static
    free(test1); // test1 is Node*
    // test2 is Node (*)[]
    free(test2);
    // test3 is a pointer to an array of pointers...
    for (int i = 0; i < _SIZE_; i += 1) free(test3[i]);
    // all gone
    test3 = NULL; // invalidate it
    printf("\n");
    return 0;
};
arfneto
  • 1,227
  • 1
  • 6
  • 13
-3

i think 1,2 are correct test2 it's an array of pointers and accessing node would be like *test[i] and think the declaration is just like that node (*test2)[511]; without malloc(511 * sizeof(node)) Edit: then filling the array like this

int i = 0;
while (i < 511)
{
 test2[i] = (node*)malloc(sizeof(node));
 i++;
}
bari barix
  • 68
  • 4