kebingungan sintaks dengan array dan pointer
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:
- test adalah array 511 node. kita dapat mengakses setiap node dengan test [i] dimana i adalah node yang kita inginkan
- 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
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));
}
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;
Jadi, apakah
testdantest1pada dasarnya sama kecualitestada di tumpukan dantest1di heap?
Ya, secara bebas, kita bisa mengatakan itu. Dengan penafian, ini adalah jenis yang berbeda.
test2terlihat seperti penunjuk ke larik. tidakmallocmengalokasikan511 * 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.
apakah yang berikut ini benar:
testadalah larik 511 node. kita dapat mengakses setiap node dengan nodetest[i]manaiyang kita inginkan
Iya
test1adalah pointer di mana kita memberimallocjarak untuk 511 node. kita dapat mengakses setiap node dengantest1[i]
Iya.
jadi apakah
testdantest1pada 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.
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 kali
argv[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;
};