[Powered by Google Translate] Parlons un peu de structures.
Structures nous fournir un moyen de regrouper un ensemble de variables entre elles
dans un joli paquet.
Il est probablement plus facile de voir un exemple tout de suite,
alors nous disons struct,
puis en ouvrant accolade,
et dans cette structure, nous aurons un âge int,
un char * nom,
et c'est tout.
Il peut sembler bizarre avec un point-virgule après une accolade,
mais il est en fait nécessaire avec structs.
Tout type valide peut aller dans la définition de la structure.
Ici, nous avons utilisé un int et un char *,
mais vous pouvez aussi utiliser un tableau, de dire, de 100 éléments
ou même une autre structure.
Lorsque vous utilisez structs en C,
vous créez de nouveaux types
sur un ensemble de types autres.
Ici, nous faisons un nouveau type
sur un nombre entier et un char *.
Comme nous le verrons plus tard, un type struct
est dans beaucoup de manières équivalentes à tout autre type que vous êtes habitué.
Habituellement, je vais comparer la façon dont un type struct
est similaire à un type entier.
Bien que le code que nous avons écrit est valide C,
ce n'est pas très utile,
et clang nous donnera un avertissement.
Rappelez-vous comment structs et ses semblables sont?
Eh bien, nous venons de dire essentiellement
int,
ce qui n'est pas une ligne très utile.
Donc, nous allons effectivement déclarer une variable de ce type
en lui donnant un nom avant le point-virgule.
Nous allons appeler l'étudiant variable.
Maintenant, nous avons déclaré un étudiant variable appelée
avec le type proposée par le struct.
Comment arrivons-nous à les variables à l'intérieur de la structure?
Techniquement, les noms de ces variables
sont membres.
Pour accéder à un membre en particulier dans une structure étudiant,
vous ajoutez un point à un nom de variable,
suivi du nom du membre que vous voulez.
Donc, ici, les 2 seules possibilités valables
sont student.age
et student.name.
Et nous pouvons faire quelque chose comme
student.age = 12
et student.name = étudiant.
Maintenant, si nous voulions faire un étudiant de deuxième?
Vous pourriez penser à copier et coller ces lignes
et changer un élève à 2 ou quelque chose,
et cela fonctionnera,
mais techniquement, étudiant et étudiant 2
n'ont pas le même type.
Voir, vous ne serez pas en mesure de les affecter à un autre.
C'est parce que, jusqu'à présent,
votre structure a été anonyme.
Nous devons lui donner un nom.
Pour ce faire, nous insérons le nom de la structure
après le mot struct.
étudiant,
suivie par la définition.
Nous pouvons toujours immédiatement déclarer une variable de type
struct étudiant, comme nous le faisions auparavant.
Nous l'appellerons S1
En donnant à la structure d'un nom,
nous pouvons maintenant utiliser étudiant struct
dans presque exactement la même manière que nous utiliserions int.
Ainsi, nous pouvons déclarer une variable de type struct étudiant,
comme
struct étudiant S2.
Comme les tableaux, les structures fournissent une syntaxe d'initialisation de raccourci,
de sorte que nous pouvons dire, struct étudiant S2
est égal à
accolade gauche 3, S2.
Ici, S2.age sera de 3,
et S2.name pointera vers S2.
Pensez à toutes les choses que vous pouvez faire avec un type int
et la plupart d'entre eux que vous pouvez faire avec un type struct étudiant.
Nous pouvons utiliser un étudiant struct comme type de paramètre d'une fonction.
Nous pouvons utiliser étudiant struct l'intérieur d'une structure nouvelle.
Nous pouvons avoir un pointeur à un étudiant struct.
Nous pouvons faire la taille de l'étudiant struct.
Étudiant struct est un type
comme int est un type.
Nous pouvons également attribuer S1 à S2
puisque les deux sont du même type, de sorte que nous pouvons faire
S1 = S2.
Qu'est-ce qui se passe si nous faisons
S1.age = 10?
Est-ce que le changement S2 du tout?
Encore une fois, pensez aux structs juste que les entiers réguliers.
Si nous attribuons une certaine X int dans une certaine int Y,
comme X = Y
puis modifiez X,
comme dans X + +,
Y ne change pas du tout?
Y ne change pas ici, et donc ni ne S2 ci-dessus.
S2.age reste 3.
Mais il faut noter que lorsque l'affectation d'un struct à l'autre,
tous les pointeurs indiquent toujours la même chose,
car ils viennent d'être copiés.
Si vous ne voulez pas les pointeurs doivent être partagées,
vous devrez gérer manuellement que,
peut-être par une malicking bloc de mémoire pour l'un des pointeurs pour pointer vers
et la copie des données sur.
Il pourrait être gênant d'avoir à écrire des élèves struct partout.
L'utilisation d'un type de def, nous pouvons faire
Type de def
struct
et nous allons l'appeler étudiant.
Maintenant, nous pouvons utiliser des étudiants partout
que nous utilisions des étudiants struct.
Ce type de définition est une struct anonyme
et il appelle cela des élèves.
Mais si nous gardons aussi l'identificateur de l'étudiant
à côté de la struct mot, comme dans typedef struct étudiant,
nous pourrions utiliser à la fois des élèves et des étudiants struct interchangeable maintenant.
Ils n'ont même pas d'avoir le même nom.
Nous pourrions taper étudiant struct def à Bob
puis struct étudiant et Bob
serait types interchangeables.
Quel que soit le type de def,
nous avons besoin de l'identifiant à côté de struct
si la définition de la structure
est récursive.
Par exemple,
Type struct def noeud
et il sera défini comme un int val
et il aura un pointeur qui pointe vers un autre nœud struct.,
comme dans noeud struct * à côté.
Et puis, nous l'appellerons nœud.
Cette structure est récursive,
puisque la définition de struct noeud contient en son sein
un pointeur vers un noeud de structure.
Notez que nous avons à dire struct noeud * suivant
à l'intérieur de la définition de la structure du noeud,
depuis la définition de type n'a pas encore fini de nous permettre de simplifier cette
juste noeud * suivant.
Vous en apprendrez plus sur structs similaires à ce
lorsqu'ils traitent avec les listes chaînées et les arbres.
Qu'en est-il structs dans une fonction?
C'est aussi tout à fait valable.
Nous pourrions avoir
annuler fonctions
qui prend comme argument,
étudiant s
et fait quelque chose avec cet élève.
Et puis on peut passer comme struct étudiant comme ceci.
Fonction de S1 d'avant.
La structure se comporte
exactement comme un entier serait lorsqu'il est passé à une fonction.
Func reçoit une copie de S1
et ne peut donc pas modifier S1;
plutôt que la copie de celui-ci qui est stocké dans S.
Si vous voulez utiliser cette fonction pour être en mesure de modifier S1,
fonctions aurez besoin de prendre un étudiant * S,
et vous aurez à passer S1 par adresse, comme ceci.
Étudiant * S, fonctions et S1.
Il ya une autre raison de passer par l'adresse ici.
Que faire si notre structure contient 100 champs?
Chaque fois que nous passons à un élève de fonction,
notre programme a besoin de copier l'ensemble de ces 100 champs en fonction de l'argument de S,
même si elle n'utilise jamais la grande majorité d'entre eux.
Donc, même si fonction n'a pas l'intention de modifier l'étudiant,
si peut toujours être utile de passer par adresse.
Ok, si nous voulons créer un pointeur vers une struct?
Nous pourrions faire quelque chose comme
étudiant * S
est égal à malloc
taille de l'élève.
Notez que la taille du marche toujours ici.
Alors, comment pouvons-nous maintenant accéder au membre âge
du bloc que les points de S?
Vous pourriez d'abord penser à faire
* S.age = 4,
mais ce ne sera pas tout à fait fonctionné.
Depuis cela va vraiment être interprété comme
S.age * entre parenthèses = 4,
qui ne seront même pas compiler,
puisque S n'est pas une structure ou plutôt un pointeur vers une struct,
et si le point ne fonctionne pas ici.
Nous pourrions faire
(* S). Âge = 4
mais les parenthèses sont parfois ennuyeux et confus.
Heureusement, nous avons un opérateur flèche spéciale
qui ressemble à
S-> age = 4.
Ces 2 façons de référencer l'âge
sont équivalentes
et nous n'avons pas vraiment besoin de plus l'opérateur flèche,
mais cela rend les choses plus joli.
Comme S est un pointeur vers un bloc de mémoire qui contient la structure,
vous pouvez penser à S> âge comme suit la flèche du pointeur
et de saisir le membre âge.
Alors pourquoi devrions-nous toujours utiliser des structs?
Il est certainement possible de s'en tirer avec seulement des nombres entiers primitifs,
caractères, des pointeurs et autres
que nous sommes habitués à;
au lieu de S1 et S2 avant,
nous aurions pu avoir âge1, age2, nom1, nom2 et
tout à variables séparées.
C'est très bien avec seulement 2 étudiants,
mais que faire si nous avons eu 10 d'entre eux?
Et si, au lieu de seulement 2 champs,
la structure étudiant avait 100 champs?
AMP, les cours, la couleur des cheveux, le sexe, et ainsi de suite.
Au lieu de seulement 10 structures, nous avons besoin de 1000 variables séparées.
Aussi, considérons une fonction
qui prend cette structure avec 100 champs avec son seul argument
et affiche tous les champs.
Si nous n'avons pas utilisé une structure,
chaque fois que nous appelons cette fonction,
nous avons besoin de passer à tous les 100 variables,
et si nous avons 100 variables pour étudiant 1,
et 100 variables pour les étudiants 2,
nous devons être sûrs de ne pas accidentellement transmettre certaines variables de l'étudiant 1
et certaines variables de l'élève 2.
Il est impossible de faire cette erreur avec une struct,
puisque tous les 100 variables sont contenues dans un seul paquet.
Juste quelques notes finales:
Si vous avez tout compris jusqu'à ce point, tant mieux.
Le reste de la vidéo est juste pour être complet.
Parce que structs peut contenir n'importe quel type de pointeur,
ils peuvent aussi contenir des pointeurs de fonction.
Si vous êtes familier avec la programmation orientée objet,
cela fournit un moyen d'utiliser des structs à programmer dans un style orienté objet.
En savoir plus sur les pointeurs de fonction à un autre moment.
En outre, vous pouvez parfois avoir 2 structs
dont les définitions dépendent les uns des autres.
Par exemple,
nous pourrions avoir struct A,
qui est définie comme
un pointeur vers une struct B,
struct B * X,
et maintenant nous pouvons avoir une struct B
qui est défini comme un pointeur
une structure de A,
struct A * Y.
Mais ce ne sera pas compilé,
puisque B struct n'existe pas à l'époque que struct A est en cours d'élaboration.
Et si nous échangeons struct A et B struct,
alors que nous venions de se retrouver avec le même problème;
cette fois, avec struct A existant pas.
Pour résoudre ce problème, nous pouvons écrire
struct B;
avant la définition de struct A.
C'est ce qu'on appelle une déclaration anticipée.
Cela permet juste savoir au compilateur que
struct B est un type valide qui sera entièrement défini plus tard ou ailleurs.
Mon nom est Rob Bowden, et c'est CS50.
[CS50.TV]