cara membebaskan struct di c


Jawaban 1:

Saat Anda memanggil malloc untuk mengalokasikan sebagian memori secara dinamis, Anda menentukan jumlah byte yang tepat yang Anda perlukan dalam blok memori. Fungsi malloc sama sekali tidak tahu apa-apa tentang tipe data dari apa yang Anda alokasikan. Itu hanya mengetahui jumlah mentah byte yang Anda minta.

Jadi, jika Anda memiliki definisi struct (kami akan menamakannya A) yang berisi anggota yang tipe datanya adalah struct lain (kami akan menamakannya B), dan Anda menggunakan sizeof operator untuk mendapatkan jumlah byte yang ditempati oleh struct tipe A, ukuran anggota B akan dimasukkan dalam ukuran total yang dilaporkan untuk A.

Pertimbangkan hal berikut:

struct A { int someInfo1; int someInfo2; struct B { int someInfo5; int someInfo6;} someMoreInfo; // sebuah struct B int someInfo3; int someInfo4;};

Ekspresi (sizeof (struct A)) akan menjadi jumlah total byte dalam instance A, yang mencakup anggota someInfo1, someInfo2, someInfo3, dan someInfo4, serta ukuran anggota someMoreInfo, yang merupakan ukuran struct B.

Untuk membuat instance struct A, Anda akan mengatakan:

struct A * pMyA;pMyA = malloc (sizeof (struct A));// periksa keberhasilan, dan init semua anggota

Dalam contoh ini, blok memori memiliki ruang untuk semua anggota struct A, termasuk struct B someMoreInfo, yang disematkan dalam instance struct A.

Ada satu dan hanya satu alokasi yang terjadi di sini. Anda mengalokasikan satu blok memori, memberi tahu malloc ukuran total dari satu blok yang Anda butuhkan. Ukuran blok itu adalah jumlah byte dalam instance struct A, dan ukuran itu termasuk ukuran someMoreInfo (a struct B), bersama dengan ukuran semua anggota struct A lainnya, serta padding apa pun yang ditambahkan oleh kompiler (jika ada).

Sekali lagi, malloc sama sekali tidak tahu apa yang Anda alokasikan. Itu melihat permintaan Anda untuk sepotong memori dengan ukuran tertentu, jadi Anda bertanggung jawab untuk mendapatkan ukuran total yang benar.

Tidak ada anggota struktur yang telah diinisialisasi, jadi Anda bertanggung jawab untuk menginisialisasi semua anggota, termasuk anggota struktur bertingkat.

Sekarang, jika struct A Anda berisi pointer ke struct B, dan Anda ingin pointer itu mengarah ke instance struct B yang sebenarnya, terserah Anda untuk melakukan alokasi terpisah dari instance struct B dan menyimpan pointer ke dalam anggota struct A. Contoh:

struct A { int someInfo1; int someInfo2; struct B { int someInfo5; int someInfo6;} * pSomeMoreInfo; // pointer, bukan struct B int someInfo3; int someInfo4;};

Dalam kasus ini, Anda harus melakukan hal berikut:

struct A * pMyA;pMyA = malloc (sizeof (struct A));// periksa kesuksesanpMyA-> pSomeMoreInfo = malloc (sizeof (struct B));// periksa keberhasilan, dan init semua anggota yang tersisa

Tidak ada anggota struktur yang telah diinisialisasi, jadi Anda bertanggung jawab untuk menginisialisasi semua anggota, termasuk anggota struktur yang ditunjuk oleh anggota pSomeMoreInfo.

Juga, perlu diingat bahwa dalam skenario kedua ini, ketika Anda selesai dengan struktur Anda, Anda perlu membebaskan struktur yang ditunjukkan oleh anggota pSomeMoreInfo, dan kemudian membebaskan struktur yang ditunjuk oleh pMyA. Urutan penting di sini. Jika Anda membebaskan pMYA sebelum membebaskan pMyA-> pSomeMoreInfo, Anda berisiko merusak heap.

Perhatikan bahwa saya meninggalkan detail pemeriksaan kesalahan yang perlu Anda lakukan pada semua panggilan ke malloc.


Jawaban 2:

Dengan struct bersarang di C, ketika Anda malloc struktur luar, apakah itu otomatis malloc struct dalam?

Seseorang tidak dan tidak bisa "malloc a struct" di C. Satu mallocs satu blok memori, dan memperlakukan blok memori itu sebagai sebuah struct. Fungsi malloc (…) mengembalikan pointer ke bagian memori yang tidak diketik di heap. Memori bukanlah "struct," itu hanya memori sampai Anda mengetik-paksa pointer yang dikembalikan.

Anda tidak perlu mengalokasikan struct on-heap sama sekali di C. Anda dapat dan harus mengalokasikan struct on-stack jika memungkinkan, karena memori heap dinamis sering kali cukup mahal dan menyisakan ruang untuk kebocoran memori.

Anda juga tidak pernah mengalokasikan struct bertingkat di C. Struct bersarang SELALU dialokasikan dengan struct yang menyusunnya. Apa yang mungkin perlu dialokasikan secara independen bukanlah struct bersarang, melainkan sebuah struct yang direferensikan melalui pointer yang bersarang di dalam objek lain.

typedef struct { data int;} Node_t;typedef struct {Node_t composeStruct; // struct ini bersarang dan // dialokasikan di blok yang sama dengan // ComposerOne_t di dalamnya // terdiri dari } ComposerOne_t;typedef struct {Node_t * composePtr; // Ini BUKAN struct "bersarang" // Ini adalah pointer "bersarang" dalam sebuah struct // Pointer tidak akan menunjuk ke sesuatu yang berarti sampai itu diikat dengan alamat dari sebuah objek Node_t} ComposerTwo_t;ComposerOne_t * ConstructObj1 (int data) { / * TIDAK membutuhkan malloc tambahan * / / * Node_t ada dalam blok yang sama dengan objek ComposerOne_t * / ComposerOne_t * rv = (ComposerOne_t *) malloc ( sizeof (ComposerOne_t) ); rv-> composeStruct.data = data; kembali rv;}ComposerTwo_t * ConstructObj2 (int data) { / * APAKAH membutuhkan malloc tambahan * / / * Node_t TIDAK ada dalam blok yang sama dengan objek ComposerTwo_t * / ComposerTwo_t * rv = (ComposerTwo_t *) malloc ( sizeof (ComposerTwo_t) ); rv-> composePtr = (Node_t *) malloc ( sizeof (Node_t) ); rv-> composePtr-> data = data; kembali rv;}

Jawaban 3:

Selama struct dalam didefinisikan dengan elemen statis, ya.

struct luar{ min lama; maks panjang; struct batin { size_t size; data panjang [100]; } };/ * secara statis mengalokasikan semuanya * /struct luar minmax; / * secara dinamis mengalokasikan semuanya * /struct luar * op = calloc (1, sizeof (struct luar));gratis (op); / * membebaskan semuanya * /

C sebenarnya tidak terlalu peduli tentang struct bersarang seperti itu, ia mengalokasikan rentang byte yang berdekatan. Sistem tipe dalam kompilator melakukan pemeriksaan paling sederhana bahwa akses tipe kompatibel untuk pembacaan dan / atau penugasan dan parameter. Beberapa padding mungkin terjadi untuk memastikan item di struct mendarat pada batas byte yang merupakan kelipatan dari ukuran kata data sistem, karena jauh lebih mudah untuk memuat struktur seperti itu ke cache CPU dan alokasi dengan malloc berada pada batas tersebut. Ini sebagian besar transparan dan tidak dilihat oleh pembaca sumber. Ini mungkin penting jika struktur sedang dibaca atau ditulis ke disk, jadi ukuran operator mungkin diperlukan untuk memastikan, tetapi struktur membaca dan menulis internal memperhitungkan padding dan dapat diabaikan. C melakukan matematika byte tingkat rendah untuk Anda untuk sebagian besar.

Sebenarnya Anda dapat memaksa wilayah memori apa pun yang cukup besar untuk menampung struct ke dalam struct itu. Jika memori tidak cukup besar, Anda mungkin masih memaksa memori ke dalam struct, tetapi Anda dapat menimpa memori di luar batas struct dan menyebabkan semua jenis malapetaka dengan data dan crash, dll.

Sebuah struct dalam bisa secara dinamis disediakan secara terpisah jika itu diadakan sebagai pointer-to-struct di luar struct, tapi kemudian rasa sakit harus diambil untuk membebaskan struktur dalam dengan sendirinya, karena memori tidak akan bersebelahan. BAHAYA!


Daftar Tertaut Ini sering terjadi dengan wadah daftar tertaut untuk struct. Node daftar tertaut mungkin bukan struktur data, tetapi hanya pemegang penunjuk ke struktur data. Ini biasanya dibuat secara dinamis saat data masuk dari aliran atau sumber, sehingga setiap struct dan node daftar tertaut yang memuatnya harus dialokasikan secara real time.

struct typedef { int a; int b; int c; int d;}Data;typedef struct _Node { Data * data; struct _Node * selanjutnya; } Node; Data * newData (int a, int b, int c, int d){ Data * dt = calloc (1, sizeof (Data));if (! dt) return NULL; / * bisa gagal * / d-> a = a; d-> b = b; d-> c = c; d-> d = d; kembali dt;}Node * newNode (Data * d){ if (! d) return NULL; Node * n = calloc (1, sizeof (Node)); if (! n) return NULL; n-> data = d; n-> berikutnya = NULL; kembali n;}batal freeNode (Node * n){ if (! n) return; gratis (n-> data); gratis (n);}batal freeList (Node * n){ Node * tmp = n; sementara (tmp) { Node * x = tmp-> berikutnya; freeNode (tmp); tmp = x; }}Node * n = newNode (newData (1,2,3,4));Node * n2 = newNode (newData (3,4,5,7));Node * n3 = newNode (newData (8,9,20, 33));n-> selanjutnya = n2;n2-> selanjutnya = n3;...freeList (n);

Anda perlu menulis fungsi untuk membebaskan memori yang membebaskan struct data dan kemudian node daftar tertaut dengan benar.


Array Array

Array dinamis dari array sering kali dilakukan dengan cara ini. Sebuah array bukanlah tipe selengkap sebuah struct, karena Anda tidak dapat menetapkan array, tidak dapat menyalinnya, tidak ada dukungan untuk operasi tingkat array. Semua operasi selain alokasi dan pembebasan berlangsung di tingkat elemen. Sebuah array bahkan tidak memiliki informasi panjang, itu sebenarnya hanya sebuah rentang memori yang berdekatan (sekali lagi).

Array pointers-to-type dapat menampung alamat dari sebuah array-of-type di setiap elemen, sehingga membentuk struktur komposit yang menampung array dengan panjang yang berbeda-beda, seperti array string. Contoh paling umum dari ini ada di fungsi utama:

int main (int argc, char ** argv, char ** env){...}

argv adalah larik string, yang diketahui oleh mesin dasar dari program yang dikompilasi untuk memuat argumen baris perintah ke dalamnya, masing-masing sebagai larik karakter dengan NULCHAR ('\ 0') yang tepat di bagian akhir. argc adalah jumlah argumen baris perintah yang dipindai dengan spasi sebagai pemisah, karena argv tidak memiliki info ukuran.

argc adalah jumlah argumen, termasuk nama program.

argv [0]

adalah nama program argv [1] - argv [argc-1] adalah argumen string.

argv adalah karakter **, pointer-to-pointer-to-char. Artinya, sebenarnya argv adalah larik dari char *. Setiap elemen argv adalah alamat dari larik karakter, awal dari sebuah string. Kadang-kadang Anda mungkin melihatnya ditulis sebagai char * argv [], yang sedikit lebih jelas untuk maksud, tetapi memiliki arti yang persis sama bagi kompiler.

argv sudah dialokasikan sepenuhnya, dan juga hanya-baca. Tetapi struktur serupa sering digunakan untuk mengumpulkan input string, dan biasanya dialokasikan secara dinamis.

Sebuah array dari char * (char **) dialokasikan dengan spasi untuk N char *. Perhatikan bahwa alokasi awal hanya untuk penunjuk karakter (masing-masing 8 byte), bukan untuk karakter sebenarnya (masing-masing 1 byte) yang disimpan. Memori untuk setiap string harus dialokasikan sebagai alokasi terpisah.

Setiap string yang dibaca dari input pengguna dibaca menjadi buffer statis terlebih dahulu, yang akan digunakan kembali. Kemudian string tersebut disalin menjadi string yang dialokasikan secara dinamis dan alamatnya ditempatkan di string array.

baris karakter [80]; / * penyangga * /char ** input = calloc (10, sizeof (char *));size_t i, clen, slen, numstrings;char * tmp;untuk (i = 0 i <10; i ++) { tmp = NULL; clen = scanf ("% s", baris); jika (clen == 0) putus; slen = strlen (garis) +1; tmp = calloc (slen, sizeof (char)); jika (tmp) { strncpy (tmp, baris, slen); masukan [i] = tmp; } lain istirahat; }jumlah string = i;...untuk (i = angka, i> = 0; i--) { gratis (masukan [i]); }gratis (masukan);

Setiap string dalam larik harus dibebaskan secara terpisah (biasanya dalam urutan pembuatan terbalik) dan kemudian larik penunjuk harus dibebaskan.


Jawaban 4:

Di C, seseorang tidak "malloc a struct". Artinya, pilihan berapa banyak memori yang akan dialokasikan tidak dibuat secara otomatis. malloc mengambil argumen integer dalam byte untuk berapa banyak memori yang akan dialokasikan, dan mengembalikan pointer void *.

Ini adalah tanggung jawab programmer untuk mengalokasikan jumlah ruang yang benar dan juga tanggung jawab programmer untuk memberikan nilai kembali malloc ke tipe penunjuk yang diinginkan. Jadi seseorang dapat menulis:

struct Besar { int somestuff; struct Kecil ( int someotherstuff; } kecil; };struct Big * bigpointer;batal beberapa fungsi (){ bigpointer = (struct Besar *) malloc (sizeof (struct Besar)); menegaskan (bigpointer! = NULL);}

Dalam hal ini kami telah meminta malloc untuk mengalokasikan cukup ruang untuk menampung struct Big dan memasukkan nilai kembaliannya ke struct Big *.

Fungsi bawaan sizeof () melakukan keajaiban di sini, tetapi Anda harus memasukkannya. Ini akan mengembalikan jumlah byte yang dibutuhkan untuk struct Big, dan jumlah itu akan mencakup ukuran semua bidang, termasuk yang dari struct Small.

Jika struct Big berisi bidang yang merupakan penunjuk ke struct, maka malloc akan mengalokasikan ruang untuk bidang yang merupakan penunjuk, tetapi tidak akan menginisialisasinya juga tidak akan malloc mengalokasikan ruang untuk hal yang ditunjukkan oleh bidang yang merupakan penunjuk .


Jawaban 5:

Dengan struct bersarang di C, ketika Anda malloc struktur luar, apakah itu otomatis malloc struct dalam?

Ini mengalokasikan jumlah memori yang dibutuhkan untuk struktur yang diberikan.

Jika struktur itu termasuk struktur lain tentunya harus mengalokasikannya.

Ini tidak berbeda dengan mengalokasikan struct yang berisi bilangan bulat pendek dan ganda.

Struktur hanyalah tipe yang ditentukan pengguna. Jadi ukuran setiap struktur dihitung dengan menjumlahkan ukuran semua jenis (serta setiap padding pelurusan yang diperlukan untuk berbagai jenis).


Jawaban 6:

Ya, selama struct benar-benar bersarang, yaitu struct bagian dalam bukanlah penunjuk ke sebuah struct.

Jika ini adalah penunjuk ke struct, Anda harus malloc sendiri.