Penempatan tanda bintang di deklarasi penunjuk

95

Baru-baru ini saya memutuskan bahwa saya akhirnya harus belajar C / C ++, dan ada satu hal yang tidak terlalu saya mengerti tentang pointer atau lebih tepatnya, definisi mereka.

Bagaimana dengan contoh ini:

  1. int* test;
  2. int *test;
  3. int * test;
  4. int* test,test2;
  5. int *test,test2;
  6. int * test,test2;

Sekarang, menurut pemahaman saya, tiga kasus pertama semuanya melakukan hal yang sama: Test bukanlah int, tetapi pointer ke satu.

Kumpulan contoh kedua sedikit lebih rumit. Dalam kasus 4, baik test dan test2 akan menjadi pointer ke int, sedangkan dalam kasus 5, hanya test yang merupakan pointer, sedangkan test2 adalah int "nyata". Bagaimana dengan kasus 6? Sama seperti kasus 5?

Michael Stum
sumber
10
Dalam C / C ++ spasi putih tidak mengubah arti.
Sulthan
19
7. int*test;?
Jin Kwon
3
+1 karena saya hanya berpikir untuk menanyakan tentang 1 - 3. Membaca pertanyaan ini mengajari saya sesuatu tentang 4 - 6 yang tidak pernah saya pikirkan.
Vastlysuperiorman
@Sulthan Itu benar 99% dari waktu, tetapi tidak selalu. Di bagian atas kepala saya ada jenis jenis templated dalam persyaratan ruang jenis templated (pra C ++ 11). Dalam Foo<Bar<char>>yang >>harus ditulis > >agar tidak diperlakukan sebagai-shift kanan.
AnorZaken
3
@AnorZaken Anda benar, itu komentar yang agak lama. Ada beberapa situasi ketika spasi akan berubah arti, misalnya, ++operator increment tidak dapat dipisahkan oleh spasi, pengenal tidak dapat dipisahkan oleh spasi (dan hasilnya masih legal untuk compiler tetapi dengan perilaku runtime yang tidak ditentukan). Situasi sebenarnya sangat sulit untuk didefinisikan mengingat kekacauan sintaks C / C ++.
Sulthan

Jawaban:

128

4, 5, dan 6 adalah hal yang sama, hanya tes adalah sebuah pointer. Jika Anda menginginkan dua petunjuk, Anda harus menggunakan:

int *test, *test2;

Atau, bahkan lebih baik (untuk memperjelas semuanya):

int* test;
int* test2;
Milan Babuškov
sumber
3
Jadi Kasus 4 sebenarnya adalah jebakan maut? Apakah ada spesifikasi atau bacaan lebih lanjut yang menjelaskan mengapa int * test, test2 hanya membuat variabel pertama sebagai pointer?
Michael Stum
8
@ Michael Stum Ini C ++ jadi apakah menurut Anda ada penjelasan yang logis?
Joe Phillips
6
Baca K&R (Bahasa Pemrograman C). Ini menjelaskan semua ini dengan sangat jelas.
Ferruccio
8
Kasus 4, 5 dan 6 adalah "perangkap maut". Inilah salah satu alasan mengapa banyak gaya C / C ++ yang menyarankan hanya satu deklarasi per pernyataan.
Michael Burr
14
Spasi kosong tidak signifikan untuk kompiler C (mengabaikan preprocessor). Jadi tidak peduli berapa banyak ruang yang ada atau tidak antara asterisk dan sekitarnya, itu memiliki arti yang persis sama.
ephemient
45

Ruang putih di sekitar tanda bintang tidak memiliki arti. Ketiganya memiliki arti yang sama:

int* test;
int *test;
int * test;

" int *var1, var2" Adalah sintaksis jahat yang hanya dimaksudkan untuk membingungkan orang dan harus dihindari. Ini berkembang menjadi:

