Λειτουργία malloc() στη βιβλιοθήκη C με EXAMPLE

⚡ Έξυπνη Σύνοψη

Η malloc() στη C δεσμεύει ένα μπλοκ μνήμης στο σωρό κατά τον χρόνο εκτέλεσης και επιστρέφει έναν δείκτη void στο πρώτο byte του, επιτρέποντας στα προγράμματα να ζητήσουν χώρο αποθήκευσης του οποίου το μέγεθος είναι άγνωστο μέχρι να εκτελεστεί ο κώδικας.

  • 🧠 Κατανομή χρόνου εκτέλεσης: Η malloc() δεσμεύει μνήμη κατά την εκτέλεση όταν το απαιτούμενο μέγεθος δεν είναι γνωστό κατά το χρόνο μεταγλώττισης.
  • 📦 Σύνταξη: Ένας δείκτης cast_type λαμβάνει malloc(byte_size), το οποίο συνήθως έχει μέγεθος sizeof για φορητότητα.
  • ⚠️ Έλεγχος NULL: Ένα αποτυχημένο αίτημα επιστρέφει έναν δείκτη NULL, επομένως επικυρώστε το αποτέλεσμα πριν το διαγράψετε από την αναφορά.
  • Αριθμητική δεικτών: Το μπλοκ είναι συνεχόμενο, επομένως χρησιμοποιήστε + αντί για ++ για να προσεγγίσετε στοιχεία πίνακα.
  • 🧹 Απελευθερώστε τη μνήμη: Απελευθερώστε κάθε μπλοκ με free() για να αποτρέψετε διαρροές μνήμης και αιωρούμενους δείκτες.
  • 🤖 Βοήθεια AI: Οι βοηθοί τεχνητής νοημοσύνης και το GitHub Copilot σχεδιάζουν κλήσεις malloc() και επισημαίνουν λείπουσες εντολές free().

Συνάρτηση malloc() σε C

Τι είναι το malloc στο C;

Η συνάρτηση malloc() σημαίνει εκχώρηση μνήμης. Είναι μια συνάρτηση που χρησιμοποιείται για την δυναμική κατανομή ενός μπλοκ μνήμης. Διατηρεί χώρο μνήμης καθορισμένου μεγέθους και επιστρέφει τον μηδενικό δείκτη που δείχνει στη θέση μνήμης. Ο δείκτης που επιστρέφεται είναι συνήθως τύπου void. Σημαίνει ότι μπορούμε να εκχωρήσουμε συνάρτηση malloc σε οποιονδήποτε δείκτη.

Τι είναι το malloc στο C

Σύνταξη

ptr = (cast_type *) malloc (byte_size);

Εδώ,

  • Το ptr είναι δείκτης cast_type.
  • Η συνάρτηση malloc επιστρέφει έναν δείκτη στην εκχωρημένη μνήμη byte_size.
Example: ptr = (int *) malloc (50)

Όταν αυτή η δήλωση εκτελεστεί με επιτυχία, δεσμεύεται ένας χώρος μνήμης 50 byte. Η διεύθυνση του πρώτου byte του δεσμευμένου χώρου εκχωρείται στον δείκτη ptr του τύπου int.

Εξετάστε ένα άλλο παράδειγμα εφαρμογής malloc:

#include <stdlib.h>
int main(){
int *ptr;
ptr = malloc(15 * sizeof(*ptr)); /* a block of 15 integers */
    if (ptr != NULL) {
      *(ptr + 5) = 480; /* assign 480 to sixth integer */
      printf("Value of the 6th integer is %d",*(ptr + 5));
    }
}

Παραγωγή:

Value of the 6th integer is 480

Παρατηρήστε ότι χρησιμοποιήθηκε η συνάρτηση sizeof(*ptr) αντί για την συνάρτηση sizeof(int) προκειμένου να γίνει ο κώδικας πιο αξιόπιστος όταν η δήλωση *ptr τυποποιηθεί σε διαφορετικό τύπο δεδομένων αργότερα.

Η εκχώρηση ενδέχεται να αποτύχει εάν η μνήμη δεν είναι επαρκής. Σε αυτήν την περίπτωση, επιστρέφει έναν δείκτη NULL. Επομένως, θα πρέπει να συμπεριλάβετε κώδικα για να ελέγξετε εάν υπάρχει δείκτης NULL.

Λάβετε υπόψη ότι η εκχωρημένη μνήμη είναι συνεχόμενη και μπορεί να αντιμετωπιστεί ως πίνακας. Μπορούμε να χρησιμοποιήσουμε δείκτης αριθμητική για την πρόσβαση στα στοιχεία του πίνακα αντί για τη χρήση αγκυλών []. Σας συμβουλεύουμε να χρησιμοποιείτε το + για να αναφερθείτε σε στοιχεία του πίνακα, επειδή η χρήση της αύξησης ++ ή += αλλάζει τη διεύθυνση που αποθηκεύεται από τον δείκτη.

