Saya menulis program C yang menerima integer input dari pengguna, yang digunakan sebagai ukuran dari sebuah array integer, dan menggunakan nilai yang menyatakan sebuah array dari ukuran tertentu, dan saya mengkonfirmasikan hal itu dengan memeriksa ukuran dari array.
Kode:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int n;
scanf("%d",&n);
int k[n];
printf("%ld",sizeof(k));
return 0;
}
dan ternyata benar! Program ini dapat membuat array dari ukuran yang dibutuhkan.
Tapi semua statis alokasi memori dilakukan pada waktu kompilasi, dan selama waktu kompilasi nilai n
tidak dikenal, jadi bagaimana compiler dapat mengalokasikan memori dari ukuran yang dibutuhkan?
Jika kita dapat mengalokasikan memori yang dibutuhkan hanya seperti itu maka apa penggunaan alokasi dinamis menggunakan malloc()
dan calloc()
?
Ini bukan "statis alokasi memori". Array k
adalah Variable Length Array (VLA), yang berarti bahwa memori untuk array ini dialokasikan pada jangka waktu. Ukuran akan ditentukan oleh run-time nilai n
.
Bahasa spesifikasi tidak mendikte setiap alokasi khusus mekanisme, tetapi secara khas implementasi anda k
biasanya akan berakhir menjadi sederhana int *
pointer dengan aktual blok memori yang dialokasikan pada stack pada saat dijalankan.
Untuk VLA sizeof
operator dievaluasi pada saat run time juga, yang mengapa anda mendapatkan nilai yang benar dari dalam eksperimen anda. Hanya menggunakan %zu
(bukan %ld
) untuk mencetak nilai-nilai dari tipe size_t
.
Tujuan utama dari malloc
(dan alokasi memori dinamis fungsi) adalah untuk menimpa lingkup berbasis seumur hidup aturan yang berlaku untuk objek lokal. I. e. memori yang dialokasikan dengan malloc
tetap dialokasikan "selamanya", atau sampai anda secara eksplisit deallocate dengan gratis
. Memori yang dialokasikan dengan malloc
tidak bisa secara otomatis deallocated pada akhir blok.
VLA, seperti dalam contoh anda, tidak memberikan "ruang lingkup-mengalahkan" fungsi. Array k
masih mematuhi biasa lingkup berbasis aturan seumur hidup: seumur hidup berakhir di akhir blok. Untuk alasan ini, dalam kasus umum, VLA tidak mungkin menggantikan malloc
dan alokasi memori dinamis fungsi.
Tetapi dalam kasus-kasus tertentu ketika anda don't perlu "mengalahkan lingkup" dan hanya menggunakan malloc
untuk mengalokasikan run-time berukuran array, VLA mungkin memang dapat dilihat sebagai pengganti untuk malloc
. Hanya perlu diingat, sekali lagi, bahwa VLAs biasanya dialokasikan pada stack dan mengalokasikan potongan besar dari memori pada stack sampai hari ini masih agak dipertanyakan pemrograman praktek.
Dalam C, cara-cara yang compiler mendukung VLAs (panjang variabel array) adalah sampai dengan compiler - itu doesn't harus menggunakan malloc()
, dan dapat (dan sering) menggunakan apa yang kadang-kadang disebut "stack" memori - misalnya menggunakan sistem fungsi-fungsi spesifik seperti alloca()
yang bukan merupakan bagian dari standar C. Jika tidak menggunakan stack, ukuran maksimum dari sebuah array ini biasanya jauh lebih kecil daripada yang mungkin menggunakan malloc()
, karena sistem operasi modern memungkinkan program-program yang jauh lebih kecil kuota stack memory.
Memori untuk variabel panjang array jelas dapat't menjadi statis dialokasikan. Namun dapat dialokasikan pada stack. Umumnya ini melibatkan penggunaan "frame pointer" untuk melacak lokasi dari fungsi stack frame di wajah dynamicly ditentukan perubahan ke stack pointer.
Ketika saya mencoba untuk mengkompilasi program anda tampaknya bahwa apa yang sebenarnya terjadi adalah bahwa variabel array dengan panjang punya dioptimalkan keluar. Jadi saya modifikasi kode untuk memaksa compiler untuk benar-benar mengalokasikan array.
#include <stdio.h>
int main(int argc, char const *argv[])
{
int n;
scanf("%d",&n);
int k[n];
printf("%s %ld",k,sizeof(k));
return 0;
}
Godbolt kompilasi untuk arm menggunakan gcc 6.3 (menggunakan lengan karena aku dapat membaca lengan ASM) yang mengkompilasi ini untuk https://godbolt.org/g/5ZnHfa. (komentar saya)
main:
push {fp, lr} ; Save fp and lr on the stack
add fp, sp, #4 ; Create a "frame pointer" so we know where
; our stack frame is even after applying a
; dynamic offset to the stack pointer.
sub sp, sp, #8 ; allocate 8 bytes on the stack (8 rather
; than 4 due to ABI alignment
; requirements)
sub r1, fp, #8 ; load r1 with a pointer to n
ldr r0, .L3 ; load pointer to format string for scanf
; into r0
bl scanf ; call scanf (arguments in r0 and r1)
ldr r2, [fp, #-8] ; load r2 with value of n
ldr r0, .L3+4 ; load pointer to format string for printf
; into r0
lsl r2, r2, #2 ; multiply n by 4
add r3, r2, #10 ; add 10 to n*4 (not sure why it used 10,
; 7 would seem sufficient)
bic r3, r3, #7 ; and clear the low bits so it is a
; multiple of 8 (stack alignment again)
sub sp, sp, r3 ; actually allocate the dynamic array on
; the stack
mov r1, sp ; store a pointer to the dynamic size array
; in r1
bl printf ; call printf (arguments in r0, r1 and r2)
mov r0, #0 ; set r0 to 0
sub sp, fp, #4 ; use the frame pointer to restore the
; stack pointer
pop {fp, lr} ; restore fp and lr
bx lr ; return to the caller (return value in r0)
.L3:
.word .LC0
.word .LC1
.LC0:
.ascii "%d\000"
.LC1:
.ascii "%s %ld\000"
Memori untuk membangun ini, yang disebut "variabel array dengan panjang", VLA, dialokasikan pada stack, dalam cara yang mirip dengan alokasi
. Persis bagaimana hal ini terjadi tergantung pada apa yang kompiler anda're menggunakan, tapi pada dasarnya itu's kasus menghitung ukuran ketika hal ini diketahui, dan kemudian mengurangkan [1] ukuran total dari stack pointer.
Anda tidak perlu malloc
dan teman-teman karena ini alokasi "mati" ketika anda meninggalkan fungsi. [Dan itu's tidak berlaku dalam standar C++]
[1] khas Untuk prosesor yang menggunakan stack bahwa "tumbuh menuju nol".
Ketika dikatakan bahwa compiler mengalokasikan memori untuk variabel compile time, itu berarti bahwa penempatan variabel tersebut sudah diputuskan dan tertanam dalam eksekusi kode yang compiler menghasilkan, tidak bahwa compiler membuat ruang bagi mereka yang tersedia saat bekerja. Sebenarnya alokasi memori dinamis dilakukan oleh dihasilkan program yang saat ini berjalan.