Saya ingin berulang kali membidik array 2d besar di C. Inilah yang saya lakukan saat ini:
// Array of size n * m, where n may not equal m
for(j = 0; j < n; j++)
{
for(i = 0; i < m; i++)
{
array[i][j] = 0;
}
}
Saya sudah mencoba menggunakan memset:
memset(array, 0, sizeof(array))
Tapi ini hanya berfungsi untuk array 1D. Ketika saya mencetak isi dari array 2D, baris pertama adalah nol, tapi kemudian saya mendapat beban angka besar acak dan macet.
memset
, karena Anda menyebutkan crash dari nol hanya satu baris juga.int d0=10, d1=20; int arr[d0][d1]
, danmemset(arr, 0, sizeof arr);
bekerja seperti yang diharapkan (gcc 3.4.6, dikompilasi dengan-std=c99 -Wall
flag). Saya menyadari bahwa "itu bekerja pada mesin saya" berarti jongkok yang tidak tepat, tetapimemset(arr, 0, sizeof arr);
seharusnya berhasil.sizeof arr
harus mengembalikan jumlah byte yang digunakan oleh seluruh array (d0 * d1 * sizeof (int)).sizeof array[0] * m * n
tidak akan memberi Anda ukuran larik yang benar.int array[][10]
, makasizeof(array) == sizeof(int*)
karena ukuran dimensi pertama tidak diketahui. OP tidak menentukan bagaimana array itu diperoleh.Jika
array
benar-benar sebuah larik, maka Anda dapat "memboloskannya" dengan:Tetapi ada dua hal yang harus Anda ketahui:
array
benar-benar merupakan "larik dua-d", yaitu, dideklarasikanT array[M][N];
untuk beberapa tipeT
.array
yang dideklarasikan. Jika Anda meneruskannya ke suatu fungsi, maka nama tersebutarray
meluruh menjadi penunjuk , dansizeof
tidak akan memberi Anda ukuran larik.Mari lakukan percobaan:
Di mesin saya, cetakan di atas:
Meskipun
arr
merupakan sebuah array, ia meluruh ke pointer ke elemen pertamanya saat diteruskanf()
, dan oleh karena itu ukuran yang dicetakf()
adalah "salah". Juga, dalamf()
size ofarr[0]
adalah ukuran dari arrayarr[0]
, yang merupakan "array [5] dariint
". Ini bukan ukuran anint *
, karena "peluruhan" hanya terjadi pada tingkat pertama, dan itulah mengapa kita perlu mendeklarasikanf()
sebagai mengambil pointer ke array dengan ukuran yang benar.Jadi, seperti yang saya katakan, apa yang Anda lakukan awalnya hanya akan berhasil jika kedua kondisi di atas terpenuhi. Jika tidak, Anda perlu melakukan apa yang orang lain katakan:
Akhirnya,
memset()
danfor
loop yang Anda posting tidak setara dalam arti sebenarnya. Mungkin ada (dan telah ada) kompiler di mana "semua bit nol" tidak sama dengan nol untuk jenis tertentu, seperti pointer dan nilai floating-point. Saya ragu Anda perlu mengkhawatirkan hal itu.sumber
memset(array, 0, n*n*sizeof array[0][0]);
Saya kira maksud Andam*n
tidakn*n
benar?memset
bekerja pada tingkat byte (char). Karena1
atau2
tidak memiliki byte yang sama dalam representasi yang mendasarinya, Anda tidak dapat melakukannya denganmemset
.int
di sistem Anda adalah 4 byte" di suatu tempat sebelum contoh kerja minimal, sehingga pembaca dapat dengan mudah menghitung jumlahnya.Nah, cara tercepat untuk melakukannya adalah dengan tidak melakukannya sama sekali.
Kedengarannya aneh, saya tahu, inilah beberapa pseudocode:
Sebenarnya, ini masih membersihkan larik, tetapi hanya jika ada sesuatu yang sedang ditulis ke larik. Ini bukan keuntungan besar di sini. Namun, jika larik 2D diimplementasikan menggunakan, katakanlah, pohon quad (bukan satu pikiran yang dinamis), atau kumpulan baris data, maka Anda dapat melokalkan efek bendera boolean, tetapi Anda memerlukan lebih banyak bendera. Di pohon quad hanya mengatur bendera kosong untuk simpul akar, dalam array baris hanya mengatur bendera untuk setiap baris.
Yang mengarah ke pertanyaan "mengapa Anda ingin berulang kali membidik array 2d besar"? Untuk apa larik itu digunakan? Apakah ada cara untuk mengubah kode sehingga array tidak perlu dibidik?
Misalnya, jika Anda memiliki:
artinya, gunakan untuk buffer akumulasi, kemudian mengubahnya seperti ini akan meningkatkan kinerja tanpa akhir:
Ini tidak memerlukan array untuk dihapus tetapi masih berfungsi. Dan itu akan jauh lebih cepat daripada membersihkan array. Seperti saya katakan, cara tercepat adalah dengan tidak melakukannya sejak awal.
sumber
Jika Anda benar-benar terobsesi dengan kecepatan (dan tidak begitu banyak dengan portabilitas) saya pikir cara tercepat mutlak untuk melakukan ini adalah dengan menggunakan intrinsik vektor SIMD. misalnya pada CPU Intel, Anda dapat menggunakan instruksi SSE2 ini:
Setiap instruksi penyimpanan akan menetapkan empat int 32-bit menjadi nol dalam satu klik.
p harus sejajar 16-byte, tetapi pembatasan ini juga bagus untuk kecepatan karena akan membantu cache. Batasan lainnya adalah bahwa p harus menunjuk ke ukuran alokasi yang merupakan kelipatan 16-byte, tetapi ini juga keren karena memungkinkan kita untuk membuka gulungan dengan mudah.
Lakukan ini dalam satu lingkaran, dan buka gulungannya beberapa kali, dan Anda akan memiliki inisialisasi cepat yang gila:
Ada juga varian
_mm_storeu
yang melewati cache (yaitu memusatkan perhatian pada array tidak akan mencemari cache) yang dapat memberi Anda beberapa keuntungan kinerja sekunder dalam beberapa keadaan.Lihat di sini untuk referensi SSE2: http://msdn.microsoft.com/en-us/library/kcwz153a(v=vs.80).aspx
sumber
Jika Anda menginisialisasi array dengan
malloc
, gunakancalloc
; itu akan nol array Anda secara gratis. (Performa yang sama jelas seperti memset, hanya lebih sedikit kode untuk Anda.)sumber
int array[N][M] = {0};
... setidaknya di GCC 4.8.
sumber
Bagaimana array 2D Anda dideklarasikan?
Jika itu seperti:
Anda dapat membidiknya dengan melakukan:
sumber
memset(a, 0, sizeof(char)*10*10);
berfungsi dengan baik untuk saya. , bagaimana itu bisa terjadi?Gunakan calloc, bukan malloc. calloc akan memulai semua bidang ke 0.
int * a = (int *) calloc (n, ukuran (int));
// semua sel a telah diinisialisasi ke 0
sumber
Saya pikir cara tercepat untuk melakukannya dengan tangan adalah dengan mengikuti kode. Anda dapat membandingkan kecepatannya dengan fungsi memset, tetapi seharusnya tidak lebih lambat.
(ubah tipe pointer ptr dan ptr1 jika tipe array Anda berbeda dengan int)
sumber
memset
jenis karakter.sumber
Anda bisa mencobanya
sumber
Ini terjadi karena sizeof (array) memberi Anda ukuran alokasi objek yang ditunjuk oleh array . ( array hanyalah penunjuk ke baris pertama dari array multidimensi Anda). Namun, Anda mengalokasikan j array dengan ukuran i . Akibatnya, Anda perlu mengalikan ukuran satu baris, yang dikembalikan oleh sizeof (larik) dengan jumlah baris yang Anda alokasikan, misalnya:
Perhatikan juga bahwa sizeof (array) hanya akan berfungsi untuk array yang dialokasikan secara statis. Untuk larik yang dialokasikan secara dinamis, Anda akan menulis
sumber
sizeof
operator,array
bukan pointer (jika dideklarasikan sebagai array). Lihat jawaban saya sebagai contoh.