kebingungan sintaks dengan array dan pointer

Sep 01 2020

Pertimbangkan hal berikut:

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));

apakah yang berikut ini benar:

  1. test adalah array 511 node. kita dapat mengakses setiap node dengan test [i] dimana i adalah node yang kita inginkan
  2. test1 adalah pointer di mana kita malloc spasi untuk 511 node. kita dapat mengakses setiap node dengan test1 [i]

jadi apakah test dan test1 pada dasarnya sama kecuali test ada di stack dan test1 di heap?

test2 terlihat seperti penunjuk ke array. apakah malloc mengalokasikan 511 * sizeof (node) ke setiap pointer atau ke seluruh array? jika nanti maka dapat kita akses setiap node dengan test2 [i] dan jika sebelumnya dapat melakukan hal berikut:

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

dan kemudian mengakses setiap node dengan test2 [i]?

secara umum apa perbedaan antara * test1 dan (* test2)?

Jawaban

1 P__JsupportswomeninPoland Sep 01 2020 at 22:10

Perbedaannya adalah yang test1satu mengacu pada node. test2merujuk pada larik 511 nodeelemen.

test1 + 1akan mereferensikan nodeobjek berikutnya

test2 + 1akan mereferensikan array 511 nodeobjek berikutnya

jadi apakah test dan test1 pada dasarnya sama kecuali test ada di stack dan test1 di heap?

Tidak ada satu array pun yang dapat meluruh menjadi penunjuk, yang lainnya adalah penunjuk yang merujuk objek bertipe node

Saat Anda mallocmengingat, lebih baik menggunakan objek daripada tipe

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));
}
1 VladfromMoscow Sep 01 2020 at 22:22

secara umum apa perbedaan antara * test1 dan (* test2)?

Dalam deklarasi ini

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

ada dinyatakan pointer ke objek tipe node. Jadi dereferensi penunjuk seperti *test1Anda akan mendapatkan objek bertipe node. Artinya, Anda akan mendapatkan akses ke objek pertama dari larik yang dialokasikan secara dinamis.

Dalam deklarasi ini

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

ada dinyatakan pointer ke objek tipe node[511]. Yaitu objek runcing yang memiliki tipe array node[511]. Dereferensi penunjuk, Anda akan mendapatkan larik runcing yang dialokasikan secara dinamis.

Begitu sizeof( *test1 )pula dengan sizeof( node ). Sedangkan sizeof( *test2 )sama dengan sizeof( node[511] )itu sama dengan 511 * sizeof( node ).

Untuk mengakses elemen pertama dari array yang dialokasikan menggunakan pointer, test2pertama-tama Anda perlu melakukan dereferensi untuk mendapatkan array berujung yang pada gilirannya digunakan dalam ekspresi dengan operator akses anggota -> diubah secara implisit menjadi pointer ke elemen pertamanya.

Berikut adalah program demonstratif.

#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;
}

Keluaran program adalah

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

Penunjuk test2juga bisa diinisialisasi misalnya dengan cara berikut

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

Sedangkan penunjuk test1bisa diinisialisasi seperti

 node *test1 = test;
1 anastaciu Sep 01 2020 at 22:30

Jadi, apakah testdan test1pada dasarnya sama kecuali testada di tumpukan dan test1di heap?

Ya, secara bebas, kita bisa mengatakan itu. Dengan penafian, ini adalah jenis yang berbeda.

test2terlihat seperti penunjuk ke larik. tidak mallocmengalokasikan 511 * sizeof(node)ke setiap penunjuk atau ke seluruh larik?

Sekali lagi, secara bebas kita dapat mengatakan kepada setiap penunjuk, yang dalam hal ini juga merupakan keseluruhan larik, karena Anda hanya mengalokasikan 1 blok dari 511 node.

Ini adalah penunjuk ke larik 511, karena itu Anda hanya perlu memasukkannya ke blok memori yang merupakan kelipatan 511 * sizeof(node). Anda dapat menetapkan sesuatu seperti:

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

Dalam hal ini Anda akan memiliki larik 5 node (*test2)[511]. Anda dapat menyamakan ini node test2[5][511]karena notasi aksesnya sama.

Jika nanti maka dapat kita akses setiap node dengan test2[i]dan jika sebelumnya dapat melakukan hal berikut:

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

dan kemudian mengakses setiap node dengan test2[i]?

Alokasi ini tidak benar. test2[0]menunjuk ke blok pertama dari 511 node, khususnya ke elemen pertama dari setiap blok dari 511 node, test2[1]menunjuk ke elemen pertama dari blok berikutnya yang terdiri dari 511 node, Anda tidak dapat menggunakan pointer ini untuk mengakses node individual, dengan pengecualian setiap node pertama dari setiap blok 511 node.

