Dalam sebuah proyek, seseorang mendorong baris ini:
double (*e)[n+1] = malloc((n+1) * sizeof(*e));
Yang seharusnya menciptakan array dua dimensi (n + 1) * (n + 1) ganda.
Seharusnya , saya katakan, karena sejauh ini, tidak seorang pun yang saya tanyai dapat memberi tahu saya apa fungsinya, tepatnya, atau dari mana asalnya atau mengapa itu harus berfungsi (yang diduga, memang demikian, tetapi saya belum membelinya).
Mungkin saya melewatkan sesuatu yang jelas, tetapi saya akan sangat menghargai jika seseorang dapat menjelaskan baris di atas kepada saya. Karena secara pribadi, saya akan merasa jauh lebih baik jika kita menggunakan sesuatu yang benar-benar kita pahami.
c
arrays
multidimensional-array
malloc
allocation
Pengguna1291
sumber
sumber
n+1
melainkandouble (*e)[rows] = malloc(columns * sizeof *e);
Jawaban:
Variabel
e
adalah penunjuk ke larikn + 1
elemen tipedouble
.Menggunakan operator dereferensi pada
e
memberi Anda tipe dasare
yang adalah "larikn + 1
elemen tipedouble
".The
malloc
panggilan hanya mengambil basis-jenise
(dijelaskan di atas) dan mendapat ukurannya, mengalikan dengann + 1
, dan melewati ukuran yang kemalloc
fungsi. Pada dasarnya mengalokasikan larikn + 1
larikn + 1
elemendouble
.sumber
sizeof(*e)
setara dengansizeof(double [n + 1])
. Lipat gandakan dengann + 1
dan Anda mendapatkan cukup.n+1
untuk kedua dimensi, hasilnya akan persegi. Jika Anda melakukannyadouble (*e)[cols] = malloc(rows * sizeof(*e));
, hasilnya akan memiliki jumlah baris dan kolom berapa pun yang Anda tentukan.int rows = n+1
danint cols = n+1
. Tuhan menyelamatkan kita dari kode pintar.Ini adalah cara tipikal Anda harus mengalokasikan array 2D secara dinamis.
e
adalah penunjuk larik ke larik bertipedouble [n+1]
.sizeof(*e)
oleh karena itu memberikan tipe tipe point-at, yang merupakan ukuran satudouble [n+1]
array.n+1
array tersebut.e
untuk menunjuk ke larik pertama dalam larik larik ini.e
sebagaie[i][j]
akses setiap item dalam array 2D.Secara pribadi menurut saya gaya ini jauh lebih mudah dibaca:
sumber
ptr = malloc(sizeof *ptr * count)
gaya tersebut.malloc(row*col*sizeof(double))
terjadi saatrow*col*sizeof()
meluap, tetapi tidaksizeof()*row*col
terjadi. (misalnya baris, kolomint
)sizeof *e * (n+1)
lebih mudah dirawat; jika Anda pernah memutuskan untuk mengubah tipe dasar (daridouble
menjadilong double
, misalnya), maka Anda hanya perlu mengubah deklarasi darie
; Anda tidak perlu mengubahsizeof
ekspresi dalammalloc
panggilan (yang menghemat waktu dan melindungi Anda dari mengubahnya di satu tempat tetapi tidak di tempat lain).sizeof *e
akan selalu memberi Anda ukuran yang tepat.Idiom ini secara alami keluar dari alokasi larik 1D. Mari kita mulai dengan mengalokasikan array 1D dari beberapa tipe arbitrer
T
:Sederhana bukan? The ekspresi
*p
memiliki tipeT
, sehinggasizeof *p
memberikan hasil yang sama sepertisizeof (T)
, jadi kita mengalokasikan cukup ruang untukN
berbagai -element dariT
. Ini berlaku untuk semua tipeT
.Sekarang, mari kita gantikan
T
dengan tipe array sepertiR [10]
. Kemudian alokasi kami menjadiSemantik di sini persis sama dengan metode alokasi 1D; semua yang berubah adalah jenis
p
. Alih-alihT *
, sekarangR (*)[10]
. Ekspresi*p
memiliki tipeT
yaitu tipeR [10]
, jadisizeof *p
ekuivalen dengansizeof (T)
yang ekivalen dengansizeof (R [10])
. Jadi kita mengalokasikan cukup ruang untukN
oleh10
elemen arrayR
.Kita dapat mengambil ini lebih jauh jika kita mau; misalkan
R
itu sendiri merupakan tipe arrayint [5]
. Gantikan ituR
dan kita dapatkanKesepakatan yang sama -
sizeof *p
sama dengansizeof (int [10][5])
, dan kami akhirnya mengalokasikan sebagian besar memori yang berdekatan yang cukup besar untuk menampungN
oleh10
oleh5
arrayint
.Jadi itulah sisi alokasi; bagaimana dengan sisi aksesnya?
Ingat bahwa
[]
operasi subskrip didefinisikan dalam istilah aritmatika penunjuk:a[i]
didefinisikan sebagai*(a + i)
1 . Jadi, operator subskrip[]
secara implisit merujuk sebuah pointer. Jikap
penunjuk keT
, Anda dapat mengakses nilai menunjuk ke baik dengan secara eksplisit dereferensi dengan*
operator unary :atau dengan menggunakan
[]
operator subskrip:Jadi, jika
p
menunjuk ke elemen pertama dari sebuah array , Anda dapat mengakses elemen apa pun dari array itu dengan menggunakan subskrip pada penunjukp
:Sekarang, mari kita lakukan operasi substitusi lagi dan ganti
T
dengan tipe arrayR [10]
:Satu perbedaan yang langsung terlihat; kami secara eksplisit mendereferensi
p
sebelum menerapkan operator subskrip. Kami tidak ingin subskrip kep
, kami ingin subskrip kep
poin apa (dalam hal ini, arrayarr[0]
). Sejak unary*
memiliki hak lebih rendah dari subscript[]
operator, kita harus menggunakan tanda kurung secara eksplisit kelompokp
dengan*
. Tapi ingat dari atas itu*p
sama denganp[0]
, jadi kita bisa menggantinya denganatau hanya
Jadi, jika
p
menunjuk ke larik 2D, kita bisa mengindeks ke larik itu melaluip
seperti ini:Mengambil kesimpulan yang sama seperti di atas dan menggantinya
R
denganint [5]
:Ini berfungsi sama jika
p
menunjuk ke array biasa, atau jika menunjuk ke memori yang dialokasikanmalloc
.Idiom ini memiliki manfaat sebagai berikut:
free
. Sekali lagi, tidak benar dengan metode alokasi sedikit demi sedikit, di mana Anda harus membatalkan alokasi masing-masingarr[i]
sebelum Anda dapat membatalkan alokasiarr
.Terkadang metode alokasi sedikit demi sedikit lebih disukai, seperti saat heap Anda terfragmentasi dengan buruk dan Anda tidak dapat mengalokasikan memori sebagai potongan yang berdekatan, atau Anda ingin mengalokasikan larik "bergerigi" di mana setiap baris dapat memiliki panjang yang berbeda. Tetapi secara umum, ini adalah cara yang lebih baik untuk pergi.
1. Ingat bahwa array bukanlah pointer - sebaliknya, ekspresi array diubah menjadi ekspresi pointer jika perlu.
sumber