Apa yang orang temukan kesulitan dengan pointer C? [Tutup]

173

Dari sejumlah pertanyaan yang diposting di sini, jelas bahwa orang-orang memiliki beberapa masalah mendasar ketika mengarahkan kepala mereka ke pointer dan aritmatika pointer.

Saya ingin tahu mengapa. Mereka tidak pernah benar-benar menyebabkan saya masalah besar (meskipun saya pertama kali mengetahui tentang mereka di Neolitik). Untuk menulis jawaban yang lebih baik atas pertanyaan-pertanyaan ini, saya ingin tahu apa yang sulit dilakukan orang.

Jadi, jika Anda berjuang dengan pointer, atau Anda baru-baru ini tiba-tiba "mengerti", apa aspek pointer yang menyebabkan Anda bermasalah?

Paul
sumber
54
Snarky, dibesar-besarkan, tidak perlu kontroversial, menjawab dengan butir kebenaran: Mereka telah lumpuh --- cacat mental, saya katakan 'ya --- oleh l'arning salah satu dari mereka "ekspresif" bahasa tingkat tinggi terlebih dahulu. Mereka seharusnya memulai dengan pemrograman pada bare metal seperti yang dimaksudkan Daniel Boone!
dmckee --- ex-moderator kitten
3
... dan Programmer akan lebih baik karena itu akan berkembang menjadi diskusi meskipun Anda sudah berusaha keras.
dmckee --- ex-moderator kitten
Ini argumentatif dan subyektif, ini menghasilkan hasil N, kesulitan saya adalah mudah Anda. Mungkin akan bekerja pada programmer, tetapi kami belum memigrasikan pertanyaan-pertanyaan ini di sana karena situs tersebut tidak keluar dari beta.
Sam Saffron
2
@ Sam Saffron: Walaupun saya umumnya setuju bahwa ini lebih merupakan pertanyaan tipe programmer. SE, jujur ​​tidak akan buruk jika orang mau menandai "Saya pikir itu mudah" dan "Saya benci melihat petunjuk" sebagai spam mereka.
jkerian
3
Seseorang harus mengangkat ini: "Ini seperti jari yang menunjuk ke bulan. Jangan berkonsentrasi pada jari atau kamu akan kehilangan semua kemuliaan surgawi itu" - Bruce Lee
mu terlalu pendek

Jawaban:

86

Saya menduga orang-orang akan terlalu dalam dalam jawaban mereka. Pemahaman tentang penjadwalan, operasi CPU yang sebenarnya, atau manajemen memori tingkat perakitan tidak benar-benar diperlukan.

Ketika saya mengajar, saya menemukan lubang-lubang berikut dalam pemahaman siswa sebagai sumber masalah yang paling umum:

  1. Penyimpanan tumpukan vs tumpukan. Sungguh menakjubkan betapa banyak orang tidak memahami ini, bahkan dalam arti umum.
  2. Bingkai tumpukan. Hanya konsep umum bagian khusus tumpukan untuk variabel lokal, beserta alasannya adalah 'tumpukan' ... perincian seperti menyembunyikan lokasi pengembalian, perincian penangan pengecualian, dan register sebelumnya dapat dengan aman dibiarkan sampai seseorang mencoba untuk membangun kompiler.
  3. "Memory is memory is memory" Casting hanya mengubah versi operator mana atau berapa banyak ruang yang diberikan kompiler untuk sebagian memori. Anda tahu Anda sedang berhadapan dengan masalah ini ketika orang berbicara tentang "apa (primitif) variabel X sebenarnya ".

Sebagian besar siswa saya dapat memahami gambar disederhanakan dari sepotong memori, umumnya bagian variabel lokal dari tumpukan pada lingkup saat ini. Umumnya memberikan alamat fiksi eksplisit ke berbagai lokasi membantu.

Saya kira dalam ringkasan, saya katakan bahwa jika Anda ingin memahami pointer, Anda harus memahami variabel, dan apa sebenarnya mereka dalam arsitektur modern.

jerman
sumber
13
IMHO, memahami stack dan heap sama tidak perlu dengan detail CPU tingkat rendah. Stack and heap adalah detail implementasi. ISO C spec tidak memiliki satu penyebutan kata "stack" dan begitu juga K&R.
sigjuice
4
@ Sigjuice: Keberatan Anda melewatkan inti pertanyaan dan jawaban. A) K&R C adalah anakronisme B) ISO C bukan satu-satunya bahasa dengan pointer, poin saya 1 dan 2 dikembangkan terhadap bahasa non-C berbasis C) 95% dari arsitektur (bukan bahasa) di luar sana menggunakan heap / sistem stack, itu cukup umum bahwa pengecualian dijelaskan relatif terhadapnya. D) Inti pertanyaannya adalah "mengapa orang tidak mengerti petunjuk", bukan "bagaimana saya menjelaskan ISO C"
jkerian
9
@ John Marchetti: Terlebih lagi ... mengingat bahwa pertanyaannya adalah "Apa masalah utama dengan masalah orang dengan pointer", saya tidak berpikir orang-orang yang menanyakan pertanyaan terkait pointer akan sangat terkesan dengan "You don ' Saya tidak perlu tahu "sebagai jawaban. Jelas mereka tidak setuju. :)
jkerian
3
@ jkerian Mungkin kedaluwarsa, tetapi tiga atau empat halaman K&R yang menjelaskan pointer melakukannya tanpa perlu rincian implementasi. Pengetahuan tentang detail implementasi berguna untuk berbagai alasan, tetapi IMHO, seharusnya tidak menjadi prasyarat untuk memahami konstruksi utama suatu bahasa.
sigjuice
3
"Umumnya memberikan alamat fiksi eksplisit ke berbagai lokasi membantu." -> +1
fredoverflow
146

Ketika saya pertama kali mulai bekerja dengan mereka, masalah terbesar yang saya miliki adalah sintaksisnya.

int* ip;
int * ip;
int *ip;

semuanya sama.

tapi:

int* ip1, ip2;  //second one isn't a pointer!
int *ip1, *ip2;

Mengapa? karena "penunjuk" bagian dari deklarasi milik variabel, dan bukan tipe.

Dan kemudian dereferensi benda menggunakan notasi yang sangat mirip:

*ip = 4;  //sets the value of the thing pointed to by ip to '4'
x = ip;   //hey, that's not '4'!
x = *ip;  //ahh... there's that '4'

Kecuali ketika Anda benar-benar perlu mendapatkan pointer ... maka Anda menggunakan ampersand!

int *ip = &x;

Hore untuk konsistensi!

Kemudian, tampaknya hanya untuk menjadi tersentak dan membuktikan betapa pintarnya mereka, banyak pengembang perpustakaan menggunakan pointer-ke-pointer-ke-pointer, dan jika mereka mengharapkan array dari hal-hal itu, baik mengapa tidak hanya meneruskan pointer ke hal itu juga .

void foo(****ipppArr);

untuk memanggil ini, saya perlu alamat array pointer ke pointer ke pointer ints:

foo(&(***ipppArr));

Dalam enam bulan, ketika saya harus mempertahankan kode ini, saya akan menghabiskan lebih banyak waktu untuk mencari tahu apa artinya semua ini daripada menulis ulang dari bawah ke atas. (Ya, mungkin salah sintaks - sudah lama sejak saya melakukan sesuatu di C. Saya agak merindukannya, tapi kemudian saya sedikit massochist)