Akses ke node individu harus dibuat dengan, misalnya test2[0][1], untuk node kedua (indeks 1) dari blok pertama dari 511 node.

Jadi, sekali lagi, alokasi harus berupa blok kelipatan 511 * sizeof(node).

Secara umum, apa perbedaan antara *test1dan (*test2)?

Itu saja, test1adalah penunjuk ke node, test2adalah penunjuk ke array 511 node. Penjelasan sebelumnya harus membuat perbedaan diperhatikan.

test1digunakan untuk mengakses setiap anggota dari setiap blok dari array node, test2digunakan untuk mengakses setiap blok dari 511 node.

SouravGhosh Sep 01 2020 at 22:09

apakah yang berikut ini benar:

  1. testadalah larik 511 node. kita dapat mengakses setiap node dengan node test[i]mana iyang kita inginkan

Iya

  1. test1adalah pointer di mana kita memberi mallocjarak untuk 511 node. kita dapat mengakses setiap node dengantest1[i]

Iya.

jadi apakah testdan test1pada dasarnya sama kecuali test ada di stack dan test1 di heap?

Tidak ada konsep stack atau heap dalam standar C, namun, mengesampingkan hal itu, keduanya tidak sama. testadalah sebuah larik dan test1penunjuk, keduanya adalah tipe yang berbeda secara bersamaan.

arfneto Sep 02 2020 at 01:02

Saya mengambil kode Anda dan menambahkan juga alternatif ke-4. Dan saya akan memposting program dan diskusi yang dapat berguna untuk membuat ini lebih jelas.

Saya percaya bahwa baris ini

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

adalah kunci untuk memahami bagaimana segala sesuatunya bisa membingungkan. malloc()mengembalikan hanya penunjuk ke area seukuran argumen. Faktanya 2 baris ini serupa

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

dan itu menggambarkan mengapa orang dari C ++ mewajibkan untuk mentransmisikan tipe untuk kembalinya malloc()like in

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

itu membuat segalanya lebih jelas, kata mereka. Dan saya percaya. Dengan cara ini kita melihat bahwa test1itu hanyalah sebuah penunjuk ke Nodedan itu dapat memperingatkan kita bahwa mungkin ada yang salah, atau mungkin tidak seperti yang kita harapkan: tidak ada bedanya jumlah byte yang dialokasikan, itu akan menjadi a NODE*. Penunjuk ke suatu area.

kembali ke tes [123] di sini

test1 sebagai

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

test1hanyalah penunjuk ke Node. malloc()akan dengan senang hati menetapkan berapa byte yang dievaluasi dari argumen. Bahkan ukurannya lebih kecil dari satu Node, dan program mungkin macet sangat cepat ... atau 511 byte, tidak membuat perbedaan praktis dalam pengujian tetapi membawanya ke topik ini di SO :)

uji

    #define _SIZE_ 16
    Node    test[_SIZE_];

test hanyalah sebuah array dari Node

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

tes2

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

Ini tidak sering terlihat karena tidak fleksibel: test2adalah penunjuk ke larik [_SIZE_]elemen Node. Sesuatu seperti itu test. Sebenarnya saya akan menunjukkan di bawah ini bahwa tidak masalah untuk menulis

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

karena ini hanya definisi dari hal yang test2ditunjukkan, tetapi sebagai _SIZE_keharusan yang harus diketahui pada saat kompilasi jarang digunakan. Sebaliknya kami memiliki hal-hal yang jauh lebih fleksibel seperti yang biasa

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

Dan memperkenalkan test3

Node** test3;

Berikut test3adalah pointer ke array pointer ke Node, dan ini adalah cara yang berguna, karena setiap C atau C ++ atau program apa pun tahu tentangnya. Mari kita isi

    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;
    };

Sekarang test3menunjuk ke area _SIZE_dengan sizeof()waktu penunjuk ke NODE. Dan kami pergi ke area tersebut dan menyiapkan petunjuk individu ke nyata NODE, masing-masing dan setiap orang. Dan kami memasukkan nilai ke dalam jumlah anggota setiap Node sehingga kami dapat mencetaknya nanti di program contoh.

  • Apa bedanya? Sekarang kita dapat melakukan iterasi pada Nodes seperti yang kita lakukan berulang kaliargv[i]
  • Apa yang hilang? Informasi ukuran. Inilah mengapa kami ada argcdi setiap program. Kami bisa menulis
// now to iterate over Nodes: should be as familiar as
typedef struct 
{
    int     nodec;
    Node**  nodev;

}   NodeArray;

sangat familiar ... Dan kita bisa melewatkan NodeArrays, susunan struktur yang dapat diulang, seperti argumen baris perintah ...

keluaran contoh

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

Kode sampel

#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;
};