Η συνάρτηση Malloc μπορεί επίσης να χρησιμοποιηθεί με τον τύπο δεδομένων χαρακτήρων καθώς και με πολύπλοκους τύπους δεδομένων όπως δομές.

Γιατί να χρησιμοποιήσω malloc() σε C;

Οι στατικοί πίνακες και οι συνηθισμένες μεταβλητές καθορίζουν το μέγεθός τους κατά τη μεταγλώττιση του προγράμματος, κάτι που σπαταλά χώρο όταν η απαίτηση αποδεικνύεται μικρότερη και αποτυγχάνει εντελώς όταν αποδεικνύεται μεγαλύτερη. Η malloc() λύνει αυτό το πρόβλημα ζητώντας μνήμη κατά τον χρόνο εκτέλεσης, έτσι ώστε ένα πρόγραμμα να μπορεί να προσαρμόσει το μέγεθος ενός buffer στην ακριβή ποσότητα δεδομένων που λαμβάνει. Αυτή η ευελιξία κατά τον χρόνο εκτέλεσης είναι η καρδιά του... δυναμική κατανομή μνήμης στο Γ.

Η δυναμική κατανομή με malloc() είναι η σωστή επιλογή σε αρκετές συνηθισμένες περιπτώσεις:

  • Η ποσότητα των δεδομένων εισόδου είναι άγνωστη μέχρι να εκτελεστεί το πρόγραμμα, όπως η ανάγνωση ενός αρχείου ή μιας λίστας που παρέχεται από τον χρήστη.
  • Απαιτούνται μεγάλα μπλοκ που θα υπερχείλιζαν την περιορισμένη στοίβα, καθώς η malloc() αντλεί από τον πολύ μεγαλύτερο σωρό.
  • Τα δεδομένα πρέπει να ζουν περισσότερο από τη συνάρτηση που τα δημιούργησε, επειδή η μνήμη σωρού παραμένει μέχρι να απελευθερωθούν ρητά.
  • Οι δομές και οι πίνακες πρέπει να αυξάνονται ή να συρρικνώνονται κατά την εκτέλεση του προγράμματος.

Επειδή το δεσμευμένο μπλοκ επιστρέφεται ως δείκτης, μπορεί να μεταβιβαστεί μεταξύ συναρτήσεων φθηνά χωρίς να αντιγραφούν τα υποκείμενα δεδομένα.

Πώς να ελευθερώσετε μνήμη που έχει διατεθεί από το malloc()

Η μνήμη που δεσμεύεται από την malloc() βρίσκεται στο σωρό και δεν απελευθερώνεται ποτέ αυτόματα. Όταν ένα πρόγραμμα συνεχίζει να εκχωρεί χωρίς να απελευθερώνει, καταναλώνει αργά όλη τη διαθέσιμη μνήμη, ένα ελάττωμα γνωστό ως διαρροή μνήμης. Η συνάρτηση free() επιστρέφει ένα ολοκληρωμένο μπλοκ στο σύστημα, ώστε ο χώρος να μπορεί να επαναχρησιμοποιηθεί.

Η συνάρτηση free() δέχεται ένα μόνο όρισμα, τον δείκτη που επέστρεψε η malloc(), και απελευθερώνει ολόκληρο το μπλοκ ταυτόχρονα:

int *ptr;
ptr = malloc(10 * sizeof(int));
if (ptr != NULL) {
    /* use the allocated memory here */
    free(ptr);   /* release the block */
    ptr = NULL;  /* avoid a dangling pointer */
}

Ακολουθήστε αυτούς τους κανόνες για να διαχειριστείτε με ασφάλεια τη δυναμική μνήμη:

  • Καλέστε τη free() ακριβώς μία φορά για κάθε επιτυχημένη malloc(). Η απελευθέρωση του ίδιου μπλοκ δύο φορές προκαλεί απροσδιόριστη συμπεριφορά.
  • Ορίστε τον δείκτη σε NULL μετά την απελευθέρωση, ώστε να μην μπορεί να επαναχρησιμοποιηθεί ως κρεμαστός δείκτης.
  • Ποτέ δεν free() ένας δείκτης που δεν επέστρεψε η malloc(), συμπεριλαμβανομένου ενός δείκτη που μετατοπίστηκε κατά αριθμητική ένδειξη.
  • Αντιστοιχίστε κάθε κατανομή με μια αντίστοιχη έκδοση πριν ο δείκτης βγει εκτός εμβέλειας.

Keeping Η κατανομή και η απελευθέρωση σε ισορροπία είναι ο βασικός κλάδος της χειροκίνητης διαχείρισης μνήμης στη C και αποτρέπει τόσο τις διαρροές όσο και τα σφάλματα που προκαλούνται από την επαναχρησιμοποίηση της απελευθερωμένης μνήμης.

malloc() vs calloc(): Βασικές διαφορές

