[Powered by Google Translate] Ας μιλήσουμε για structs. Structs μας παρέχει έναν τρόπο για να συγκεντρώσει ένα μάτσο μεταβλητές μαζί σε ένα ωραίο πακέτο. Είναι ίσως πιο εύκολο να δούμε ένα παράδειγμα αμέσως, έτσι λέμε struct, τότε το άνοιγμα άγκιστρο, και σε αυτό το struct, θα έχουμε έναν int ηλικία, ένα char * name, και αυτό είναι αυτό. Μπορεί να φαίνεται παράξενο με ένα ερωτηματικό μετά από ένα στήριγμα σγουρά, αλλά είναι στην πραγματικότητα αναγκαία structs. Οποιαδήποτε έγκυρη τύπος μπορεί να πάει στον ορισμό struct. Εδώ, έχουμε χρησιμοποιήσει μια int και char *, αλλά μπορείτε επίσης να χρησιμοποιήσετε μια σειρά, ας πούμε, 100 στοιχεία ή ακόμα και ένα άλλο struct. Όταν χρησιμοποιείτε structs σε C, είστε δημιουργία νέων τύπων από μια συλλογή των άλλων τύπων. Εδώ, κάνουμε ένα νέο τύπο από έναν ακέραιο και ένα char *. Όπως θα δούμε αργότερα, ένας τύπος struct είναι σε πολλούς τρόπους που ισοδυναμεί με οποιονδήποτε άλλο τύπο που έχετε συνηθίσει. Συνήθως, θα πρέπει να συγκρίνει τον τρόπο με έναν τύπο struct είναι παρόμοιο με ένα ακέραιο τύπο. Ενώ ο κώδικας που γράψαμε είναι έγκυρη C, δεν είναι πολύ χρήσιμο, κλαγγή και θα μας δώσει μια προειδοποίηση. Θυμηθείτε πώς και structs του είναι παρόμοια; Λοιπόν, βασικά ακριβώς είπε int, η οποία δεν είναι μια πολύ χρήσιμη γραμμή. Ας δηλώσει στην πραγματικότητα μια μεταβλητή αυτού του τύπου δίνοντας ένα όνομα πριν το ελληνικό ερωτηματικό. Θα καλέσετε τη μεταβλητή μαθητή. Τώρα έχουμε δηλώσει μια μεταβλητή που ονομάζεται φοιτητής με τον τύπο δίδεται από τον struct. Πώς θα φτάσουμε στις μεταβλητές μέσα στο struct; Τεχνικά, τα ονόματα για αυτές τις μεταβλητές είναι μέλη. Για την πρόσβαση σε οποιοδήποτε συγκεκριμένο μέλος σε ένα struct μαθητή, την προσάρτηση μια τελεία στο όνομα της μεταβλητής, ακολουθούμενο από το όνομα του μέλους που θέλετε. Μέχρι εδώ, τα έγκυρα μόνο 2 δυνατότητες είναι student.age και student.name. Και μπορούμε να κάνουμε κάτι σαν student.age = 12 και student.name = μαθητή. Τώρα τι γίνεται αν θέλουμε να κάνουμε ένα δεύτερο μαθητή; Μπορείτε να σκεφτείτε να αντιγράψετε και να επικολλήσετε αυτές τις γραμμές και να αλλάξετε μαθητή σε μαθητή 2 ή κάτι, και ότι θα λειτουργήσει, αλλά τεχνικά, φοιτητών και σπουδαστών 2 δεν έχουν τον ίδιο τύπο. Δείτε, δεν θα είστε σε θέση να τους τοποθετεί σε ένα από το άλλο. Αυτό συμβαίνει επειδή, μέχρι στιγμής, struct σας ήταν ανώνυμο. Πρέπει να δώσετε ένα όνομα. Για να το κάνετε αυτό, εισάγετε το όνομα του struct μετά τη λέξη struct. φοιτητής, ακολουθούμενο από τον ορισμό. Μπορούμε ακόμη να δηλώσει αμέσως μια μεταβλητή του τύπου struct φοιτητής, όπως κάναμε πριν. Θα το ονομάσουμε S1 Δίνοντας το struct ένα όνομα, μπορούμε να χρησιμοποιήσουμε τώρα φοιτητής struct με σχεδόν τον ίδιο ακριβώς τρόπο που θα χρησιμοποιήσει int. Έτσι, μπορούμε να δηλώσουμε μια μεταβλητή τύπου struct μαθητή, σαν struct φοιτητής S2. Όπως και συστοιχίες, structs παρέχουν μια σύνταξη προετοιμασίας συντόμευσης, έτσι μπορούμε να πούμε, struct φοιτητής S2 ισούται αριστερό άγκιστρο 3, S2. Εδώ, S2.age θα είναι 3, S2.name και θα επισημάνει στο S2. Σκεφτείτε όλα τα πράγματα που μπορείτε να κάνετε με ένα τύπου int και τα περισσότερα από αυτά που μπορείτε να κάνετε με έναν τύπο φοιτητή struct. Μπορούμε να χρησιμοποιήσουμε έναν σπουδαστή struct ως ένα είδος μιας παραμέτρου λειτουργίας. Μπορούμε να χρησιμοποιήσουμε φοιτητής struct μέσα από ένα νέο struct. Μπορούμε να έχουμε ένα δείκτη σε struct μαθητή. Μπορούμε να κάνουμε το μέγεθος του σπουδαστή struct. Struct φοιτητής είναι ένας τύπος ακριβώς όπως int είναι ένας τύπος. Μπορούμε επίσης να εκχωρήσετε το S1 στο S2 δεδομένου ότι και οι δύο είναι του ίδιου τύπου, ώστε να μπορούμε να κάνουμε S1 = S2. Τι θα συμβεί αν κάνουμε S1.age = 10; Μήπως S2 αλλαγή σε όλα; Και πάλι, σκεφτείτε τα structs όπως ακριβώς τακτική ακέραιοι. Αν αντιστοιχίσετε κάποια int X Y σε κάποιο int, όπως Χ = Υ και στη συνέχεια, αλλάξτε το Χ, όπως στο Χ + +, Υ έχει αλλάξει καθόλου; Υ δεν αλλάζει εδώ, και έτσι ούτε και S2 παραπάνω. S2.age εξακολουθεί να είναι 3. Αλλά σημειώστε ότι κατά την ανάθεση ενός struct στο άλλο, όλοι οι δείκτες εξακολουθούν να δείχνουν το ίδιο πράγμα, δεδομένου ότι μόλις αντιγράψατε. Αν δεν θέλετε οι δείκτες να μοιραστούν, θα πρέπει να χειριστεί το χέρι ότι, ίσως με malicking ένα μπλοκ μνήμης για έναν από τους δείκτες για να υποδεικνύουν και την αντιγραφή των δεδομένων πάνω. Θα μπορούσε να είναι ενοχλητικό να πρέπει να γράψετε φοιτητής struct παντού. Χρησιμοποιώντας ένα def τύπου, μπορούμε να κάνουμε τύπου def struct και θα καλέσουμε το μαθητή. Τώρα, μπορούμε να χρησιμοποιήσουμε φοιτητής παντού που χρησιμοποιείται για να χρησιμοποιήσει φοιτητής struct. Αυτό def τύπος είναι μια ανώνυμη struct και καλεί το μαθητή. Αλλά αν συνεχίσουμε επίσης το αναγνωριστικό φοιτητής δίπλα στο struct λέξη, όπως και σε typedef struct σπουδαστή, θα μπορούσαμε να χρησιμοποιήσουμε τόσο μαθητή και σπουδαστή struct εναλλακτικά τώρα. Δεν χρειάζεται καν να έχουν το ίδιο όνομα. Θα μπορούσαμε να πληκτρολογήσετε def φοιτητής struct στον Bob struct και τότε φοιτητής και ο Bob θα είναι εναλλάξιμα είδη. Ανεξάρτητα από τον τύπο του def, χρειαζόμαστε το αναγνωριστικό δίπλα στο struct αν ο ορισμός του struct είναι αναδρομική. Για παράδειγμα, def τύπου struct node και θα ορίζεται ως int val και θα έχουν ένα δείκτη που δείχνει σε άλλο κόμβο struct., όπως σε struct node * επόμενο. Και τότε εμείς θα αποκαλούμε κόμβο. Αυτό το struct είναι αναδρομική, δεδομένου ότι ο ορισμός του κόμβου struct περιέχει εντός αυτού ένα δείκτη σε struct node. Σημειώστε ότι πρέπει να πούμε struct node * επόμενο εσωτερικό του ορισμού του κόμβου struct, δεδομένου ότι ο τύπος def δεν έχει τελειώσει ακόμη για να μας επιτρέψει να απλοποιήσει αυτό ακριβώς δίπλα κόμβο *. Θα μάθετε περισσότερα σχετικά με structs παρόμοιο με αυτό όταν ασχολείται με συνδεδεμένες λίστες και δέντρα. Τι γίνεται με structs σε λειτουργία; Αυτό είναι επίσης απολύτως έγκυρη. Θα μπορούσαμε να έχουμε ακυρώσουν την λειτουργία η οποία λαμβάνει ως επιχείρημα, φοιτητής s και κάνει κάτι με αυτό το μαθητή. Και τότε μπορούμε να το περάσει ως φοιτητής struct όπως έτσι. Func του S1 από πριν. Η struct συμπεριφέρεται ακριβώς όπως ένας ακέραιος θα όταν περάσει σε μια λειτουργία. Func λαμβάνει ένα αντίγραφο του S1 και έτσι δεν μπορεί να τροποποιήσει S1? Αντίθετα, μόνο το αντίγραφο του αυτό που είναι αποθηκευμένο στο S. Αν θέλετε η λειτουργία να είναι σε θέση να τροποποιήσει S1, λειτουργία θα πρέπει να λάβει φοιτητής * S, και θα πρέπει να περάσει από τη διεύθυνση S1, όπως έτσι. Φοιτητής * S, λειτουργία & S1. Υπάρχει άλλος ένας λόγος για να περάσει από τη διεύθυνση εδώ. Τι θα συμβεί αν struct μας περιείχε 100 πεδία; Κάθε χρόνο περνάμε ένα μαθητή να λει, το πρόγραμμά μας πρέπει να αντιγράψει όλα αυτά τα 100 γήπεδα σε S επιχείρημα λειτουργία του, ακόμη και αν δεν χρησιμοποιεί τη συντριπτική πλειοψηφία τους. Έτσι, ακόμη και αν δεν λει το σχέδιο για την τροποποίηση του μαθητή, αν μπορεί ακόμα να είναι πολύτιμη για να περάσει από τη διεύθυνση. Εντάξει, τι γίνεται αν θέλουμε να δημιουργήσουμε ένα δείκτη σε struct; Θα μπορούσαμε να κάνουμε κάτι σαν * S φοιτητής ισούται με malloc μέγεθος του μαθητή. Παρατηρήστε ότι το μέγεθος του εξακολουθεί να εργάζεται εδώ. Επομένως, πώς θα έχουν πρόσβαση τώρα το μέλος ηλικία του μπλοκ που να επισημαίνει S; Μπορεί να πρώτα να σκεφτούμε να κάνουμε * S.age = 4, αλλά αυτό δεν θα εργάζονται αρκετά. Δεδομένου ότι αυτό θα είναι πραγματικά να ερμηνευθεί ως * S.age σε παρενθέσεις = 4, η οποία δεν θα είναι καν σύνταξη, από S δεν είναι ένα struct ή μάλλον ένας δείκτης σε μια struct, και έτσι η τελεία δεν θα λειτουργήσει εδώ. Θα μπορούσαμε να κάνουμε (*, S). Ηλικία = 4 αλλά οι παρενθέσεις μπορούν να πάρουν ενοχλητικό και σύγχυση. Ευτυχώς, έχουμε ένα ειδικό φορέα βέλος που μοιάζει S-> ηλικία = 4. Αυτές οι 2 τρόποι αναφορά ηλικία είναι ισοδύναμες και δεν πρέπει ποτέ πραγματικά τον χειριστή βέλος, αλλά αυτό κάνει τα πράγματα να φαίνονται πιο ωραία. Επειδή το S είναι ένας δείκτης για κάποια μπλοκ μνήμης που περιέχει το struct, μπορείτε να σκεφτείτε την ηλικία S> ως εξής το βέλος δείκτη και να αρπάξει την ηλικία μέλος. Έτσι, γιατί θα πρέπει να χρησιμοποιήσετε ποτέ structs; Είναι σίγουρα δυνατόν να ξεφύγει με μόνο τα πρωτόγονα ακέραιοι, χαρακτήρες, οι δείκτες και τα παρόμοια ότι έχουμε συνηθίσει να? αντί των S1 και S2 πριν, θα μπορούσαμε να είχαμε age1, age2, NAME1, NAME2 και όλα σε ξεχωριστές μεταβλητές. Αυτό είναι καλό, με μόνο 2 φοιτητές, αλλά τι θα γινόταν αν είχαμε 10 από αυτούς; Και τι θα γίνει αν αντί για μόνο 2 πεδία, η struct φοιτητής είχε 100 πεδία; ΣΔΣ, τα μαθήματα, το χρώμα των μαλλιών, το φύλο, και ούτω καθεξής. Αντί μόλις 10 structs, χρειαζόμαστε 1.000 ξεχωριστές μεταβλητές. Επίσης, σκεφτείτε μια λειτουργία που παίρνει αυτό το struct με 100 πεδία με μόνο επιχείρημα του και εκτυπώνει όλα τα πεδία. Αν δεν χρησιμοποιείτε ένα struct, κάθε φορά που λέμε αυτή τη λειτουργία, θα πρέπει να περάσει σε όλες τις μεταβλητές 100, και αν έχουμε 100 μεταβλητές για το μαθητή 1, και 100 μεταβλητές για φοιτητή 2, πρέπει να είμαστε σίγουροι ότι δεν περνούν τυχαία κάποιες μεταβλητές από φοιτητή 1 και κάποιες μεταβλητές από το μαθητή 2. Είναι αδύνατο να κάνει αυτό το λάθος με ένα struct, δεδομένου ότι όλες οι μεταβλητές που περιέχονται 100 σε ένα ενιαίο πακέτο. Ακριβώς ένα ζευγάρι των τελικών σημειώσεις: Εάν έχετε κατανοήσει τα πάντα μέχρι αυτό το σημείο, μεγάλη. Το υπόλοιπο του βίντεο είναι μόνο για λόγους πληρότητας ». Επειδή structs μπορεί να κρατήσει οποιοδήποτε τύπο του δείκτη, μπορούν να κρατήσουν επίσης δείκτες λειτουργίας. Αν είστε εξοικειωμένοι με αντικειμενοστραφή προγραμματισμό, αυτό παρέχει έναν τρόπο για να χρησιμοποιήσετε το πρόγραμμα για να structs σε μια αντικειμενοστραφή στυλ. Περισσότερα για την λειτουργία δείκτες σε άλλη χρονική στιγμή. Επίσης, μερικές φορές μπορεί να έχουν 2 structs ορισμούς των οποίων εξαρτάται από το ένα στο άλλο. Για παράδειγμα, θα μπορούσαμε να έχουμε ένα struct, που ορίζεται ως ένα δείκτη σε struct Β, struct B * X, και τώρα μπορούμε να έχουμε ένα struct Β η οποία ορίζεται ως δείκτης σε ένα struct Α, Ένα struct * Y. Αλλά αυτό δεν θα καταρτίσει, από struct Β δεν υπάρχει κατά το χρόνο που struct Α που καταρτίζονται. Και αν έχουμε ανταλλάξει struct Α και Β struct, τότε είχαμε απλώς να μείνει με το ίδιο πρόβλημα? αυτή τη φορά, με ένα struct δεν υπάρχουν. Για να λυθεί αυτό, μπορούμε να γράψουμε struct Β? πριν στον ορισμό του Α. struct Αυτό ονομάζεται δήλωση προς τα εμπρός. Αυτό αφήνει μόνο ο compiler γνωρίζει ότι struct Β είναι ένας έγκυρος τύπος που θα οριστεί αργότερα πλήρως ή αλλού. Το όνομά μου είναι Rob Bowden, και αυτό είναι CS50. [CS50.TV]