Saya memerlukan penunjuk ke array 2 dimensi statis. Bagaimana ini dilakukan?
static uint8_t l_matrix[10][20];
void test(){
uint8_t **matrix_ptr = l_matrix; //wrong idea
}
Saya mendapatkan semua jenis kesalahan seperti:
- peringatan: tugas dari tipe penunjuk yang tidak kompatibel
- nilai yang disubscribe bukanlah array atau pointer
- kesalahan: penggunaan anggota larik fleksibel tidak valid
Jawaban:
Di sini Anda ingin membuat penunjuk ke elemen pertama dari array
Dengan typedef, ini terlihat lebih bersih
Kemudian Anda bisa menikmati hidup lagi :)
Waspadalah terhadap dunia pointer / array di C, banyak kebingungan seputar ini.
Sunting
Meninjau beberapa jawaban lain di sini, karena kolom komentar terlalu pendek untuk dilakukan di sana. Beberapa alternatif diusulkan, tetapi tidak ditunjukkan bagaimana mereka berperilaku. Inilah cara mereka melakukannya
Jika Anda memperbaiki kesalahan dan menambahkan alamat-operator
&
seperti di cuplikan berikutKemudian yang satu itu membuat pointer ke tipe array yang tidak lengkap dari elemen tipe array 20 uint8_t. Karena penunjuk adalah ke array array, Anda harus mengaksesnya dengan
Dan karena ini adalah penunjuk ke larik yang tidak lengkap, Anda tidak dapat melakukannya sebagai pintasan
Karena pengindeksan memerlukan ukuran jenis elemen untuk diketahui (pengindeksan menyiratkan penambahan bilangan bulat ke penunjuk, sehingga tidak akan berfungsi dengan jenis yang tidak lengkap). Perhatikan bahwa ini hanya berfungsi di
C
, karenaT[]
danT[N]
merupakan tipe yang kompatibel. C ++ tidak memiliki konsep tipe yang kompatibel , sehingga akan menolak kode tersebut, karenaT[]
danT[10]
merupakan tipe yang berbeda.Alternatif berikut tidak berfungsi sama sekali, karena tipe elemen dari larik, saat Anda melihatnya sebagai larik satu dimensi, bukan
uint8_t
, tetapiuint8_t[20]
Berikut ini adalah alternatif yang bagus
Anda mengaksesnya dengan
Ini memiliki keuntungan karena mempertahankan ukuran dimensi luar. Jadi Anda bisa menerapkan ukuran di atasnya
Ada satu jawaban lain yang memanfaatkan fakta bahwa item dalam array disimpan secara berdekatan
Sekarang, secara formal hanya memungkinkan Anda untuk mengakses elemen elemen pertama dari array dua dimensi. Artinya, kondisi berikut berlaku
Anda akan melihatnya mungkin berhasil
10*20-1
, tetapi jika Anda menggunakan analisis alias dan pengoptimalan agresif lainnya, beberapa kompilator dapat membuat asumsi yang dapat merusak kode itu. Karena itu, saya tidak pernah menemukan kompiler yang gagal di dalamnya (tapi sekali lagi, saya belum menggunakan teknik itu dalam kode sebenarnya), dan bahkan C FAQ memiliki teknik itu (dengan peringatan tentang UB'ness-nya) ), dan jika Anda tidak dapat mengubah tipe array, ini adalah opsi terakhir untuk menyelamatkan Anda :)sumber
uint8_t *d[20]
, yang membuat larik 3 pointer ke uint8_t, tetapi itu tidak akan berfungsi dalam kasus ini.Untuk memahami ini sepenuhnya , Anda harus memahami konsep berikut:
Array bukanlah penunjuk!
Pertama-tama (Dan sudah cukup diberitakan), array bukanlah pointer . Sebaliknya, di sebagian besar penggunaan, mereka 'membusuk' ke alamat ke elemen pertama mereka, yang dapat ditetapkan ke penunjuk:
Saya berasumsi ini bekerja dengan cara ini sehingga konten array dapat diakses tanpa menyalin semuanya. Itu hanya perilaku tipe array dan tidak dimaksudkan untuk menyiratkan bahwa keduanya adalah hal yang sama.
Array multidimensi
Array multidimensi hanyalah cara untuk 'mempartisi' memori dengan cara yang dapat dipahami dan dioperasikan oleh kompiler / mesin.
Misalnya,
int a[4][3][5]
= sebuah array yang berisi 4 * 3 * 5 (60) 'potongan' memori berukuran integer.Keuntungan menggunakan
int a[4][3][5]
vs biasaint b[60]
adalah sekarang mereka 'dipartisi' (Lebih mudah untuk bekerja dengan 'chunks' mereka, jika diperlukan), dan program sekarang dapat melakukan pemeriksaan terikat.Faktanya,
int a[4][3][5]
disimpan persis sepertiint b[60]
di memori - Satu- satunya perbedaan adalah bahwa program sekarang mengelolanya seolah-olah mereka adalah entitas terpisah dengan ukuran tertentu (Secara khusus, empat grup dari tiga grup lima).Perlu diingat: Keduanya
int a[4][3][5]
danint b[60]
sama dalam memori, dan satu-satunya perbedaan adalah bagaimana mereka ditangani oleh aplikasi / kompilerDari sini, Anda dapat dengan jelas melihat bahwa setiap "partisi" hanyalah sebuah array yang dipantau oleh program.
Sintaksis
Sekarang, array secara sintaksis berbeda dari pointer . Secara khusus, ini berarti kompilator / mesin akan memperlakukannya secara berbeda. Ini mungkin tampak tidak sulit, tapi lihat ini:
Contoh di atas mencetak alamat memori yang sama dua kali, seperti ini:
Namun, hanya satu yang dapat ditetapkan ke penunjuk secara langsung :
Mengapa tidak
a
bisa ditetapkan ke penunjuk tapia[0]
bisa?Ini, sederhananya, adalah konsekuensi dari array multidimensi, dan saya akan menjelaskan alasannya:
Pada level '
a
', kami masih melihat bahwa kami memiliki 'dimensi' lain untuk dinantikan. Pada tingkatan 'a[0]
', bagaimanapun, kita sudah berada di dimensi teratas, sejauh menyangkut program kita hanya melihat array normal.Anda mungkin bertanya:
Mengapa penting jika array multidimensi dalam hal membuat penunjuk untuknya?
Cara terbaik untuk berpikir seperti ini:
Sebuah 'decay' dari array multidimensi bukan hanya sebuah alamat, tetapi sebuah alamat dengan data partisi (AKA masih memahami bahwa data dasarnya terbuat dari array lain), yang terdiri dari batas-batas yang ditetapkan oleh array di luar dimensi pertama.
Logika 'partisi' ini tidak bisa ada di dalam pointer kecuali kita menentukannya:
Jika tidak, arti properti pengurutan larik akan hilang.
Perhatikan juga penggunaan tanda kurung di sekitar
*p
:int (*p)[5][95][8]
- Itu untuk menentukan bahwa kami membuat pointer dengan batas-batas ini, bukan array pointer dengan batas-batas ini:int *p[5][95][8]
Kesimpulan
Mari kita ulas:
Singkatnya: array multidimensi membusuk ke alamat yang membawa kemampuan untuk memahami isinya.
sumber
int *p1 = &(a[0]); // RIGHT !
sebenarnya ini identik denganint *p1 = a;
Di
Anda dapat mengakses suka
setelah semua array 2 dimensi juga disimpan sebagai 1-d.
sumber
G'day,
Deklarasi
telah menyisihkan penyimpanan untuk 10 baris dari 20 lokasi unit8_t, yaitu 200 lokasi berukuran uint8_t, dengan tiap elemen ditemukan dengan menghitung 20 x baris + kolom.
Jadi tidak
memberi Anda apa yang Anda butuhkan dan arahkan ke elemen kolom nol dari baris pertama dari array?
Sunting: Berpikir tentang ini sedikit lebih jauh, bukankah nama array, menurut definisi, sebuah pointer? Artinya, nama sebuah array adalah sinonim untuk lokasi elemen pertama, yaitu l_matrix [0] [0]?
Sunting2: Seperti yang disebutkan oleh orang lain, ruang komentar agak terlalu kecil untuk diskusi lebih lanjut. Bagaimanapun:
tidak menyediakan alokasi penyimpanan apa pun untuk larik yang dimaksud.
Seperti disebutkan di atas, dan seperti yang didefinisikan oleh standar, pernyataan:
telah menyisihkan 200 lokasi berurutan tipe uint8_t.
Mengacu ke l_matrix menggunakan pernyataan bentuk:
akan memberi Anda konten elemen warna yang ditemukan di baris rowno.
Hal ini juga terjadi jika padding atau pergeseran perataan byte terlibat dalam penyimpanan objek yang ada. Kompiler akan secara otomatis menyesuaikan ini. Menurut definisi standar C ANSI.
HTH
Bersulang,
sumber
Di C99 (didukung oleh clang dan gcc) ada sintaks yang tidak jelas untuk meneruskan array multi-dimensi ke fungsi dengan referensi:
Tidak seperti pointer biasa, ini mengisyaratkan tentang ukuran array, secara teoritis memungkinkan compiler untuk memperingatkan tentang melewatkan array yang terlalu kecil dan menemukan akses di luar batas yang jelas.
Sayangnya, itu tidak memperbaiki
sizeof()
dan penyusun tampaknya belum menggunakan informasi itu, jadi tetap menjadi rasa ingin tahu.sumber
static 10
adalah semacam jaminan bahwa setidaknya ada 10 elemen, yang sekali lagi berarti ukurannya tidak tetap.static
, array tidak akan diteruskan oleh referensi, yang mana tidak benar. Array diteruskan dengan referensi. Pertanyaan asli menanyakan tentang kasus penggunaan yang berbeda - mengakses elemen array 2D menggunakan penunjuk tambahan dalam fungsi / namespace yang sama.Anda selalu dapat menghindari mengutak-atik compiler dengan mendeklarasikan array sebagai linear dan melakukan kalkulasi indeks (row, col) ke array sendiri.
inilah yang akan dilakukan oleh kompilator.
sumber
Sintaks dasar dari menginisialisasi pointer yang mengarah ke array multidimentional adalah
type (*pointer)[1st dimension size][2nd dimension size][..] = &array_name
Sintaks dasar untuk memanggilnya adalah
Berikut ini contohnya:
Outputnya adalah:
Berhasil ...
sumber
Anda bisa melakukannya seperti ini:
sumber
Anda ingin pointer ke elemen pertama, jadi;
sumber
Anda juga dapat menambahkan offset jika Anda ingin menggunakan indeks negatif:
Jika kompiler Anda memberikan kesalahan atau peringatan, Anda dapat menggunakan:
sumber
c
, jadi jawabannya harus dalam bahasa yang sama. Harap perhatikan tagnya.