Jeff Knecht
sumber
21
Komentar Anda untuk yang pertama, >> * ip = 4; // setel nilai ip ke '4' << salah. Seharusnya >> // menetapkan nilai dari hal yang ditunjukkan oleh ip ke '4'
aaaa bbbb
8
Menumpuk terlalu banyak jenis di atas satu sama lain adalah ide yang buruk, dalam bahasa apa pun. Anda mungkin menemukan tulisan "foo (& (*** ipppArr));" aneh di C, tetapi menulis sesuatu seperti "std :: map <std :: pair <int, int>, std :: pair <std :: vector <int>, std :: tuple <int, double, std :: list <int> >>> "di C ++ juga sangat kompleks. Ini tidak berarti bahwa pointer dalam wadah C atau STL dalam C ++ kompleks. Ini hanya berarti bahwa Anda harus menggunakan definisi tipe yang lebih baik agar dapat dimengerti oleh pembaca kode Anda.
Patrick
20
Saya sungguh-sungguh tidak percaya salah paham tentang sintaksis adalah jawaban yang paling banyak dipilih. Itu bagian termudah tentang pointer.
jason
4
Bahkan membaca jawaban ini, saya tergoda untuk mengambil selembar kertas dan menggambar. Di C, saya selalu menggambar.
Michael Easter
19
@Jason Ukuran objektif kesulitan apa yang ada selain apa yang sulit dilakukan oleh mayoritas orang?
Rupert Madden-Abbott
52

Pemahaman yang tepat tentang pointer membutuhkan pengetahuan tentang arsitektur mesin yang mendasarinya.

Banyak programmer saat ini tidak tahu cara kerja mesin mereka, seperti kebanyakan orang yang tahu cara mengendarai mobil tidak tahu apa-apa tentang mesin.

Robert Harvey
sumber
18
@ dmckee: Ya, apakah saya salah? Berapa banyak programmer Java yang bisa menangani segfault?
Robert Harvey
5
Apakah segfault ada hubungannya dengan tongkat persneling? - Programmer Java
Tom Anderson
6
@ Robert: itu dimaksudkan sebagai pelengkap asli. Ini adalah topik yang sulit untuk didiskusikan tanpa menyakiti perasaan orang. Dan saya khawatir komentar saya memicu konflik yang saya pikir akan Anda hindari. Mea cupla.
dmckee --- ex-moderator kitten
30
Saya tidak setuju; Anda tidak perlu memahami arsitektur yang mendasari untuk mendapatkan pointer (mereka adalah abstraksi, toh).
jason
11
@Jason: Di C, pointer pada dasarnya adalah alamat memori. Bekerja dengan mereka dengan aman adalah hal yang mustahil tanpa memahami arsitektur mesin. Lihat en.wikipedia.org/wiki/Pointer_(computing) dan boredzo.org/pointers/#definition
Robert Harvey
42

Ketika berhadapan dengan pointer, orang-orang yang bingung banyak berada di salah satu dari dua kubu. Saya pernah (keduanya?) Di keduanya.

The array[]kerumunan

Ini adalah kerumunan yang lurus ke atas tidak tahu bagaimana menerjemahkan dari notasi pointer ke notasi array (atau bahkan tidak tahu bahwa mereka bahkan terkait). Berikut adalah empat cara untuk mengakses elemen dari array:

  1. notasi array (pengindeksan) dengan nama array
  2. notasi array (pengindeksan) dengan nama pointer
  3. notasi pointer (the *) dengan nama pointer
  4. notasi pointer (the *) dengan nama array

 

int vals[5] = {10, 20, 30, 40, 50};
int *ptr;
ptr = vals;

array       element            pointer
notation    number     vals    notation

vals[0]     0          10      *(ptr + 0)
ptr[0]                         *(vals + 0)

vals[1]     1          20      *(ptr + 1)
ptr[1]                         *(vals + 1)

vals[2]     2          30      *(ptr + 2)
ptr[2]                         *(vals + 2)

vals[3]     3          40      *(ptr + 3)
ptr[3]                         *(vals + 3)

vals[4]     4          50      *(ptr + 4)
ptr[4]                         *(vals + 4)

Idenya di sini adalah bahwa mengakses array melalui pointer tampaknya cukup sederhana dan mudah, tetapi satu ton hal yang sangat rumit dan pintar dapat dilakukan dengan cara ini. Beberapa di antaranya dapat membuat programmer C / C ++ yang berpengalaman bingung, apalagi pemula yang belum berpengalaman.

The reference to a pointerdan pointer to a pointerkerumunan

Ini adalah artikel bagus yang menjelaskan perbedaannya dan saya akan mengutip dan mencuri beberapa kode dari :)

Sebagai contoh kecil, bisa sangat sulit untuk melihat dengan tepat apa yang ingin dilakukan penulis jika Anda menemukan sesuatu seperti ini:

//function prototype
void func(int*& rpInt); // I mean, seriously, int*& ??

int main()
{
  int nvar=2;
  int* pvar=&nvar;
  func(pvar);
  ....
  return 0;
}

Atau, pada tingkat lebih rendah, sesuatu seperti ini:

//function prototype
void func(int** ppInt);

int main()
{
  int nvar=2;
  int* pvar=&nvar;
  func(&pvar);
  ....
  return 0;
}

Jadi pada akhirnya, apa yang benar-benar kita pecahkan dengan semua omong kosong ini? Tidak ada.

Sekarang kita telah melihat sintaks ptr-to-ptr dan ref-to-ptr. Apakah ada kelebihan satu di atas yang lain? Saya takut, tidak. Penggunaan salah satu dari keduanya, bagi sebagian programmer hanyalah preferensi pribadi. Beberapa yang menggunakan ref-to-ptr mengatakan sintaksnya "bersih" sementara beberapa yang menggunakan ptr-to-ptr, mengatakan sintaks ptr-to-ptr membuatnya lebih jelas bagi mereka yang membaca apa yang Anda lakukan.

Kompleksitas ini dan pertukaran yang tampak (yang nampak tebal) dengan referensi, yang seringkali merupakan peringatan lain dari pointer dan kesalahan pendatang baru, membuat pointer sulit dipahami. Penting juga untuk memahami, demi penyelesaian, bahwa petunjuk referensi adalah ilegal dalam C dan C ++ karena alasan membingungkan yang membawa Anda ke lvalue- rvaluesemantik.

Seperti jawaban sebelumnya berkomentar, berkali-kali Anda hanya akan memiliki programmer jagoan ini yang berpikir mereka pintar dengan menggunakan ******awesome_var->lol_im_so_clever()dan kebanyakan dari kita mungkin bersalah menulis kekejaman seperti itu di kali, tetapi itu bukan kode yang baik, dan tentu saja tidak dapat dipertahankan .

Yah jawaban ini ternyata lebih lama dari yang saya harapkan ...

David Titarenco
sumber
5
Saya pikir Anda mungkin telah memberikan jawaban C ++ untuk pertanyaan C di sini ... setidaknya bagian kedua.
detly
Pointer ke pointer berlaku untuk C, juga: p
David Titarenco
1
Heh? Saya hanya melihat pointer ke pointer ketika melewati array - contoh kedua Anda tidak benar-benar berlaku untuk kode C paling layak. Juga, Anda menyeret C ke kekacauan C ++ - referensi di C tidak ada.
new123456
Anda harus berurusan dengan pointer ke pointer dalam banyak kasus yang sah. Misalnya, ketika berhadapan dengan pointer fungsi yang menunjuk ke fungsi yang mengembalikan pointer. Contoh lain: sebuah struct yang dapat menampung sejumlah variabel dari struct lainnya. Dan masih banyak lagi ...
David Titarenco
2
"pointer ke referensi ilegal di C" - lebih seperti "absen" :)
Kos
29

Saya menyalahkan kualitas bahan referensi dan orang-orang yang melakukan pengajaran, secara pribadi; sebagian besar konsep dalam C (tetapi terutama pointer) hanya diajarkan secara buruk. Saya terus mengancam untuk menulis buku C saya sendiri (berjudul Hal Terakhir yang Dunia Butuhkan Adalah Buku Lain Tentang Bahasa Pemrograman C ), tetapi saya tidak punya waktu atau kesabaran untuk melakukannya. Jadi saya nongkrong di sini dan melemparkan kutipan acak dari Standar pada orang.

Ada juga fakta bahwa ketika C awalnya dirancang, diasumsikan Anda memahami arsitektur mesin ke tingkat yang cukup rinci hanya karena tidak ada cara untuk menghindarinya dalam pekerjaan Anda sehari-hari (memori sangat ketat dan prosesor sangat lambat Anda harus memahami bagaimana apa yang Anda tulis memengaruhi kinerja).

John Bode
sumber
3
Iya. 'int foo = 5; int * pfoo = & foo; Lihat betapa bermanfaatnya itu? OK, terus maju ... 'Saya tidak benar-benar menggunakan pointer sampai saya menulis daftar pustaka tautan ganda saya.
John Lopez
2
+1. Saya gunakan untuk mengajari siswa CS100 dan banyak masalah mereka diselesaikan hanya dengan membaca petunjuk dengan cara yang dimengerti.
benzado
1
+1 untuk konteks historis. Sudah dimulai lama setelah waktu itu, ini tidak pernah terjadi pada saya.
Lumi
26

Ada artikel bagus yang mendukung gagasan bahwa pointer sulit di situs Joel Spolsky - The Perils of JavaSchools .

[Penafian - Saya bukan pembenci Java per se .]

Steve Townsend
sumber
2
@Jason - itu benar tetapi tidak meniadakan argumen.
Steve Townsend
4
Spolsky tidak mengatakan bahwa JavaSchools adalah alasan orang menemukan petunjuk sulit. Dia mengatakan mereka menghasilkan orang buta huruf dengan gelar Ilmu Komputer.
benzado
1
@ Albenzado - titik adil - posting singkat saya akan ditingkatkan jika membaca 'artikel bagus yang mendukung gagasan bahwa pointer sulit'. Apa yang disiratkan oleh artikel itu adalah bahwa "memiliki gelar CS dari 'sekolah yang baik'" bukanlah prediktor keberhasilan yang sama baiknya dengan pengembang seperti dulu, sementara "memahami petunjuk" (dan rekursi) masih tetap.
Steve Townsend
1
@Steve Townsend: Saya pikir Anda kehilangan inti argumen Mr. Spolsky.
jason
2
@Steve Townsend: Mr. Spolsky berargumen bahwa sekolah-sekolah di Jawa meningkatkan generasi programmer yang tidak tahu pointer dan rekursi, bukan karena pointer sulit karena prevalensi sekolah-sekolah Jawa. Ketika Anda menyatakan "ada artikel bagus tentang mengapa ini sulit" dan terkait dengan artikel tersebut, tampaknya Anda memiliki interpretasi yang terakhir. Maafkan saya jika saya salah.
jason
24

Kebanyakan hal lebih sulit untuk dipahami jika Anda tidak didasarkan pada pengetahuan yang "di bawah". Ketika saya mengajar CS, ini menjadi jauh lebih mudah ketika saya memulai siswa saya pada pemrograman "mesin" yang sangat sederhana, komputer desimal simulasi dengan opcode desimal yang ingatannya terdiri dari register desimal dan alamat desimal. Mereka akan memasukkan program yang sangat singkat ke, misalnya, menambahkan serangkaian angka untuk mendapatkan total. Kemudian mereka akan melangkah untuk menyaksikan apa yang terjadi. Mereka bisa menahan tombol "enter" dan melihatnya berlari "cepat".

Saya yakin hampir semua orang di SO bertanya-tanya mengapa hal ini berguna untuk menjadi sangat mendasar. Kami lupa bagaimana rasanya tidak tahu cara memprogram. Bermain dengan komputer mainan seperti itu menempatkan konsep-konsep yang tanpanya Anda tidak dapat memprogram, seperti gagasan bahwa perhitungan adalah proses langkah-demi-langkah, menggunakan sejumlah kecil primitif dasar untuk membangun program, dan konsep memori variabel sebagai tempat menyimpan nomor, di mana alamat atau nama variabel berbeda dari nomor yang dikandungnya. Ada perbedaan antara waktu di mana Anda memasuki program, dan waktu di mana ia "berjalan". Saya menyamakan belajar program dengan melewati serangkaian "gundukan kecepatan", seperti program yang sangat sederhana, lalu loop dan subrutin, kemudian array, lalu I / O berurutan, lalu pointer dan struktur data.

Akhirnya, ketika sampai di C, pointer membingungkan meskipun K&R melakukan pekerjaan yang sangat baik untuk menjelaskannya. Cara saya mempelajarinya dalam C adalah untuk mengetahui cara membacanya - kanan ke kiri. Seperti ketika saya melihat int *pdi kepala saya, saya mengatakan " pmenunjuk ke sebuah int". C diciptakan sebagai salah satu langkah maju dari bahasa assembly dan itulah yang saya sukai - dekat dengan "tanah" itu. Pointer, seperti hal lainnya, lebih sulit untuk dipahami jika Anda tidak memiliki landasan itu.

Mike Dunlavey
sumber
1
Cara yang baik untuk mempelajari ini adalah memprogram mikrokontroler 8-bit. Mereka mudah dimengerti. Ambil pengontrol Atmel AVR; mereka bahkan didukung oleh gcc.
Xenu
@Xenu: Saya setuju. Bagi saya itu adalah Intel 8008 dan 8051 :-)
Mike Dunlavey
Bagi saya itu adalah komputer 8-bit kustom ("Mungkin") di MIT dalam kabut waktu yang redup.
QuantumMechanic
Mike - Anda harus mendapatkan siswa Anda CARDIAC :)
QuantumMechanic
1
@ Quantum: CARDIAC- bagus, belum pernah mendengarnya. "Mungkin" - coba saya tebak, adalah ketika Sussman (dkk) meminta orang membaca buku Mead-Conway dan membuat chip LSI mereka sendiri? Itu sedikit setelah waktu saya di sana.
Mike Dunlavey
17

Saya tidak mendapatkan petunjuk sampai saya membaca deskripsi di K&R. Sampai saat itu, petunjuk tidak masuk akal. Saya membaca banyak hal di mana orang mengatakan "Jangan belajar pointer, mereka membingungkan dan akan melukai kepala Anda dan memberi Anda aneurisma" jadi saya menghindarinya untuk waktu yang lama, dan menciptakan suasana konsep sulit yang tidak perlu ini. .