int *var1;
int var2;
Ates Goral
sumber
16
Jangan lupa int*test.
Mateen Ulhaq
2
ruang sebelum atau sesudah tanda bintang hanyalah masalah estetika. Namun, standar Google Coding sesuai dengan int *test( google-styleguide.googlecode.com/svn/trunk/… ).
@SebastianRaschka Panduan Gaya Google C ++ secara eksplisit mengizinkan penempatan tanda bintang. Mungkin sudah berubah sejak Anda membacanya.
Jared Beck
33

Banyak pedoman pengkodean menyarankan Anda hanya mendeklarasikan satu variabel per baris . Ini untuk menghindari kebingungan apa pun yang Anda alami sebelum mengajukan pertanyaan ini. Sebagian besar programmer C ++ yang pernah bekerja dengan saya tampaknya tetap berpegang pada ini.


Sedikit tambahan yang saya tahu, tetapi sesuatu yang menurut saya berguna adalah membaca deklarasi secara terbalik.

int* test;   // test is a pointer to an int

Ini mulai bekerja dengan sangat baik, terutama ketika Anda mulai mendeklarasikan pointer const dan menjadi sulit untuk mengetahui apakah pointer itu adalah const, atau apakah hal yang ditunjuk pointer itu adalah const.

int* const test; // test is a const pointer to an int

int const * test; // test is a pointer to a const int ... but many people write this as  
const int * test; // test is a pointer to an int that's const
Scott Langham
sumber
Meskipun "satu variabel per baris" tampaknya berguna, kami masih belum sepenuhnya menyelesaikan situasi di mana tanda bintang lebih ke kiri, atau lebih ke kanan. Saya cukup yakin bahwa dalam kode di alam bebas satu varian berlaku; agak seperti beberapa negara mengemudi di sisi kanan, dan yang lainnya mengemudi ke arah yang salah, seperti Inggris. ;-)
shevy
Sayangnya dari petualangan saya di alam liar, saya melihat banyak dari kedua gaya tersebut. Di tim saya, kami sekarang menggunakan format dentang dengan gaya yang telah kami sepakati. Ini setidaknya berarti semua kode yang dihasilkan tim kami memiliki gaya yang sama dengan spasi kosong.
Scott Langham
33

Gunakan "Aturan Spiral Searah Jarum Jam" untuk membantu mengurai deklarasi C / C ++;

Ada tiga langkah sederhana untuk diikuti:

  1. Dimulai dengan elemen yang tidak diketahui, bergerak dalam arah spiral / searah jarum jam; ketika menemukan elemen berikut, gantilah dengan pernyataan bahasa Inggris yang sesuai:

    [X]atau []: Larik X ukuran ... atau Larik ukuran tak terdefinisi ...

    (type1, type2): fungsi yang meneruskan type1 dan type2 kembali ...

    *: penunjuk ke ...

  2. Terus lakukan ini dalam arah spiral / searah jarum jam sampai semua token tertutupi.
  3. Selalu selesaikan apa pun di dalam tanda kurung terlebih dahulu!

Juga, deklarasi harus berada dalam pernyataan terpisah jika memungkinkan (yang seringkali benar).

Michael Burr
sumber
4
Itu terlihat menakutkan dan sangat mengerikan, maaf untuk dikatakan.
Joe Phillips
7
memang demikian, tetapi tampaknya penjelasan yang cukup bagus untuk beberapa konstruksi yang lebih rumit
Michael Stum
@ d03boy: Tidak ada pertanyaan - Deklarasi C / C ++ bisa menjadi mimpi buruk.
Michael Burr
2
"Spiral" tidak masuk akal, apalagi "searah jarum jam". Saya lebih suka menamakannya "aturan kanan-kiri", karena sintaksis tidak membuat Anda melihat kanan-bawah-kiri-atas, hanya kanan-kiri.
Ruslan
Saya mempelajarinya sebagai aturan "kanan-kiri-kanan". Orang-orang C ++ sering suka berpura-pura semua informasi jenis ada di sebelah kiri, yang mengarah ke int* x;gaya daripada int *x;gaya tradisional . Tentu saja, jarak tidak menjadi masalah bagi kompiler, tetapi itu mempengaruhi manusia. Penolakan sintaks yang sebenarnya mengarah pada aturan gaya yang dapat mengganggu dan membingungkan pembaca.
Adrian McCarthy
12

Seperti yang disebutkan orang lain, 4, 5, dan 6 adalah sama. Seringkali, orang-orang menggunakan contoh-contoh ini untuk membuat argumen bahwa *variabel tersebut dimiliki oleh variabel, bukan tipe. Meskipun ini adalah masalah gaya, ada beberapa perdebatan mengenai apakah Anda harus memikirkan dan menulisnya seperti ini:

int* x; // "x is a pointer to int"

atau begini:

int *x; // "*x is an int"

FWIW Saya di kubu pertama, tapi alasan orang lain membuat argumen untuk bentuk kedua adalah karena (kebanyakan) memecahkan masalah khusus ini:

int* x,y; // "x is a pointer to int, y is an int"

yang berpotensi menyesatkan; sebaliknya Anda juga akan menulis

int *x,y; // it's a little clearer what is going on here

atau jika Anda benar-benar menginginkan dua petunjuk,

int *x, *y; // two pointers

Secara pribadi, saya katakan simpan itu ke satu variabel per baris, maka tidak masalah gaya mana yang Anda sukai.

huskerchad.dll
sumber
6
ini palsu, apa yang kamu sebut int *MyFunc(void)? a *MyFuncadalah fungsi yang mengembalikan int? tidak. Jelas kita harus menulis int* MyFunc(void), dan say MyFuncadalah fungsi yang mengembalikan a int*. Jadi bagi saya ini jelas, aturan parsing tata bahasa C dan C ++ salah untuk deklarasi variabel. mereka harus menyertakan kualifikasi penunjuk sebagai bagian dari tipe bersama untuk seluruh urutan koma.
v.oddou
1
Tapi *MyFunc() adalah sebuah int. Masalah dengan sintaks C adalah mencampurkan prefiks dan sintaks postfix - jika hanya postfix yang digunakan, tidak akan ada kebingungan.
Antti Haapala
1
Kamp pertama melawan sintaks bahasa, yang mengarah ke konstruksi membingungkan seperti int const* x;, yang menurut saya menyesatkan a * x+b * y.
Adrian McCarthy
11
#include <type_traits>

std::add_pointer<int>::type test, test2;
fredoverflow
sumber
#include <windows.h>LPINT test, test2;
Stefan Dragnev
5

Dalam 4, 5 dan 6, testselalu merupakan penunjuk dan test2bukan penunjuk. Spasi putih (hampir) tidak pernah signifikan dalam C ++.

1800 INFORMASI
sumber
3

Alasan di C adalah Anda mendeklarasikan variabel seperti yang Anda gunakan. Sebagai contoh

char *a[100];

mengatakan itu *a[42]akan menjadi char. Dan a[42]penunjuk karakter. Dan dengan demikian aadalah array pointer karakter.

Ini karena penulis kompilator asli ingin menggunakan parser yang sama untuk ekspresi dan deklarasi. (Bukan alasan yang masuk akal untuk pilihan desain bahasa)

Michel Billaud
sumber
Namun menulis char* a[100]; juga menyimpulkan bahwa *a[42];akan menjadi a chardan a[42];penunjuk karakter.
yyny
Nah, kita semua menyimpulkan kesimpulan yang sama, hanya urutannya yang bervariasi.
Michel Billaud
Kutipan: "mengatakan bahwa * a [42] akan menjadi karakter. Dan [42] karakter penunjuk". Apakah Anda yakin tidak sebaliknya?
deLock
Jika Anda lebih suka cara lain, say a[42]is a charpointer, and *a[42]is a char.
Michel Billaud
3

Menurut saya, jawabannya adalah KEDUA, tergantung situasinya. Secara umum, IMO, lebih baik meletakkan tanda bintang di sebelah nama penunjuk, daripada jenisnya. Bandingkan misalnya:

int *pointer1, *pointer2; // Fully consistent, two pointers
int* pointer1, pointer2;  // Inconsistent -- because only the first one is a pointer, the second one is an int variable
// The second case is unexpected, and thus prone to errors

Mengapa kasus kedua tidak konsisten? Karena eg int x,y;mendeklarasikan dua variabel dengan tipe yang sama tetapi tipenya hanya disebutkan sekali dalam deklarasi. Ini menciptakan preseden dan perilaku yang diharapkan. Dan int* pointer1, pointer2;tidak konsisten dengan itu karena dideklarasikan pointer1sebagai pointer, tetapi pointer2merupakan variabel integer. Jelas rentan terhadap kesalahan dan, karenanya, harus dihindari (dengan meletakkan tanda bintang di sebelah nama penunjuk, bukan jenisnya).

Namun , ada beberapa pengecualian di mana Anda mungkin tidak dapat menempatkan tanda bintang di sebelah nama objek (dan di mana Anda meletakkannya) tanpa mendapatkan hasil yang tidak diinginkan - misalnya:

MyClass *volatile MyObjName

void test (const char *const p) // const value pointed to by a const pointer

Akhirnya, dalam beberapa kasus, mungkin lebih jelas untuk menempatkan tanda bintang di sebelah nama jenis , misalnya:

void* ClassName::getItemPtr () {return &item;} // Clear at first sight

deLock
sumber
2

Saya akan mengatakan bahwa konvensi awal adalah meletakkan bintang di sisi nama penunjuk (sisi kanan deklarasi

Anda dapat mengikuti aturan yang sama, tetapi itu bukan masalah jika Anda meletakkan bintang di sisi tipe. Ingatlah bahwa konsistensi itu penting, jadi selalu tetapi bintang di sisi yang sama terlepas dari sisi mana yang Anda pilih.

TheDrev
sumber
Nah - pengurai tampaknya mengizinkan salah satu varian, tetapi jika Dennis dan Linus mengatakan itu harus di sisi kanan, itu cukup menarik. Tapi tetap saja, kami kurang memiliki beberapa alasan, dan juga penjelasan mengapa ini dilakukan. Ini agak mirip dengan situasi tab versus ruang - kecuali yang diselesaikan, karena orang yang menggunakan spasi daripada tab, menghasilkan lebih banyak uang, menurut StackOverflow ... :-)
shevy
1

Pointer adalah pengubah tipe. Yang terbaik adalah membacanya dari kanan ke kiri untuk lebih memahami bagaimana tanda bintang mengubah jenisnya. 'int *' dapat dibaca sebagai "pointer ke int '. Dalam beberapa deklarasi, Anda harus menentukan bahwa setiap variabel adalah sebuah pointer atau akan dibuat sebagai variabel standar.

1,2 dan 3) Tes bertipe (int *). Spasi putih tidak masalah.

4,5 dan 6) Tes bertipe (int *). Test2 adalah tipe int. Sekali lagi, spasi tidak penting.

Ron Warholic
sumber
1

Ada tiga bagian dari teka-teki ini.

Bagian pertama adalah bahwa spasi dalam C dan C ++ biasanya tidak signifikan selain memisahkan token yang berdekatan yang tidak dapat dibedakan.

Selama tahap preprocessing, teks sumber dipecah menjadi urutan token - pengidentifikasi, punctuator, literal numerik, literal string, dll. Urutan token tersebut kemudian dianalisis untuk sintaks dan artinya. Tokeniser bersifat "serakah" dan akan membuat token valid terpanjang yang memungkinkan. Jika Anda menulis sesuatu seperti

inttest;

tokenizer hanya melihat dua token - pengenal inttestdiikuti oleh tanda pengenal ;. Itu tidak dikenali intsebagai kata kunci terpisah pada tahap ini (yang terjadi nanti dalam proses). Jadi, agar baris dibaca sebagai deklarasi integer bernama test, kita harus menggunakan spasi untuk memisahkan token pengenal:

int test;

The *karakter bukan bagian dari identifier apapun; itu adalah token terpisah (punctuator) dengan sendirinya. Jadi jika Anda menulis

int*test;

kompilator melihat 4 token terpisah - int, *, test, dan ;. Jadi, spasi putih tidak signifikan dalam deklarasi pointer, dan semua

int *test;
int* test;
int*test;
int     *     test;

ditafsirkan dengan cara yang sama.


Bagian kedua dari teka-teki adalah bagaimana deklarasi sebenarnya bekerja di C dan C ++ 1 . Deklarasi dipecah menjadi dua bagian utama - urutan penentu deklarasi (penentu kelas penyimpanan, penentu jenis, penentu jenis, dll.) Diikuti dengan daftar deklarator (mungkin diinisialisasi) yang dipisahkan koma . Dalam deklarasi

unsigned long int a[10]={0}, *p=NULL, f(void);

specifiers deklarasi yang unsigned long intdan declarators yang a[10]={0}, *p=NULL, dan f(void). Deklarator memperkenalkan nama hal yang dideklarasikan ( a,, pdan f) bersama dengan informasi tentang array-ness, pointer-ness, dan function-ness. Deklarator mungkin juga memiliki penginisialisasi terkait.

Jenisnya aadalah "larik 10 elemen unsigned long int". Jenis tersebut sepenuhnya ditentukan oleh kombinasi penentu deklarasi dan deklarator, dan nilai awal ditentukan dengan penginisialisasi ={0}. Demikian pula, tipe padalah "pointer to unsigned long int", dan sekali lagi tipe itu ditentukan oleh kombinasi penentu deklarasi dan deklarator, dan diinisialisasi ke NULL. Dan jenisnya fadalah "fungsi yang kembali unsigned long int" dengan alasan yang sama.

Ini adalah kunci - tidak ada penentu tipe "penunjuk-ke" , sama seperti tidak ada penentu jenis "larik-dari", sama seperti tidak ada penentu jenis yang "mengembalikan fungsi". Kami tidak dapat mendeklarasikan sebuah array sebagai

int[10] a;

karena operan []operatornya a, bukan int. Begitu pula di deklarasi

int* p;

operannya *adalah p, bukan int. Tetapi karena operator indirection adalah unary dan whitespace tidak signifikan, compiler tidak akan mengeluh jika kita menuliskannya dengan cara ini. Namun, itu selalu diartikan sebagai int (*p);.

Karena itu, jika Anda menulis

int* p, q;

operan dari *adalah p, jadi itu akan diartikan sebagai

int (*p), q;

Jadi, semuanya

int *test1, test2;
int* test1, test2;
int * test1, test2;

melakukan hal yang sama - dalam ketiga kasus, test1adalah operan *dan karenanya memiliki tipe "pointer to int", sementara test2memiliki tipe int.

Deklarator bisa menjadi rumit secara sewenang-wenang. Anda dapat memiliki array pointer:

T *a[N];

Anda dapat memiliki pointer ke array:

T (*a)[N];

Anda dapat memiliki fungsi yang mengembalikan pointer:

T *f(void);

Anda dapat memiliki petunjuk ke fungsi:

T (*f)(void);

Anda dapat memiliki array pointer ke fungsi:

T (*a[N])(void);

Anda dapat memiliki fungsi yang mengembalikan pointer ke array:

T (*f(void))[N];

Anda dapat memiliki fungsi yang mengembalikan pointer ke array pointer ke fungsi yang mengembalikan pointer ke T:

T *(*(*f(void))[N])(void); // yes, it's eye-stabby.  Welcome to C and C++.

dan kemudian Anda memiliki signal:

void (*signal(int, void (*)(int)))(int);

yang berbunyi

       signal                             -- signal
       signal(                 )          -- is a function taking
       signal(                 )          --   unnamed parameter
       signal(int              )          --   is an int
       signal(int,             )          --   unnamed parameter
       signal(int,      (*)    )          --   is a pointer to
       signal(int,      (*)(  ))          --     a function taking
       signal(int,      (*)(  ))          --       unnamed parameter
       signal(int,      (*)(int))         --       is an int
       signal(int, void (*)(int))         --     returning void
     (*signal(int, void (*)(int)))        -- returning a pointer to
     (*signal(int, void (*)(int)))(   )   --   a function taking
     (*signal(int, void (*)(int)))(   )   --     unnamed parameter
     (*signal(int, void (*)(int)))(int)   --     is an int
void (*signal(int, void (*)(int)))(int);  --   returning void
    

dan ini hanya menggores permukaan dari apa yang mungkin. Tetapi perhatikan bahwa array-ness, pointer-ness, dan function-ness selalu menjadi bagian dari deklarator, bukan penentu tipe.

Satu hal yang harus diperhatikan - constdapat memodifikasi tipe pointer dan tipe menunjuk-ke:

const int *p;  
int const *p;

Kedua hal di atas mendeklarasikan psebagai pointer ke sebuah const intobjek. Anda dapat menulis nilai baru untuk pmenyetelnya agar mengarah ke objek yang berbeda:

const int x = 1;
const int y = 2;

const int *p = &x;
p = &y;

tetapi Anda tidak dapat menulis ke objek yang diarahkan ke:

*p = 3; // constraint violation, the pointed-to object is const

Namun,

int * const p;

mendeklarasikan psebagai constpointer ke non-const int; Anda dapat menulis ke hal yang pditunjukkan

int x = 1;
int y = 2;
int * const p = &x;

*p = 3;

tetapi Anda tidak dapat menetapkan puntuk menunjuk ke objek lain:

p = &y; // constraint violation, p is const

Yang membawa kita ke bagian ketiga dari teka-teki - mengapa deklarasi disusun seperti ini.

Maksudnya adalah bahwa struktur deklarasi harus mencerminkan struktur ekspresi dalam kode ("deklarasi meniru penggunaan"). Sebagai contoh, misalkan kita memiliki array pointer untuk intdinamai ap, dan kita ingin mengakses intnilai yang ditunjukkan oleh ielemen 'th. Kami akan mengakses nilai itu sebagai berikut:

printf( "%d", *ap[i] );

The ekspresi *ap[i] memiliki tipe int; dengan demikian, pernyataan aptertulis sebagai

int *ap[N]; // ap is an array of pointer to int, fully specified by the combination
            // of the type specifier and declarator

Deklarator *ap[N]memiliki struktur yang sama dengan ekspresi *ap[i]. Operator *dan []berperilaku dengan cara yang sama dalam deklarasi yang mereka lakukan dalam ekspresi - []memiliki prioritas yang lebih tinggi daripada unary *, jadi operand of *adalah ap[N](diurai sebagai *(ap[N])).

Sebagai contoh lain, misalkan kita memiliki pointer ke array intbernama padan kita ingin mengakses nilai ielemen 'th. Kami akan menulisnya sebagai

printf( "%d", (*pa)[i] );

Jenis ekspresi (*pa)[i]adalah int, sehingga deklarasi ditulis sebagai

int (*pa)[N];

Sekali lagi, aturan prioritas dan asosiatif yang sama berlaku. Dalam hal ini, kami tidak ingin mendereferensi ielemen 'th pa, kami ingin mengakses ielemen' th pa poin apa , jadi kami harus secara eksplisit mengelompokkan *operator dengan pa.

Operator *, []dan ()semuanya adalah bagian dari ekspresi dalam kode, jadi semuanya adalah bagian dari deklarator dalam deklarasi. Deklarator memberi tahu Anda cara menggunakan objek dalam ekspresi. Jika Anda memiliki deklarasi seperti int *p;, itu memberi tahu Anda bahwa ekspresi *pdalam kode Anda akan menghasilkan intnilai. Dengan ekstensi, ini memberitahu Anda bahwa ekspresi pmenghasilkan nilai tipe "pointer ke int", atau int *.


Jadi, bagaimana dengan pemeran dan sizeofekspresi, di mana kita menggunakan hal-hal seperti (int *)atau sizeof (int [10])atau seperti itu? Bagaimana cara membaca sesuatu seperti

void foo( int *, int (*)[10] );

Tidak ada deklarator, bukankah operator *and []memodifikasi tipe secara langsung?

Ya, tidak - masih ada deklarator, hanya dengan pengenal kosong (dikenal sebagai deklarator abstrak ). Jika kami mewakili sebuah identifier kosong dengan λ simbol, maka kita dapat membaca hal-hal sebagai (int *λ), sizeof (int λ[10]), dan

void foo( int *λ, int (*λ)[10] );

dan mereka berperilaku persis seperti deklarasi lainnya. int *[10]mewakili larik yang terdiri dari 10 penunjuk, sedangkan int (*)[10]mewakili penunjuk ke larik.


Dan sekarang bagian opini dari jawaban ini. Saya tidak menyukai konvensi C ++ yang menyatakan pointer sederhana sebagai

T* p;

dan menganggapnya sebagai praktik yang buruk karena alasan berikut:

  1. Ini tidak konsisten dengan sintaks;
  2. Ini menimbulkan kebingungan (seperti yang dibuktikan oleh pertanyaan ini, semua duplikat dari pertanyaan ini, pertanyaan tentang arti T* p, q;, semua duplikat dari pertanyaan - pertanyaan itu, dll.);
  3. Ini tidak konsisten secara internal - mendeklarasikan array pointer sebagai T* a[N]asimetris dengan penggunaan (kecuali jika Anda terbiasa menulis * a[i]);
  4. Ini tidak bisa diterapkan ke tipe pointer-to-array atau pointer-to-function (kecuali Anda membuat typedef supaya Anda bisa menerapkan T* pkonvensi dengan rapi, yang ... tidak );
  5. Alasan untuk melakukannya - "ini menekankan penunjuk-an objek" - adalah palsu. Itu tidak dapat diterapkan ke tipe array atau fungsi, dan saya akan berpikir kualitas itu sama pentingnya untuk ditekankan.

Pada akhirnya, ini hanya menunjukkan pemikiran yang bingung tentang bagaimana sistem tipe kedua bahasa bekerja.

Ada alasan bagus untuk menyatakan item secara terpisah; mengatasi praktik yang buruk ( T* p, q;) bukanlah salah satunya. Jika Anda menulis deklarator dengan benar ( T *p, q;), kemungkinan kecil Anda akan menimbulkan kebingungan.

Saya menganggapnya mirip dengan sengaja menulis semua forloop sederhana Anda sebagai

i = 0;
for( ; i < N; ) 
{ 
  ... 
  i++ 
}

Valid secara sintaksis, tetapi membingungkan, dan maksudnya cenderung disalahartikan. Namun, T* p;konvensi tersebut mengakar dalam komunitas C ++, dan saya menggunakannya dalam kode C ++ saya sendiri karena konsistensi di seluruh basis kode adalah hal yang baik, tetapi itu membuat saya gatal setiap kali melakukannya.


  1. Saya akan menggunakan terminologi C - terminologi C ++ sedikit berbeda, tetapi konsepnya sebagian besar sama.
John Bode
sumber
-3

Sebuah aturan praktis yang baik, banyak orang tampaknya memahami konsep ini dengan: Dalam C ++ banyak makna semantik diturunkan oleh pengikatan kiri kata kunci atau pengenal.

Ambil contoh:

int const bla;

Const berlaku untuk kata "int". Hal yang sama berlaku untuk tanda bintang penunjuk, tanda tersebut berlaku untuk kata kunci di sebelah kiri. Dan nama variabel sebenarnya? Yup, itu dinyatakan dengan apa yang tersisa darinya.

mstrobl.dll
sumber
1
Ini tidak menjawab pertanyaan itu. Lebih buruk lagi, jika kita mencoba menyimpulkan jawaban darinya, maka itu menyiratkan bahwa tanda bintang mengikat jenis di sebelah kirinya, yang seperti yang dikatakan orang lain, salah. Ini mengikat nama variabel tunggal di sebelah kanannya.
underscore_d