Di C, saya tahu saya dapat secara dinamis mengalokasikan array dua dimensi di heap menggunakan kode berikut:
int** someNumbers = malloc(arrayRows*sizeof(int*));
for (i = 0; i < arrayRows; i++) {
someNumbers[i] = malloc(arrayColumns*sizeof(int));
}
Jelas, ini sebenarnya menciptakan array satu dimensi dari pointer ke sekelompok array satu dimensi yang terpisah dari integer, dan "Sistem" dapat mengetahui apa yang saya maksud ketika saya meminta:
someNumbers[4][2];
Tetapi ketika saya secara statis mendeklarasikan array 2D, seperti pada baris berikut ...:
int someNumbers[ARRAY_ROWS][ARRAY_COLUMNS];
... apakah struktur serupa dibuat pada stack, atau apakah itu dari bentuk lain sepenuhnya? (Yaitu apakah itu array 1D pointer? Jika tidak, apa itu, dan bagaimana referensi untuk itu bisa diketahui?)
Juga, ketika saya berkata, "Sistem," apa yang sebenarnya bertanggung jawab untuk mencari tahu? Kernel? Atau apakah kompiler C mengatasinya saat kompilasi?
c
arrays
memory
data-structures
stack-memory
Chris Cooper
sumber
sumber
malloc()
tidak menghasilkan array N-dimensi. . Ini menghasilkan array pointer [ke array pointer [...]] untuk sepenuhnya memisahkan array satu dimensi . Lihat Mengalokasikan array multi-dimensi dengan benar untuk melihat bagaimana mengalokasikan array N-dimensi yang BENAR .Jawaban:
Array dua dimensi yang statis terlihat seperti array array - hanya diletakkan secara berdekatan dalam memori. Array tidak sama dengan pointer, tetapi karena Anda sering dapat menggunakannya secara bergantian, terkadang membingungkan. Kompiler terus melacak dengan benar, yang membuat semuanya berbaris dengan baik. Anda harus berhati-hati dengan array 2D statis seperti yang Anda sebutkan, karena jika Anda mencoba untuk mengirimkannya ke fungsi yang mengambil
int **
parameter, hal-hal buruk akan terjadi. Ini contoh singkatnya:Dalam memori terlihat seperti ini:
persis sama dengan:
Tetapi jika Anda mencoba meneruskan
array1
ke fungsi ini:Anda akan mendapatkan peringatan (dan aplikasi akan gagal mengakses array dengan benar):
Karena array 2D tidak sama dengan
int **
. Pembusukan otomatis array menjadi pointer hanya bisa dikatakan "sedalam level". Anda perlu mendeklarasikan fungsinya sebagai:atau
Untuk membuat semuanya bahagia.
Konsep yang sama ini meluas ke n- dimensi array. Namun, mengambil keuntungan dari bisnis lucu semacam ini dalam aplikasi Anda hanya akan membuatnya lebih sulit untuk dipahami. Jadi berhati-hatilah di luar sana.
sumber
sizeof(int[100]) != sizeof(int *)
(kecuali jika Anda menemukan platform dengan100 * sizeof(int)
byte /int
, tapi itu hal yang berbeda.Jawabannya didasarkan pada gagasan bahwa C tidak benar - benar memiliki array 2D - ia memiliki array array. Ketika Anda menyatakan ini:
Anda meminta untuk
someNumbers
menjadi array dari 4 elemen, di mana setiap elemen dari array itu adalah tipeint [2]
(yang merupakan array dari 2int
s).Bagian lain dari teka-teki adalah bahwa array selalu diletakkan berdampingan dalam memori. Jika Anda meminta:
maka itu akan selalu terlihat seperti ini:
(4
sometype_t
objek diletakkan bersebelahan, tanpa spasi di antaranya). Jadi dalamsomeNumbers
array-of-array Anda, akan terlihat seperti ini:Dan setiap
int [2]
elemen itu sendiri merupakan array, yang terlihat seperti ini:Jadi secara keseluruhan, Anda mendapatkan ini:
sumber
int
dalam array array (mis. dengan mengevaluasia[0]
atau&a[0][0]
) maka ya, Anda dapat mengimbangi itu untuk mengakses secara berurutan setiapint
).dalam memori sama dengan:
sumber
Sebagai jawaban untuk Anda juga: Keduanya, meskipun kompiler melakukan sebagian besar tugas berat.
Dalam hal array yang dialokasikan secara statis, "Sistem" akan menjadi kompiler. Ini akan menyimpan memori seperti halnya untuk variabel tumpukan apa pun.
Dalam kasus array malloc'd, "Sistem" akan menjadi pelaksana malloc (biasanya kernel). Semua kompiler akan mengalokasikan adalah pointer dasar.
Compiler selalu akan menangani tipe seperti apa yang mereka nyatakan kecuali pada contoh yang diberikan Carl di mana ia dapat mengetahui penggunaan yang dapat dipertukarkan. Inilah sebabnya mengapa jika Anda meneruskan sebuah [] [] ke suatu fungsi, ia harus mengasumsikan bahwa itu adalah flat yang dialokasikan secara statis, di mana ** diasumsikan sebagai pointer ke pointer.
sumber
malloc
penerapannya tidak ditentukan oleh standar dan diserahkan kepada implementasi, resp. lingkungan Hidup. Untuk lingkungan yang berdiri bebas itu opsional seperti semua bagian dari perpustakaan standar yang membutuhkan fungsi penautan (itulah yang sebenarnya dihasilkan persyaratan, bukan literal apa yang dinyatakan standar). Untuk beberapa lingkungan yang di-host modern, itu memang bergantung pada fungsi kernel, baik hal-hal yang lengkap, atau (misalnya Linux) ketika Anda menulis menggunakan keduanya, stdlib dan kernel-primitif. Untuk sistem proses tunggal memori non-virtual, itu bisa saja stdlib.Misalkan, kita memiliki
a1
dana2
mendefinisikan dan menginisialisasi seperti di bawah ini (c99):a1
adalah array 2D homogen dengan tata letak kontinu polos dalam memori dan ekspresi(int*)a1
dievaluasi menjadi penunjuk ke elemen pertama:a2
diinisialisasi dari array 2D yang heterogen dan merupakan penunjuk ke nilai tipeint*
, yaitu ekspresi dereferensi*a2
dievaluasi menjadi nilai tipeint*
, tata letak memori tidak harus kontinu:Meskipun tata letak memori dan semantik aksesnya sangat berbeda, tata bahasa C untuk ekspresi akses-array terlihat persis sama untuk array 2D homogen dan heterogen:
a1[1][0]
akan mengambil nilai144
daria1
arraya2[1][0]
akan mengambil nilai244
daria2
arrayCompiler tahu bahwa ekspresi akses untuk
a1
beroperasi pada tipeint[2][2]
, ketika ekspresi akses untuka2
beroperasi pada tipeint**
. Kode rakitan yang dihasilkan akan mengikuti semantik akses yang homogen atau heterogen.Kode biasanya macet saat run-time ketika array
int[N][M]
tipe dicor tipe dan kemudian diakses sebagai tipeint**
, misalnya:sumber
Untuk mengakses array 2D tertentu, pertimbangkan peta memori untuk deklarasi array seperti yang ditunjukkan pada kode di bawah ini:
Untuk mengakses setiap elemen, cukup lewati saja array yang Anda minati sebagai parameter untuk fungsi tersebut. Kemudian gunakan offset untuk kolom untuk mengakses setiap elemen secara individual.
sumber