Kalau tidak, sebagian besar apa yang saya pikirkan adalah, mengapa Anda ingin variabel yang harus Anda lewati untuk mendapatkan nilai, dan jika Anda ingin menetapkan barang untuk itu, Anda harus melakukan hal-hal aneh untuk mendapatkan nilai untuk pergi. ke mereka. Inti dari sebuah variabel adalah sesuatu untuk menyimpan nilai, pikir saya, jadi mengapa seseorang ingin membuatnya rumit berada di luar jangkauan saya. "Jadi dengan pointer kamu harus menggunakan *operator untuk mendapatkan nilainya ??? Variabel konyol macam apa itu?" , Saya pikir. Tidak ada gunanya, tidak ada pelesetan yang dimaksudkan.

Alasannya rumit adalah karena saya tidak mengerti bahwa pointer adalah alamat untuk sesuatu. Jika Anda menjelaskan bahwa itu adalah alamat, bahwa itu adalah sesuatu yang berisi alamat untuk sesuatu yang lain, dan bahwa Anda dapat memanipulasi alamat itu untuk melakukan hal-hal yang berguna, saya pikir itu dapat menghilangkan kebingungan.

Kelas yang diperlukan menggunakan pointer untuk mengakses / memodifikasi port pada PC, menggunakan pointer aritmatika untuk mengatasi lokasi memori yang berbeda, dan melihat kode-C yang lebih rumit yang mengubah argumen mereka membuat saya terhindar dari gagasan bahwa pointer itu, yah, tidak ada gunanya.

J. Polfer
sumber
4
Jika Anda memiliki sumber daya terbatas untuk bekerja dengan (RAM, ROM, CPU), seperti dalam aplikasi embedded, pointer dengan cepat jauh lebih masuk akal.
Nick T
+1 untuk komentar Nick - terutama untuk melewati struct.
new123456
12

Berikut adalah contoh pointer / array yang memberi saya jeda. Asumsikan Anda memiliki dua array:

uint8_t source[16] = { /* some initialization values here */ };
uint8_t destination[16];

Dan tujuan Anda adalah menyalin konten uint8_t dari tujuan sumber menggunakan memcpy (). Coba tebak yang mana dari yang berikut mencapai tujuan itu:

memcpy(destination, source, sizeof(source));
memcpy(&destination, source, sizeof(source));
memcpy(&destination[0], source, sizeof(source));
memcpy(destination, &source, sizeof(source));
memcpy(&destination, &source, sizeof(source));
memcpy(&destination[0], &source, sizeof(source));
memcpy(destination, &source[0], sizeof(source));
memcpy(&destination, &source[0], sizeof(source));
memcpy(&destination[0], &source[0], sizeof(source));

Jawabannya (Spoiler Alert!) Adalah SEMUA dari mereka. "tujuan", "& tujuan", dan "& tujuan [0]" semuanya bernilai sama. "& tujuan" adalah tipe yang berbeda dari dua lainnya, tetapi nilainya masih sama. Hal yang sama berlaku untuk permutasi "sumber".

Selain itu, saya pribadi lebih suka versi pertama.

Andrew Cottrell
sumber
Saya lebih suka versi pertama juga (kurang tanda baca).
sigjuice
++ Begitu juga saya, tetapi Anda benar-benar harus berhati-hati sizeof(source), karena jika sourcesebuah pointer, sizeofitu tidak akan seperti yang Anda inginkan. Saya terkadang (tidak selalu) menulis sizeof(source[0]) * number_of_elements_of_sourcehanya untuk menjauh dari bug itu.
Mike Dunlavey
tujuan, & tujuan, & tujuan [0] sama sekali tidak sama - tetapi masing-masing melalui mekanisme yang berbeda akan dikonversi ke kekosongan yang sama * ketika digunakan dalam memcpy. Namun, ketika digunakan sebagai argumen sizeof, Anda akan mendapatkan dua hasil yang berbeda, dan tiga hasil yang berbeda dimungkinkan.
gnasher729
Saya pikir alamat operator diperlukan?
MarcusJ
7

Saya harus memulai dengan mengatakan bahwa C dan C ++ adalah bahasa pemrograman pertama yang saya pelajari. Saya mulai dengan C, kemudian melakukan C ++ di sekolah, banyak, dan kemudian kembali ke C untuk menjadi fasih di dalamnya.

Hal pertama yang membingungkan saya tentang petunjuk ketika belajar C adalah sederhana:

char ch;
char str[100];
scanf("%c %s", &ch, str);

Kebingungan ini sebagian besar berakar pada telah diperkenalkan untuk menggunakan referensi ke variabel untuk argumen OUT sebelum pointer diperkenalkan kepada saya. Saya ingat bahwa saya melewatkan menulis beberapa contoh pertama dalam C untuk Dummies karena mereka terlalu sederhana hanya untuk tidak pernah mendapatkan program pertama yang saya tulis untuk bekerja (kemungkinan besar karena ini).

Apa yang membingungkan tentang ini adalah apa yang &chsebenarnya dimaksudkan dan mengapa strtidak membutuhkannya.

Setelah saya menjadi terbiasa dengan itu saya selanjutnya ingat menjadi bingung tentang alokasi dinamis. Saya menyadari pada suatu titik bahwa memiliki pointer ke data tidak terlalu berguna tanpa alokasi dinamis dari beberapa jenis, jadi saya menulis sesuatu seperti:

char * x = NULL;
if (y) {
     char z[100];
     x = z;
}

untuk mencoba mengalokasikan ruang secara dinamis. Itu tidak berhasil. Saya tidak yakin itu akan berhasil, tetapi saya tidak tahu bagaimana lagi cara kerjanya.

Saya kemudian belajar tentang mallocdan new, tetapi mereka benar-benar tampak seperti generator memori ajaib bagi saya. Saya tidak tahu bagaimana cara mereka bekerja.

Beberapa waktu kemudian saya diajari rekursi lagi (saya sudah mempelajarinya sendiri sebelumnya, tetapi sekarang di kelas) dan saya bertanya bagaimana cara kerjanya di bawah tenda - di mana variabel-variabel terpisah disimpan. Profesor saya berkata "di tumpukan" dan banyak hal menjadi jelas bagi saya. Saya telah mendengar istilah sebelumnya dan telah mengimplementasikan tumpukan perangkat lunak sebelumnya. Saya telah mendengar orang lain merujuk pada "tumpukan" jauh sebelumnya, tetapi telah melupakannya.

Sekitar waktu ini saya juga menyadari bahwa menggunakan array multidimensi dalam C bisa sangat membingungkan. Saya tahu bagaimana mereka bekerja, tetapi mereka sangat mudah terjerat sehingga saya memutuskan untuk mencoba menggunakannya kapan saja saya bisa. Saya pikir masalah di sini sebagian besar sintaksis (terutama melewati atau mengembalikannya dari fungsi).

Karena saya sedang menulis C ++ untuk sekolah untuk satu atau dua tahun ke depan saya mendapat banyak pengalaman menggunakan pointer untuk struktur data. Di sini saya punya satu set masalah baru - mencampur pointer. Saya akan memiliki beberapa level pointer (hal-hal seperti node ***ptr;) membuat saya tersandung. Saya akan merujuk pointer berapa kali salah dan akhirnya mencari tahu berapa banyak* saya butuhkan dengan coba-coba.