malloc() και calloc() Και οι δύο διατηρούν μνήμη σωρού, αλλά διαφέρουν στα ορίσματά τους και στον τρόπο που χειρίζονται το νέο μπλοκ. Η malloc() δέχεται ένα όρισμα, τον συνολικό αριθμό bytes, και αφήνει τα περιεχόμενα χωρίς αρχικοποίηση, επομένως το μπλοκ διατηρεί απρόβλεπτες τιμές άχρηστων στοιχείων μέχρι το πρόγραμμα να γράψει σε αυτό. Η calloc() δέχεται δύο ορίσματα, τον αριθμό των στοιχείων και το μέγεθος του καθενός, και μηδενίζει κάθε byte πριν επιστρέψει τον δείκτη.

Οι πρακτικές διαφορές συνοψίζονται σε τρία σημεία:

  • Αρχικοποίηση: η calloc() μηδενίζει τη μνήμη, ενώ η malloc() όχι, γεγονός που καθιστά την malloc() ελαφρώς ταχύτερη όταν οι τιμές θα αντικατασταθούν ούτως ή άλλως.
  • Ορίσματα: γράφετε malloc(n * size) αλλά calloc(n, size) για να δεσμεύσετε τον ίδιο πίνακα.
  • Περίπτωση χρήσης: επιλέξτε calloc() όταν έχει σημασία ένα καθαρό, μηδενισμένο μπλοκ και malloc() όταν προτιμάται η ταχύτητα και η αρχικοποίηση γίνεται χειροκίνητα.

Και οι δύο συναρτήσεις δηλώνονται στο stdlib.h, και οι δύο επιστρέφουν έναν δείκτη void ή NULL σε περίπτωση αποτυχίας και και οι δύο επιστρέφουν τη μνήμη τους με την ίδια συνάρτηση free().

Συχνές Ερωτήσεις

Στη C, η μετατροπή είναι προαιρετική και συχνά αποθαρρύνεται, επειδή το void* μετατρέπεται αυτόματα σε οποιονδήποτε δείκτη αντικειμένου και ένα explicit cast μπορεί να καλύψει ένα stdlib.h include που λείπει. C++, ωστόσο, το καστ είναι απαραίτητο.

Μια επιστροφή NULL σημαίνει ότι το αίτημα απέτυχε, συνήθως λόγω ανεπαρκούς μνήμης. Ελέγχετε πάντα τον δείκτη πριν τον χρησιμοποιήσετε, επειδή η κατάργηση της αναφοράς NULL οδηγεί σε απροσδιόριστη συμπεριφορά και συνήθως διακόπτει τη λειτουργία του προγράμματος.

Η realloc() αλλάζει το μέγεθος ενός μπλοκ που είχε προηγουμένως κρατηθεί από την malloc(), keeping υπάρχοντα δεδομένα μέχρι το μικρότερο μέγεθος. Εάν αποτύχει, επιστρέφει NULL και αφήνει το αρχικό μπλοκ άθικτο, επομένως αντιστοιχίστε πρώτα το αποτέλεσμά του σε έναν προσωρινό δείκτη.

Μια διαρροή μνήμης συμβαίνει όταν η μνήμη heap από το malloc() δεν απελευθερώνεται ποτέ με την free(). Το πρόγραμμα συνεχίζει να δεσμεύει χώρο που δεν χρησιμοποιεί πλέον, γεγονός που μπορεί σταδιακά να εξαντλήσει τη μνήμη που είναι διαθέσιμη σε αυτό.

Η malloc() δεσμεύει μνήμη στο σωρό, όχι στη στοίβα. Τα μπλοκ σωρού παραμένουν έγκυρα μέχρι να καλέσετε τη free(), επομένως μπορούν να επιβιώσουν από τη συνάρτηση που τα δημιούργησε, σε αντίθεση με τις αυτόματες μεταβλητές στοίβας που εξαφανίζονται κατά την επιστροφή.

Η malloc() είναι μια συνάρτηση βιβλιοθήκης που επιστρέφει void* και χρειάζεται το sizeof για να υπολογίσει τα bytes. C++ Το new είναι ένας τελεστής που επιστρέφει έναν πληκτρολογημένο δείκτη και καλεί κατασκευαστές. Συνδυάστε την malloc() με την free() και την new με την delete.

Ναι. Οι βοηθοί κωδικοποίησης τεχνητής νοημοσύνης σχεδιάζουν κλήσεις malloc(), εισάγουν ελέγχους NULL και επισημαίνουν ελλείπουσες κλήσεις free() ή διαρροές, και μπορούν να εξηγήσουν την αριθμητική δεικτών. Πάντα να μεταγλωττίζετε και να δοκιμάζετε τον παραγόμενο κώδικα πριν τον εμπιστευτείτε.

GitHub Copilot προτείνει malloc(), sizeof() και αντίστοιχες γραμμές free() από ένα σχόλιο που περιγράφει την πρόθεσή σας. RevΕξετάστε κάθε πρόταση για ελλείποντες ελέγχους NULL και διαρροές πριν από τη μεταγλώττιση.

Συνοψίστε αυτήν την ανάρτηση με: