Jika C tidak mendukung melewati variabel dengan referensi, mengapa ini bekerja?
#include <stdio.h>
void f(int *j) {
(*j)++;
}
int main() {
int i = 20;
int *p = &i;
f(p);
printf("i = %d\n", i);
return 0;
}
Keluaran:
$ gcc -std=c99 test.c
$ a.exe
i = 21
&
) sebelum memanggil fungsi dan secara eksplisit men-decereference (with*
) dalam fungsi.f(&i);
ini adalah implementasi pass by reference, yang tidak ada murni dalam C. C pass by referenceJawaban:
Karena Anda melewatkan nilai pointer ke metode dan kemudian mendereferensi untuk mendapatkan integer yang ditunjuk.
sumber
func
:func(&A);
Ini akan meneruskan pointer ke A ke fungsi tanpa menyalin apa pun. Ini adalah nilai per nilai, tetapi nilai itu adalah referensi, jadi Anda 'meneruskan variabel' variabel A. Tidak perlu menyalin. Ini valid untuk mengatakan itu hanya sebagai referensi.Itu bukan pass-by-reference, yaitu pass-by-value seperti yang dinyatakan orang lain.
Aturannya adalah sebagai berikut:
Mari kita coba melihat perbedaan antara parameter skalar dan pointer dari suatu fungsi.
Variabel skalar
Program singkat ini menunjukkan nilai per nilai menggunakan variabel skalar.
param
disebut parameter formal danvariable
pada pemanggilan fungsi disebut parameter aktual. Catatan kenaikanparam
fungsi tidak berubahvariable
.Hasilnya adalah
Ilusi pass-by-reference
Kami mengubah sedikit kode.
param
adalah pointer sekarang.Hasilnya adalah
Itu membuat Anda percaya bahwa parameter dilewatkan oleh referensi. Bukan itu. Itu diteruskan oleh nilai, nilai param menjadi alamat. Nilai tipe int bertambah, dan itulah efek samping yang membuat kita berpikir bahwa itu adalah panggilan fungsi pass-by-reference.
Pointer - melewati nilai
Bagaimana kita bisa menunjukkan / membuktikan fakta itu? Yah, mungkin kita bisa mencoba contoh pertama variabel Scalar, tetapi alih-alih skalar kita menggunakan alamat (pointer). Mari kita lihat apakah itu bisa membantu.
Hasilnya adalah bahwa kedua alamat tersebut sama (jangan khawatir tentang nilai pastinya).
Contoh hasil:
Menurut pendapat saya ini membuktikan dengan jelas bahwa pointer dilewatkan oleh nilai. Kalau tidak
ptr
akanNULL
setelah pemanggilan fungsi.sumber
Sumber: www-cs-students.stanford.edu
sumber
Karena tidak ada pass-by-reference dalam kode di atas. Menggunakan pointer (seperti
void func(int* p)
) adalah pass-by-address. Ini adalah referensi per detik dalam C ++ (tidak akan berfungsi dalam C):sumber
Contoh Anda berfungsi karena Anda meneruskan alamat variabel Anda ke fungsi yang memanipulasi nilainya dengan operator dereference .
Sementara C tidak mendukung tipe data referensi , Anda masih bisa mensimulasikan melewati-oleh-referensi dengan secara eksplisit melewati nilai pointer, seperti dalam contoh Anda.
Tipe data referensi C ++ kurang kuat tetapi dianggap lebih aman daripada tipe pointer yang diwarisi dari C. Ini akan menjadi contoh Anda, disesuaikan untuk menggunakan referensi C ++ :
sumber
Anda melewati sebuah pointer (alamat lokasi) berdasarkan nilai .
Itu seperti mengatakan "inilah tempat dengan data yang saya ingin Anda perbarui."
sumber
p adalah variabel pointer. Nilainya adalah alamat i. Saat Anda memanggil f, Anda meneruskan nilai p, yang merupakan alamat i.
sumber
Tidak ada pass-by-reference di C, tetapi p "merujuk" ke i, dan Anda melewatkan p dengan nilai.
sumber
Dalam C semuanya pass-by-value. Penggunaan pointer memberi kita ilusi bahwa kita melewati referensi karena nilai variabel berubah. Namun, jika Anda mencetak alamat variabel pointer, Anda akan melihat bahwa itu tidak terpengaruh. Sebuah salinan dari nilai dari alamat dilewatkan-in ke fungsi. Di bawah ini adalah cuplikan yang menggambarkan hal itu.
sumber
Karena Anda melewatkan pointer (alamat memori) ke variabel p ke dalam fungsi f. Dengan kata lain Anda melewatkan pointer bukan referensi.
sumber
Jawaban singkat: Ya, C mengimplementasikan parameter passing dengan referensi menggunakan pointer.
Saat mengimplementasikan parameter passing, perancang bahasa pemrograman menggunakan tiga strategi yang berbeda (atau model semantik): mentransfer data ke subprogram, menerima data dari subprogram, atau melakukan keduanya. Model-model ini umumnya dikenal sebagai dalam mode, mode keluar, dan mode keluar, sesuai.
Beberapa model telah dirancang oleh perancang bahasa untuk menerapkan tiga strategi pengoperan parameter dasar ini:
Pass-by-Value (dalam mode semantik) Pass-by-Result (semantik mode out) Pass-by-Value-Result (semantik mode inout) Pass-by-Reference (semantik mode inout) Pass-by-Name (mode inout) semantik)
Pass-by-reference adalah teknik kedua untuk passing parameter mode keluar. Alih-alih menyalin data bolak-balik antara rutin utama dan subprogram, sistem runtime mengirim jalur akses langsung ke data untuk subprogram. Dalam strategi ini, subprogram memiliki akses langsung ke data yang secara efektif berbagi data dengan rutin utama. Keuntungan utama dengan teknik ini adalah sangat efisien dalam waktu dan ruang karena tidak perlu menduplikasi ruang dan tidak ada operasi penyalinan data.
Implementasi passing parameter dalam C: C mengimplementasikan semantik nilai demi nilai dan juga semantik (inout mode) dengan menggunakan pointer sebagai parameter. Pointer dikirim ke subprogram dan tidak ada data aktual yang disalin sama sekali. Namun, karena pointer adalah jalur akses ke data rutin utama, subprogram dapat mengubah data dalam rutinitas utama. C mengadopsi metode ini dari ALGOL68.
Implementasi passing parameter dalam C ++: C ++ juga mengimplementasikan semantik pass-by-reference (mode keluaran) menggunakan pointer dan juga menggunakan pointer jenis khusus, yang disebut tipe referensi. Pointer tipe referensi secara implisit direferensikan di dalam subprogram tetapi semantik mereka juga lulus-oleh-referensi.
Jadi konsep utama di sini adalah pass-by-reference mengimplementasikan jalur akses ke data alih-alih menyalin data ke dalam subprogram. Jalur akses data dapat berupa pointer dereferensi secara eksplisit atau pointer dereferensi otomatis (tipe referensi).
Untuk info lebih lanjut, silakan merujuk ke buku Concepts of Programming Languages oleh Robert Sebesta, 10th Ed., Bab 9.
sumber
Anda tidak melewatkan int dengan referensi, Anda melewati nilai pointer-to-an-int. Sintaks berbeda, artinya sama.
sumber
void func(int* ptr){ *ptr=111; int newValue=500; ptr = &newvalue }
denganint main(){ int value=0; func(&value); printf("%i\n",value); return 0; }
, ia mencetak 111 bukannya 500. Jika Anda melewati referensi, ia akan mencetak 500. C tidak mendukung parameter lewat dengan referensi.ptr = &newvalue
akan dianulir. Terlepas dari perbedaannya, saya pikir Anda menunjukkan bahwa "makna yang sama" tidak sepenuhnya benar karena Anda juga memiliki fungsi tambahan dalam C (kemampuan untuk menetapkan kembali "referensi" itu sendiri).ptr=&newvalue
jika dilewatkan dengan referensi. Sebagai gantinya, kita menulisptr=newvalue
Di sini adalah contoh dalam C ++:void func(int& ptr){ ptr=111; int newValue=500; ptr = newValue; }
Nilai parameter yang dilewatkan ke func () akan menjadi500
.param = new Class()
di dalam fungsi tidak akan berpengaruh bagi pemanggil jika dilewatkan oleh nilai (pointer). Jikaparam
dilewatkan dengan referensi, perubahan akan terlihat oleh penelepon.Dalam C, untuk lulus dengan referensi Anda menggunakan alamat-operator
&
yang harus digunakan terhadap variabel, tetapi dalam kasus Anda, karena Anda telah menggunakan variabel pointerp
, Anda tidak perlu awalan dengan alamat-operator. Itu akan menjadi benar jika Anda digunakan&i
sebagai parameter:f(&i)
.Anda juga dapat menambahkan ini, ke dereferensi
p
dan melihat bagaimana nilai itu cocoki
:sumber
pointer dan referensi adalah dua hal yang berbeda.
Beberapa hal yang belum saya lihat disebutkan.
Pointer adalah alamat sesuatu. Pointer dapat disimpan dan disalin seperti variabel lainnya. Dengan demikian memiliki ukuran.
Referensi harus dilihat sebagai ALIAS sesuatu. Itu tidak memiliki ukuran dan tidak dapat disimpan. Ini HARUS referensi sesuatu, yaitu. itu tidak bisa nol atau diubah. Yah, kadang-kadang kompiler perlu menyimpan referensi sebagai pointer, tetapi itu adalah detail implementasi.
Dengan referensi Anda tidak memiliki masalah dengan pointer, seperti penanganan kepemilikan, pemeriksaan nol, de-referensi penggunaan.
sumber
'Lulus dengan referensi' (dengan menggunakan petunjuk) telah ada di C dari awal. Menurut Anda mengapa tidak?
sumber
j
( tidak*j
) dif()
tidak berpengaruh padai
dalammain()
.Saya pikir C sebenarnya mendukung pass by reference.
Sebagian besar bahasa membutuhkan gula sintaksis untuk lulus dengan referensi alih-alih nilai. (C ++ misalnya membutuhkan & dalam deklarasi parameter).
C juga membutuhkan gula sintaksis untuk ini. Itu * dalam deklarasi tipe parameter dan & pada argumen. Jadi * dan & adalah sintaks C untuk pass by reference.
Orang sekarang dapat berpendapat bahwa pass by reference sebenarnya hanya memerlukan sintaks pada deklarasi parameter, bukan pada sisi argumen.
Tapi sekarang datang C # yang melakukan dukungan dengan referensi yang lewat dan membutuhkan gula sintaksis pada kedua parameter dan argumen sisi.
Argumen bahwa C tidak memiliki by-ref menyebabkan elemen sintaksis untuk mengekspresikannya menunjukkan implementasi teknis yang mendasarinya bukanlah argumen sama sekali, karena ini berlaku lebih atau kurang untuk semua implementasi.
Satu-satunya argumen yang tersisa adalah bahwa melewati oleh ref dalam C bukan fitur monolitik tetapi menggabungkan dua fitur yang ada. (Ambil ref argumen oleh &, harapkan ref untuk mengetikkan dengan *.) C # misalnya memang membutuhkan dua elemen sintaksis, tetapi mereka tidak dapat digunakan tanpa satu sama lain.
Ini jelas argumen yang berbahaya, karena banyak fitur lain dalam bahasa yang terdiri dari fitur lain. (seperti dukungan string dalam C ++)
sumber
Apa yang Anda lakukan adalah nilai demi nilai, bukan referensi. Karena Anda mengirim nilai variabel 'p' ke fungsi 'f' (utama sebagai f (p);)
Program yang sama dalam C dengan pass by reference akan terlihat seperti, (!!! program ini memberikan 2 kesalahan karena pass by reference tidak didukung dalam C)
Keluaran:-
sumber