Pada titik tertentu saya belajar bagaimana tumpukan program bekerja (semacam, tapi cukup bagus sehingga tidak lagi membuat saya terjaga di malam hari). Saya ingat pernah membaca bahwa jika Anda melihat beberapa byte sebelum pointer yang mallocpada sistem tertentu kembali, Anda dapat melihat berapa banyak data yang sebenarnya dialokasikan. Saya menyadari bahwa kode ini mallocdapat meminta lebih banyak memori dari OS dan memori ini bukan bagian dari file yang dapat dieksekusi. Memiliki ide kerja yang layak tentang cara mallockerja adalah hal yang sangat berguna.

Segera setelah ini saya mengambil kelas perakitan, yang tidak mengajarkan saya banyak tentang petunjuk seperti kebanyakan programmer mungkin berpikir. Itu membuat saya berpikir lebih banyak tentang perakitan apa kode saya mungkin diterjemahkan ke dalam. Saya selalu mencoba menulis kode yang efisien, tetapi sekarang saya punya ide yang lebih baik.

Saya juga mengambil beberapa kelas di mana saya harus menulis beberapa lisp . Ketika menulis lisp saya tidak begitu peduli dengan efisiensi seperti saya di C. Saya punya sedikit ide tentang kode ini jika diterjemahkan, jika dikompilasi, tetapi saya tahu bahwa sepertinya menggunakan banyak simbol lokal bernama (variabel) yang dibuat banyak hal lebih mudah. Pada titik tertentu saya menulis beberapa kode rotasi pohon AVL dalam sedikit lisp, bahwa saya mengalami kesulitan menulis di C ++ karena masalah pointer. Saya menyadari bahwa keengganan saya untuk apa yang saya pikir kelebihan variabel lokal telah menghambat kemampuan saya untuk menulis itu dan beberapa program lain di C ++.

Saya juga mengikuti kelas kompiler. Sementara di kelas ini saya beralih ke materi lanjutan dan belajar tentang static single assignment (SSA) dan variabel mati, yang tidak begitu penting kecuali bahwa itu mengajari saya bahwa setiap kompiler yang layak akan melakukan pekerjaan yang layak untuk berurusan dengan variabel yang tidak lagi digunakan. Saya sudah tahu bahwa lebih banyak variabel (termasuk pointer) dengan jenis yang benar dan nama baik akan membantu saya menjaga hal-hal tetap di kepala saya, tetapi sekarang saya juga tahu bahwa menghindari mereka karena alasan efisiensi bahkan lebih bodoh daripada profesor berpikiran kurang optimasi mikro saya mengatakan kepada saya.

Jadi bagi saya, mengetahui sedikit tentang tata letak memori suatu program sangat membantu. Memikirkan apa arti kode saya, baik secara simbolis maupun pada perangkat keras, membantu saya keluar. Menggunakan pointer lokal yang memiliki tipe yang benar sangat membantu. Saya sering menulis kode yang terlihat seperti:

int foo(struct frog * f, int x, int y) {
    struct leg * g = f->left_leg;
    struct toe * t = g->big_toe;
    process(t);

sehingga jika saya mengacaukan tipe pointer sangat jelas oleh kesalahan kompiler apa masalahnya. Jika saya melakukannya:

int foo(struct frog * f, int x, int y) {
    process(f->left_leg->big_toe);

dan ada jenis pointer yang salah di sana, kesalahan kompiler akan jauh lebih sulit untuk dipecahkan. Saya akan tergoda untuk menggunakan perubahan coba-coba dalam frustrasi saya, dan mungkin membuat segalanya lebih buruk.

nategoose
sumber
1
+1. Teliti dan berwawasan luas. Saya lupa tentang scanf, tetapi sekarang setelah Anda membahasnya, saya ingat memiliki kebingungan yang sama.
Joe White
6

Menoleh ke belakang, ada empat hal yang benar-benar membantu saya untuk akhirnya memahami petunjuk. Sebelum ini, saya bisa menggunakannya, tetapi saya tidak sepenuhnya memahaminya. Yaitu, saya tahu jika saya mengikuti formulir, saya akan mendapatkan hasil yang saya inginkan, tetapi saya tidak sepenuhnya memahami 'mengapa' formulir tersebut. Saya menyadari bahwa ini bukan apa yang Anda tanyakan, tetapi saya pikir ini adalah akibat wajar yang berguna.

  1. Menulis rutin yang membawa pointer ke integer dan memodifikasi integer. Ini memberi saya bentuk yang diperlukan untuk membangun model mental bagaimana pointer bekerja.

  2. Alokasi memori dinamis satu dimensi. Mencari tahu alokasi memori 1-D membuat saya memahami konsep pointer.

  3. Alokasi memori dinamis dua dimensi. Mencari tahu alokasi memori 2-D memperkuat konsep itu, tetapi juga mengajari saya bahwa pointer itu sendiri membutuhkan penyimpanan dan harus diperhitungkan.

  4. Perbedaan antara variabel tumpukan, variabel global dan memori tumpukan. Mencari tahu perbedaan-perbedaan ini mengajari saya jenis-jenis memori yang menjadi titik / rujukan.

Masing-masing barang ini diperlukan untuk membayangkan apa yang sedang terjadi di tingkat yang lebih rendah - membangun model mental yang memuaskan setiap kasus yang saya bisa pikirkan untuk melemparkannya. Butuh waktu dan usaha, tetapi itu sepadan. Saya yakin bahwa untuk memahami petunjuk, Anda harus membangun model mental tentang cara kerjanya dan bagaimana penerapannya.

Sekarang kembali ke pertanyaan awal Anda. Berdasarkan daftar sebelumnya, ada beberapa item yang saya sulit pegang pada awalnya.

  1. Bagaimana dan mengapa orang menggunakan pointer.
  2. Bagaimana mereka berbeda dan mirip dengan array.
  3. Memahami di mana informasi pointer disimpan.
  4. Memahami apa dan di mana itu adalah pointer menunjuk.
Sparky
sumber
Hei, bisakah Anda mengarahkan saya ke artikel / buku / gambar / doodle / apa pun di mana saya bisa belajar dengan cara yang sama seperti yang Anda jelaskan dalam jawaban Anda? Saya sangat percaya bahwa ini adalah cara untuk pergi ketika belajar dengan baik, pada dasarnya apa saja. Pemahaman yang mendalam dan model mental yang baik
Alexander Starbuck
1
@AlexStarbuck - Saya tidak bermaksud untuk ini terdengar kurang ajar, tetapi metode ilmiah adalah alat yang hebat. Gambar diri sendiri tentang apa yang menurut Anda mungkin terjadi untuk skenario tertentu. Program sesuatu untuk mengujinya, dan menganalisis apa yang Anda dapatkan. Apakah itu sesuai dengan yang Anda harapkan? Jika tidak, identifikasi di mana perbedaannya? Ulangi seperlunya, secara bertahap tingkatkan kompleksitas untuk menguji pemahaman dan model mental Anda.
Sparky
6

Saya memiliki "momen penunjuk" saya bekerja pada beberapa program telepon di C. Saya harus menulis emulator pertukaran AXE10 menggunakan penganalisa protokol yang hanya mengerti klasik C. Semuanya bergantung pada mengetahui petunjuk. Saya mencoba menulis kode tanpa mereka (hei, saya "pre-pointer" membuat saya sedikit malas) dan gagal total.

Kunci untuk memahami mereka, bagi saya, adalah operator & (alamat). Setelah saya mengerti itu &iberarti "alamat saya" maka pemahaman itu *iberarti "isi alamat yang ditunjukkan oleh saya" datang sedikit kemudian. Setiap kali saya menulis atau membaca kode saya, saya selalu mengulangi apa arti "&" dan apa arti "*" dan akhirnya saya menggunakannya secara intuitif.

Untuk rasa malu saya, saya dipaksa ke VB dan kemudian Java sehingga pengetahuan pointer saya tidak setajam dulu, tapi saya senang saya "post-pointer". Namun, jangan tanya saya untuk menggunakan perpustakaan yang mengharuskan saya untuk memahami * * p.

Gary Rowe
sumber
Jika &ialamat dan *iisinya, apa itu i?
Thomas Ahle
2
Saya agak overloading penggunaan i. Untuk variabel arbitrer i, & i berarti "alamat" i, i dengan sendirinya berarti "isi & i", dan * i berarti "memperlakukan konten & i sebagai alamat, buka alamat itu, dan kembalikan isi".
Gary Rowe
5

Kesulitan utama dengan pointer, setidaknya bagi saya, adalah bahwa saya tidak memulai dengan C. Saya mulai dengan Java. Seluruh gagasan tentang pointer benar-benar asing sampai beberapa kelas di perguruan tinggi tempat saya diharapkan mengenal C. Jadi, saya belajar sendiri dasar-dasar C dan bagaimana menggunakan pointer dalam arti yang sangat mendasar. Bahkan kemudian, setiap kali saya membaca kode C, saya harus mencari sintaks pointer.

Jadi dalam pengalaman saya yang sangat terbatas (dunia nyata 1 tahun + 4 di perguruan tinggi), petunjuk membingungkan saya karena saya tidak pernah benar-benar menggunakannya dalam apa pun selain pengaturan ruang kelas. Dan saya dapat bersimpati dengan para siswa sekarang mulai CS dengan JAVA bukan C atau C ++. Seperti yang Anda katakan, Anda mempelajari petunjuk di era 'Neolitik' dan mungkin telah menggunakannya sejak itu. Bagi kami orang yang lebih baru, gagasan mengalokasikan memori dan melakukan aritmatika pointer benar-benar asing karena semua bahasa ini telah mengabstraksikan begitu saja.

PS Setelah membaca esai Spolsky, deskripsinya tentang 'JavaSchools' tidak seperti apa yang saya lalui di perguruan tinggi di Cornell ('05 -'09). Saya mengambil struktur dan pemrograman fungsional (sml), sistem operasi (C), algoritma (pena dan kertas), dan seluruh kelas lain yang tidak diajarkan di java. Namun semua kelas intro dan pilihan semuanya dilakukan di java karena ada nilai dalam tidak menciptakan kembali roda ketika Anda mencoba untuk melakukan sesuatu yang lebih tinggi levelnya daripada mengimplementasikan hashtable dengan pointer.

kotak sepatu639
sumber
4
Jujur, mengingat Anda masih memiliki kesulitan dengan pointer, saya tidak yakin bahwa pengalaman Anda di Cornell secara substansial bertentangan dengan artikel Joel. Jelas sekali otak Anda terhubung dengan pola pikir Jawa untuk menegaskan maksudnya.
jkerian
5
Wat? Referensi dalam Java (atau C #, atau Python, atau banyak sekali bahasa lainnya) hanyalah pointer tanpa aritmatika. Memahami petunjuk berarti memahami mengapa void foo(Clazz obj) { obj = new Clazz(); }tidak boleh ada saat void bar(Clazz obj) { obj.quux = new Quux(); }mengubah argumen ...
1
Saya tahu referensi apa yang ada di Jawa, tetapi saya hanya mengatakan bahwa jika Anda meminta saya untuk melakukan refleksi di Jawa atau menulis sesuatu yang bermakna dalam CI tidak bisa begitu saja membungkamnya. Itu membutuhkan banyak penelitian, seperti mempelajarinya untuk pertama kali, setiap kali.
shoebox639
1
Bagaimana Anda bisa melewati kelas sistem operasi di C tanpa menjadi fasih dalam C? Tidak ada pelanggaran yang dimaksudkan, hanya saja saya ingat harus cukup banyak mengembangkan sistem operasi sederhana dari awal. Saya harus menggunakan pointer seribu kali ...
Gravity
5

Berikut ini adalah non-jawaban: Gunakan cdecl (atau c ++ decl) untuk mencari tahu:

eisbaw@leno:~$ cdecl explain 'int (*(*foo)(const void *))[3]'
declare foo as pointer to function (pointer to const void) returning pointer to array 3 of int
eisbaw
sumber
4

Mereka menambahkan dimensi ekstra pada kode tanpa perubahan signifikan pada sintaksis. Pikirkan tentang ini:

int a;
a = 5

Hanya ada satu hal untuk perubahan: a. Anda dapat menulis a = 6dan hasilnya jelas bagi kebanyakan orang. Tetapi sekarang pertimbangkan:

int *a;
a = &some_int;

Ada dua hal ayang relevan pada waktu yang berbeda: nilai aktual a, pointer, dan nilai "di belakang" pointer. Anda dapat mengubah a:

a = &some_other_int;

... dan some_intmasih ada di suatu tempat dengan nilai yang sama. Tetapi Anda juga dapat mengubah hal yang ditunjukkannya:

*a = 6;

Ada kesenjangan konseptual antara a = 6, yang hanya memiliki efek samping lokal, dan *a = 6, yang dapat mempengaruhi banyak hal lain di tempat lain. Maksud saya di sini adalah tidak bahwa konsep tipuan secara inheren rumit, tapi itu karena Anda bisa melakukan keduanya dengan segera, hal lokal dengan aatau hal tidak langsung dengan *a... yang mungkin apa yang membingungkan orang.

detly
sumber
4

Saya telah memprogram dalam c ++ selama 2 tahun dan kemudian dikonversi ke Java (5 tahun) dan tidak pernah melihat ke belakang. Namun, ketika saya baru-baru ini harus menggunakan beberapa barang asli, saya menemukan (dengan takjub) bahwa saya tidak melupakan apa pun tentang petunjuk dan saya bahkan menemukan mereka mudah digunakan. Ini sangat kontras dengan apa yang saya alami 7 tahun lalu ketika saya pertama kali mencoba memahami konsep tersebut. Jadi, saya kira pemahaman dan kesukaan adalah masalah kematangan pemrograman? :)

ATAU

Pointer seperti mengendarai sepeda, begitu Anda mengetahui cara bekerja dengan mereka, tidak ada yang lupa.

Semua dalam semua, sulit untuk dipahami atau tidak, ide pointer keseluruhan SANGAT mendidik dan saya percaya itu harus dipahami oleh setiap programmer terlepas apakah dia memprogram bahasa dengan pointer atau tidak.

Nikola Yovchev
sumber
3

Pointer sulit karena tipuan.

jason
sumber
"Dikatakan bahwa tidak ada masalah dalam ilmu komputer yang tidak dapat diselesaikan dengan satu tingkat tipuan lagi" (meskipun tidak ada yang mengatakannya terlebih dahulu)
The Archetypal Paul
Ini seperti sihir, di mana penyesatan adalah hal yang membingungkan orang (tapi benar-benar hebat)
Nick T
3

Pointer (bersama dengan beberapa aspek lain dari pekerjaan tingkat rendah), mengharuskan pengguna untuk mengambil keajaiban.

Kebanyakan programmer tingkat tinggi menyukai keajaiban.

Paul Nathan
sumber
3

Pointer adalah cara berurusan dengan perbedaan antara pegangan ke objek dan objek itu sendiri. (ok, belum tentu benda, tapi Anda tahu apa yang saya maksud, serta di mana pikiran saya berada)

Pada titik tertentu, Anda mungkin harus berurusan dengan perbedaan antara keduanya. Dalam bahasa modern tingkat tinggi ini menjadi perbedaan antara copy-by-value dan copy-by-reference. Apa pun itu, ini adalah konsep yang sering sulit dipahami oleh para programmer.

Namun, seperti yang telah ditunjukkan, sintaks untuk menangani masalah ini dalam C jelek, tidak konsisten, dan membingungkan. Akhirnya, jika Anda benar-benar berusaha memahaminya, sebuah pointer akan masuk akal. Tetapi ketika Anda mulai berurusan dengan pointer ke pointer, dan seterusnya ad nauseum, itu menjadi sangat membingungkan bagi saya serta bagi orang lain.

Hal penting lain yang perlu diingat tentang pointer adalah mereka berbahaya.C adalah bahasa master programmer. Ini mengasumsikan Anda tahu apa yang sedang Anda lakukan dan dengan demikian memberi Anda kekuatan untuk benar-benar mengacaukan segalanya. Sementara beberapa jenis program masih perlu ditulis dalam C, sebagian besar program tidak, dan jika Anda memiliki bahasa yang memberikan abstraksi yang lebih baik untuk perbedaan antara objek dan pegangannya, maka saya sarankan Anda menggunakannya.

Memang, dalam banyak aplikasi C ++ modern, sering terjadi bahwa aritmatika pointer yang diperlukan dienkapsulasi dan diabstraksi. Kami tidak ingin pengembang melakukan aritmatika pointer di semua tempat. Kami menginginkan API terpusat dan teruji dengan baik yang melakukan aritmatika penunjuk di tingkat terendah. Membuat perubahan pada kode ini harus dilakukan dengan sangat hati-hati dan pengujian ekstensif.

Samo
sumber
3

Saya pikir salah satu alasan C pointer sulit adalah mereka mengacaukan beberapa konsep yang tidak benar-benar setara; namun, karena semuanya diimplementasikan menggunakan pointer, orang dapat mengalami kesulitan menguraikan konsep.

Di C, pointer digunakan untuk, di antara hal-hal lain:

  • Tentukan struktur data rekursif

Di C Anda akan mendefinisikan daftar bilangan bulat yang ditautkan seperti ini:

struct node {
  int value;
  struct node* next;
}

Pointer hanya ada di sana karena ini adalah satu-satunya cara untuk mendefinisikan struktur data rekursif dalam C, ketika konsep itu benar-benar tidak ada hubungannya dengan detail tingkat rendah seperti alamat memori. Pertimbangkan persamaan berikut di Haskell, yang tidak memerlukan penggunaan pointer:

data List = List Int List | Null

Cukup mudah - daftar kosong, atau dibentuk dari nilai dan sisa daftar.

  • Ulangi string dan array

Inilah cara Anda menerapkan fungsi fooke setiap karakter string dalam C:

char *c;
for (c = "hello, world!"; *c != '\0'; c++) { foo(c); }

Meskipun juga menggunakan pointer sebagai iterator, contoh ini memiliki sedikit kesamaan dengan yang sebelumnya. Membuat iterator yang dapat Anda tambahkan adalah konsep yang berbeda dari mendefinisikan struktur data rekursif. Tidak ada konsep yang secara khusus terkait dengan ide alamat memori.

  • Mencapai polimorfisme

Berikut adalah tanda tangan fungsi aktual yang ditemukan di glib :

typedef struct g_list GList;

void  g_list_foreach    (GList *list,
                 void (*func)(void *data, void *user_data),
                         void* user_data);

Wah! Itu cukup seteguk void*. Dan itu semua hanya untuk mendeklarasikan fungsi yang beralih ke daftar yang dapat berisi segala hal, menerapkan fungsi untuk setiap anggota. Bandingkan dengan cara mapyang dinyatakan dalam Haskell:

map::(a->b)->[a]->[b]

Itu jauh lebih mudah: mapadalah fungsi yang mengambil fungsi yang mengonversikan ake b, dan menerapkannya ke daftar auntuk menghasilkan daftar b. Sama seperti dalam fungsi C g_list_foreach, maptidak perlu tahu apa pun dalam definisi sendiri tentang tipe yang akan diterapkan.

Untuk menyimpulkan:

Saya pikir pointer C akan jauh lebih membingungkan jika orang pertama kali belajar tentang struktur data rekursif, iterator, polimorfisme, dll. Sebagai konsep yang terpisah, dan kemudian belajar bagaimana pointer dapat digunakan untuk mengimplementasikan ide-ide tersebut dalam C , daripada menindas semua ini konsep bersama menjadi satu subjek "pointer".

gcbenison
sumber
c != NULLContoh penyalahgunaan dalam "Halo dunia" Anda ... maksud Anda *c != '\0'.
Olaf Seibert
2

Saya pikir itu membutuhkan fondasi yang kuat, mungkin dari tingkat mesin, dengan pengenalan beberapa kode mesin, perakitan, dan bagaimana merepresentasikan item dan struktur data dalam RAM. Dibutuhkan sedikit waktu, beberapa pekerjaan rumah atau latihan pemecahan masalah, dan beberapa pemikiran.

Tetapi jika seseorang tahu bahasa tingkat tinggi pada awalnya (yang tidak ada salahnya - seorang tukang kayu menggunakan kapak. Seseorang yang perlu membagi atom menggunakan sesuatu yang lain. Kita membutuhkan orang-orang yang tukang kayu, dan kita memiliki orang-orang yang mempelajari atom) dan orang yang tahu bahasa tingkat tinggi ini diberikan pengantar pointer selama 2 menit, dan kemudian sulit untuk mengharapkannya memahami pointer aritmatika, pointer ke pointer, array pointer ke string ukuran variabel, dan array array karakter, dll. Fondasi solid tingkat rendah dapat banyak membantu.

nonopolaritas
sumber
2
Pointer grouting tidak memerlukan pemahaman tentang kode mesin atau perakitan.
jason
Membutuhkan, no. Tetapi orang-orang yang memahami kebaktian kemungkinan akan menemukan petunjuk lebih banyak, lebih mudah, karena mereka telah membuat sebagian besar (jika tidak semua) koneksi mental yang diperlukan.
cHao
2

Masalah yang selalu saya alami (terutama otodidak) adalah "kapan" menggunakan pointer. Saya dapat membungkus kepala saya di sekitar sintaks untuk membangun pointer tetapi saya perlu tahu dalam keadaan apa pointer harus digunakan.

Apakah saya satu-satunya dengan pola pikir ini? ;-)

Larry
sumber
Saya mengerti. Respons saya agak berurusan dengan itu.
J. Polfer
2

Sekali waktu ... Kami memiliki mikroprosesor 8 bit dan semua orang menulis dalam pertemuan. Sebagian besar prosesor menyertakan beberapa jenis pengalamatan tidak langsung yang digunakan untuk tabel lompatan dan kernel. Ketika bahasa tingkat yang lebih tinggi datang, kami menambahkan lapisan tipis abstraksi dan menyebutnya pointer. Selama bertahun-tahun kami semakin menjauh dari perangkat keras. Ini belum tentu hal yang buruk. Mereka disebut bahasa tingkat yang lebih tinggi karena suatu alasan. Semakin saya dapat berkonsentrasi pada apa yang ingin saya lakukan daripada rincian tentang bagaimana hal itu dilakukan dengan lebih baik.

Jim C
sumber
2

Tampaknya banyak siswa memiliki masalah dengan konsep tipuan, terutama ketika mereka bertemu konsep tipuan untuk pertama kalinya. Saya ingat dari belakang ketika saya masih seorang siswa yang keluar dari +100 siswa kursus saya, hanya segelintir orang yang benar-benar mengerti petunjuk.

Konsep tipuan bukanlah sesuatu yang sering kita gunakan dalam kehidupan nyata, dan karena itu konsep sulit untuk dipahami pada awalnya.

axilmar
sumber
2

Saya baru saja memiliki momen klik pointer, dan saya terkejut bahwa saya telah menemukan itu membingungkan. Lebih dari itu semua orang membicarakannya begitu banyak, sehingga saya berasumsi bahwa sihir gelap sedang terjadi.

Cara saya mendapatkannya adalah ini. Bayangkan bahwa semua variabel yang ditentukan diberikan ruang memori pada waktu kompilasi (pada stack). Jika Anda menginginkan program yang dapat menangani file data besar seperti audio atau gambar, Anda tidak akan menginginkan jumlah memori yang tetap untuk struktur potensial ini. Jadi Anda menunggu sampai runtime untuk menetapkan sejumlah memori untuk menyimpan data ini (di heap).

Setelah Anda memiliki data di memori, Anda tidak ingin menyalin data itu di sekitar bus memori Anda setiap kali Anda ingin menjalankan operasi di dalamnya. Katakanlah Anda ingin menerapkan filter ke data gambar Anda. Anda memiliki pointer yang dimulai di bagian depan data yang telah Anda tetapkan untuk gambar, dan sebuah fungsi berjalan melintasi data itu, mengubahnya di tempat. Jika Anda tidak tahu apa yang kami lakukan, Anda mungkin akan akhirnya membuat duplikat data, saat Anda menjalankannya melalui operasi.

Setidaknya itulah yang saya lihat saat ini!

Chris Barry
sumber
Sebagai pemikiran, Anda dapat menentukan jumlah memori tetap untuk menyimpan gambar / audio / video, katakan pada perangkat terbatas memori, tetapi kemudian Anda harus berurusan dengan beberapa jenis streaming masuk dan keluar dari solusi memori.
Chris Barry
1

Berbicara sebagai pemula C ++ di sini:

Sistem pointer membutuhkan waktu cukup lama bagi saya untuk mencerna tidak perlu karena konsep tetapi karena sintaksis C ++ relatif ke Jawa. Beberapa hal yang menurut saya membingungkan adalah:

(1) Deklarasi variabel:

A a(1);

vs.

A a = A(1);

vs.

A* a = new A(1); 

dan rupanya

A a(); 

adalah deklarasi fungsi dan bukan deklarasi variabel. Dalam bahasa lain, pada dasarnya hanya ada satu cara untuk mendeklarasikan variabel.

(2) Ampersand digunakan dalam beberapa cara berbeda. Jika memang

int* i = &a;

maka & a adalah alamat memori.

OTOH, jika itu

void f(int &a) {}

maka & a adalah parameter referensi-per-lewat.

Meskipun ini mungkin tampak sepele, ini bisa membingungkan bagi pengguna baru - saya berasal dari bahasa Jawa dan Jawa dengan penggunaan operator yang lebih seragam

(3) Hubungan array-pointer

Satu hal yang agak sulit untuk dipahami adalah sebuah pointer

int* i

bisa menjadi pointer ke int

int *i = &n; // 

atau

bisa berupa array ke int

int* i = new int[5];

Dan kemudian hanya untuk membuat hal-hal berantakan, pointer dan array tidak dapat dipertukarkan dalam semua kasus dan pointer tidak dapat dilewatkan sebagai parameter array.

Ini meringkas beberapa frustrasi dasar yang saya miliki dengan C / C ++ dan petunjuknya, yang IMO, sangat diperparah oleh fakta bahwa C / C ++ memiliki semua kebiasaan khusus bahasa ini.

Some Newbie
sumber
C ++ 2011 telah meningkatkan banyak hal sejauh deklarasi variabel yang bersangkutan.
gnasher729
0

Saya pribadi tidak mengerti pointer bahkan setelah saya lulus dan setelah pekerjaan pertama saya. Satu-satunya hal yang saya ketahui adalah bahwa Anda memerlukannya untuk daftar yang ditautkan, pohon biner dan untuk melewatkan array ke dalam fungsi. Ini adalah situasi bahkan pada pekerjaan pertama saya. Hanya ketika saya mulai memberikan wawancara, saya mengerti bahwa konsep pointer sangat mendalam dan memiliki potensi dan penggunaan yang luar biasa. Kemudian saya mulai membaca K&R dan menulis program tes sendiri. Seluruh tujuan saya didorong oleh pekerjaan.
Pada saat ini saya menemukan bahwa pointer benar-benar tidak buruk atau sulit jika mereka diajarkan dengan cara yang baik. Sayangnya ketika saya belajar C dalam kelulusan, guru yang keluar tidak mengetahui pointer, dan bahkan tugasnya menggunakan pointer yang lebih sedikit. Di tingkat pascasarjana penggunaan pointer benar-benar hanya untuk membuat pohon biner dan daftar tertaut. Pemikiran ini bahwa Anda tidak memerlukan pemahaman yang tepat tentang pointer untuk bekerja dengan mereka, bunuh ide untuk mempelajarinya.

Manoj R
sumber
0

Pointer .. hah .. semua tentang pointer di kepalaku adalah bahwa ia memberikan alamat memori di mana nilai aktual dari apa pun referensi itu .. jadi tidak ada keajaiban tentang itu .. jika Anda belajar perakitan Anda tidak akan memiliki banyak kesulitan belajar bagaimana pointer berfungsi .. ayo teman-teman ... bahkan di Jawa semuanya adalah referensi ..

cass
sumber
0

Masalah utama orang tidak mengerti mengapa mereka membutuhkan petunjuk. Karena mereka tidak jelas tentang tumpukan dan tumpukan. Adalah baik untuk memulai dari assembler 16bit untuk x86 dengan mode memori kecil. Ini membantu banyak orang untuk mendapatkan ide stack, heap dan "address". Dan byte :) Programmer modern kadang-kadang tidak bisa memberi tahu Anda berapa banyak byte yang Anda butuhkan untuk mengatasi ruang 32 bit. Bagaimana mereka bisa mendapatkan petunjuk?

Momen kedua adalah notasi: Anda menyatakan pointer sebagai *, Anda mendapatkan alamat sebagai & dan ini tidak mudah dimengerti bagi sebagian orang.

Dan hal terakhir yang saya lihat adalah masalah penyimpanan: mereka mengerti heap dan stack tetapi tidak bisa memahami "statis".

pengguna996142
sumber