Bonjour et bienvenue à nouveau.
Dans cette conférence, je veux parler de l'utilisation des pointeurs et des
structures, comment ils sont liés.
Nous pouvons avoir des éléments à l'intérieur d'une
structure comme pointeurs, puis nous pouvons également faire de nos structures elles-mêmes des pointeurs.
Deux concepts très utiles.
La structure est donc importante ici c autorise les pointeurs à deux structures.
Ainsi, lorsque nous créons une variable de type structure, nous pouvons la
créer en tant que pointeur.
Les pointeurs vers des structures sont plus faciles à manipuler que les structures elles-mêmes.
Donc, encore une fois, c'est une sorte de chose de
notation, cela rend les choses beaucoup plus faciles et c'est aussi plus efficace.
Dans certaines implémentations plus anciennes du langage
c, une structure ne
peut pas être passée comme argument à une fonction, mais
nous savons qu'un pointeur le peut. C'est donc une autre raison pour
laquelle vous voulez qu'une structure soit un pointeur lorsque vous
la déclarez, car vous pouvez la transmettre dans les anciennes versions de
c, vous pouvez la passer comme argument à une fonction.
Même si vous pouvez passer une structure en argument, le
passage d'un pointeur est plus efficace.
Nous savons que c'est plus efficace. Nous avons parlé de cela dans le passé
à quel point le passage important peut être plus efficace.
Dans ce cas, c'est encore plus efficace
car si vous passez dans une structure entière, si la structure est
grande et qu'elle contient beaucoup d'éléments, vous copiez
tous les éléments de la structure vers ce paramètre.
Si vous passez un pointeur, copiez simplement l'adresse.
C'est donc encore plus important avec
des pointeurs comme arguments structurés car les structures peuvent être volumineuses.
Tant de représentations de données utilisent des structures, contenant des pointeurs
vers d'autres structures.
Vous allez voir cela beaucoup dans toutes vos structures
de programmes c qui sont des pointeurs et pour les raisons que nous avons mentionnées.
Le fait que vous puissiez les passer en paramètres sur les anciennes versions
pour les voir et c'est aussi plus efficace car vous
faites tout en passant par valeur ce qui est
beaucoup plus efficace pour copier une adresse
que copier tous les éléments de cette grande structure.
Donc déclarer une structure comme un pointeur assez simple.
Lorsque vous définissez une variable pour être un pointeur vers frappé, vous utilisez simplement cet astérisque
après le type des données.
Et nous avons dit que les structures sont vraiment un nouveau type.
Dans ce cas, notre structure de date toujours importante.
Nous disons simplement struct date, puis utilisons le pointeur de date
astérisque, et vous voudrez probablement l'initialiser à null.
Parce que rappelez-vous, lorsque vous dites struct date pointer date struct
date date pointer, qui n'alloue aucune mémoire pour, il
crée de la mémoire pour stocker le pointeur réel.
Il ne crée pas de mémoire pour les données qu'il contient.
Ainsi, vous pouvez
soit affecter ce point de date ou l'adresse d'une
autre date de structure, soit lui allouer une mémoire
ailleurs ou l'initialiser avec des
données de cette façon également.
Ainsi, le pointeur de date variable peut être affecté comme les autres pointeurs, vous
pouvez le définir pour qu'il pointe vers la date du
jour avec l'instruction d'affectation, donc si nous avions déjà une déclaration de la date du jour.
Nous utiliserions simplement l'esperluette pour en obtenir l'adresse.
Nous créons donc une structure de date normale et c'est la date du jour.
Cela créerait donc de la mémoire pour les trois éléments.
Et puis nous créons notre pointeur et nous lui
attribuons simplement l'adresse de l'autre date.
Assez simple. Nous l'avons fait avec des types de données
normaux, ce n'est pas différent lorsque vous le faites avec des structures.
Vous pouvez ensuite accéder indirectement à l'un des membres de la structure de données pointés par le pointeur de date.
Il faudrait donc faire quelque chose comme ça.
Si vous souhaitez accéder à l'élément de
la structure du pointeur de jour, vous devez d'abord le dé-référencer.
Et donc il serait probablement utile de le mettre entre parenthèses, donc c'est très simple.
Vous devez dé-référencer le pointeur de date pour obtenir la valeur de
la date du jour vers laquelle
pointe, la valeur de l'adresse de la date du jour vers
laquelle il pointe afin de définir des valeurs particulières.
Donc, vous le dé-référenceriez et ensuite
faire le point jour égal à 21 et cela attribuerait 21 à votre
pointeur de jour.
Maintenant, ce qui précède indique simplement quelle que soit la date du jour,
nous voulons accéder à cette valeur et définir le jour sur 21.
Dans ce cas, les parenthèses sont obligatoires car le
point a une priorité plus élevée que l'astérisque.
Si vous n'avez pas mis les parenthèses là-dedans, il est foutu car il essaierait de faire le
point d'abord avant d'avoir réellement le pointeur vers le pointeur, pour le
pointer vers les données.
Donc, il essaierait d'accéder aux données avec un pointeur nul essentiellement.
Et donc en dé-référençant vous obtenez la valeur.
Maintenant, lorsque nous utilisons des structures, des pointeurs.
Si nous voulions tester la valeur des mois stockés dans la structure de date pointée par le pointeur de date,
nous pourrions faire quelque chose comme ça.
Nous dé-référencons le pointeur, mis entre parenthèses, donc il a priorité sur le point, puis nous
disons le mois du point égal à 12.
C'est une syntaxe parfaitement valide.
Mais c'est un peu encombrant.
Ainsi, c a sa propre syntaxe, vous n'avez donc pas à tout dé-référencer
et à le mettre entre parenthèses pour les structures.
Lorsque vous souhaitez accéder à ce vers quoi la structure pointe, vous n'avez
pas à la dé-référencer de cette façon.
Il existe un opérateur spécial qui existe dans c pour les structures de pointeurs, et
c'est le tiret supérieur à.
C'est un tiret suivi du signe supérieur à.
Et cela vous permet de ne pas avoir à dé-référencer le pointeur.
Donc, au lieu de faire étoile x entre parenthèses, puis point y,
vous pouvez simplement dire x tiret supérieur à y.
Parce que x est un pointeur, vous n'avez pas à le référencer et vous voulez
accéder à l'élément à l'intérieur de cette structure quel que soit votre pointeur.
Vous allez donc voir cette syntaxe partout. Vous n'allez pas voir
les parenthèses et la référence d. C'est parfaitement valide, mais vous saisissez plus de caractères.
Il est beaucoup plus efficace de dire simplement x tiret supérieur à y.
Donc, la précédente instruction if ici au lieu de déréférencer entre parenthèses, tout ce que vous avez à
faire est de dire si le pointeur de date est supérieur au mois.
Et c'est un peu intuitif parce que le tiret plus grand que signifie en quelque sorte qu'il pointe vers quelque chose.
Et donc le tiret de date supérieur au mois.
Et donc le pointeur de date est un pointeur et c'est pourquoi vous utilisez le tiret supérieur à.
Maintenant, s'il s'agissait d'une structure imbriquée, vous
feriez le tiret plus grand que la structure, puis vous deviez faire
un point après cela pour accéder aux éléments de la structure imbriquée.
Mais comme le pointeur de jour est un pointeur, vous devez utiliser le tiret égal
ou supérieur à.
Donc, voici un exemple, nous créons notre date de structure, nous
avons trois éléments, puis nous créons notre pointeur de date de pointeur et nous créons juste
une variable régulière aujourd'hui. Nous attribuons à notre
pointeur l'adresse d'aujourd'hui, puis pour attribuer des éléments réels de
la structure, nous utilisons simplement ce tiret supérieur à et nous pouvons ensuite l'imprimer.
Alors regardons cela dans les blocs de code pour voir comment cela fonctionne.
Je vais donc mettre cet exemple ici.
Et généralement, lorsque vous définissez des structures, vous
les définissez en dehors d'une fonction, car vous pouvez alors les utiliser dans n'importe quelle fonction.
C'est un peu comme un mondial. Mais rappelez-vous que
lorsque vous définissez la structure, vous ne créez pas de mémoire.
Vous créez donc toujours les variables en tant que variables locales ou pointeurs, mais
la définition réelle est en dehors de la fonction.
Donc, si vous souhaitez l'utiliser, vous pouvez l'utiliser dans n'importe quelle fonction.
Donc ici en haut, nous avons créé une nouvelle structure de type date
ou nom à date et elle contient trois entiers, nous la terminons par un point-virgule.
Nous créons ensuite quelques variables à l'intérieur du main.
Une qui est juste une date de struct variable normale aujourd'hui,
puis une autre qui est un pointeur. Nous savons que c'est un pointeur car il est précédé de l'astérisque.
Nous savons qu'un pointeur lorsque vous créez un pointeur, il crée uniquement alloue de la mémoire pour
stocker cette adresse pour celle pour cette valeur de ce pointeur.
Nous devrons donc lui attribuer une adresse, ce que nous faisons avec une esperluette aujourd'hui,
car cela crée en fait un rapport de mémoire.
Alors maintenant, le pointeur de date va pointer vers ce
qui est aujourd'hui avec l'adresse d'aujourd'hui.
Nous pouvons alors commencer à lui attribuer des données en utilisant ce tiret plus que très
utile et attribuer simplement une donnée comme n'importe qui d'autre, utilisez simplement l'opérateur d'affectation.
Et puis, lorsque nous l'imprimerons,
vous remarquerez que nous n'avons pas à le dé-référencer pour l'impression.
Pour l'imprimer, nous
pouvons simplement dire que les types de données pour les spécificateurs de format sont ici
pour cent plus élevés pour les entiers, puis nous utilisons simplement un niveleur de
tirets, car c'est en fait le dé-référencement, rappelez-vous.
Maintenant, nous pourrions changer cela et ce serait valable.
Nous devons mettre entre parenthèses et ensuite nous devons dire le point mois.
Dans les deux cas, c'est bien, mais habituez-vous au tiret, puis plus grand car c'est une meilleure syntaxe.
Et maintenant, lorsque nous construisons
cela, vous verrez qu'il imprime les valeurs des pointeurs de
date et ils sont tous définis sur 9 25 et 2015.
On dit donc que la date d'aujourd'hui est le 9 25 15. Il a été formaté pour être imprimé de cette façon.
Des trucs assez simples.
Rappelez-vous simplement que le tiret supérieur à, c'est une nouvelle
syntaxe pour les pointeurs vers les structures.
Mais tout le reste ici est juste normal.
Nous savons que les pointeurs doivent avoir des adresses de magasin, nous
savons donc que nous devons soit allouer de la mémoire dynamique, soit lui attribuer une structure existante.
Revenons en arrière et parlons plus des structures et des pointeurs.
Parlons maintenant des structures qui contiennent des pointeurs.
Nous savons créer un pointeur pour une structure.
Nous pourrions allouer de la mémoire pour ce pointeur si nous ne voulions
pas attribuer une adresse existante à un pointeur existant.
Mais vous pouvez également avoir des éléments à l'intérieur d'une
structure qui est elle-même un pointeur. Ainsi, un pointeur peut également être membre d'une structure.
Nous n'avons pas besoin d'utiliser ce tableau de caractères.
Donc, nous pourrions dire struct,
nous pourrions le nommer en pointeurs et ensuite nous pourrions utiliser ici dans cet exemple nous avons
deux entiers, deux pointeurs entiers p1 et p2, une syntaxe parfaitement valide pour le faire.
Ainsi, une structure appelée pointeurs est définie pour contenir deux pointeurs entiers.
Le premier s'appelle p1 et le second s'appelle p2.
Vous pouvez définir une variable de type struct dans des pointeurs tout comme
les pointeurs normal, struct, int, pointers.
Les pointeurs de variable peuvent maintenant être utilisés comme les autres structures.
Les pointeurs ne sont pas des pointeurs.
Ce sont des pointeurs int. Il contient deux éléments à l'intérieur de son
frappé qui sont des pointeurs, mais les pointeurs eux-mêmes ne sont pas un pointeur réel.
Alors faites attention à cela. C'est une variable de structure qui a deux pointeurs
comme membres, c'est différent.
Donc, si nous voulons accéder aux éléments à l'intérieur de la
variable pointeurs qui est dans les pointeurs, nous n'utilisons
pas le tiret plus grand que parce que les pointeurs n'est pas un pointeur, c'est une structure.
Nous utiliserions le point
pour accéder à p1 et accéder à p2.
Donc dans cet exemple, nous créons notre structure,
nous créons une variable. Ce n'est pas un pointeur appelé pointeurs.
Et puis on crée deux entiers,
i1 égal à 100 et i2 qui n'est pas initialisé.
Maintenant p1 et p2 sont des pointeurs.
Ils doivent donc contenir des adresses mémoire valides où les adresses ont
été allouées en mémoire.
Et c'est ce que font les i1 et i2.
Lorsque vous déclarez les variables entières, de la mémoire est allouée pour ces entiers.
Et donc en attribuant les adresses i1 et i2 à p1 et p2, c'est parfaitement bien car i1
et i2 ont de la mémoire allouée car ce sont des entiers.
Maintenant, si les pointeurs entiers n'étaient pas des pointeurs entiers mais des pointeurs de caractères,
alors vous devrez allouer de la mémoire dynamique.
Alors maintenant, nous n'utilisons que des entiers, donc nous assignons les adresses des deux entiers à p1 et p2.
Nous pouvons maintenant dire des pointeurs étoiles. p2 vaut 97, moins
97.
Pourquoi devons-nous le dé-référencer ici parce
que des pointeurs. p2 est ce à quoi nous faisons référence.
Des pointeurs. pt p2 est un pointeur.
Nous n'accédons pas à un élément d'une structure.
Nous déréférencons tous les pointeurs. p2.
Et nous allons attribuer à cela la valeur de tout ce qui indique une valeur négative de 97.
Alors remarquez la différence là-bas.
Nous ne créons pas de pointeur de structure.
Nous créons un pointeur de variable régulier, mais il
contient deux éléments qui sont des pointeurs.
Donc, si nous voulons attribuer à ces deux éléments à l'intérieur de la structure, nous
devons les dé-référencer à l'aide de l'opérateur d'indirection, et c'est ce
que nous faisons là-bas.
Et puis dans nos deux déclarations imprimées.
Encore une fois, nous voulons imprimer les valeurs de ce vers quoi p1
pointe, donc nous le dé-référencons de la
même manière avec p2, puis nous voulons
également imprimer à nouveau les valeurs vers lesquelles pointent les pointeurs.
Donc, dans ce premier, nous disons que i1 est égal
au pourcentage I pointeurs de virgule. p1 est égal au
pourcentage I.
Donc, le premier à l'intérieur des guillemets doubles est juste l'impression de
ce texte réel, il ne déréférencer rien après la virgule est l'endroit où nous faisons le dé-référencement.
Nous imprimons d'abord i1 qui vaut 100, puis nous
imprimons les pointeurs p1 qui seraient 100.
I2 sera en fait négatif
97 après que nous l'ayons attribué à p2.
Alors qu'en est-il des tableaux de caractères ou des pointeurs de caractères. Dans la conférence précédente, nous avons
expliqué comment créer un tableau de caractères en tant qu'élément
à l'intérieur d'un pointeur. Mais qu'en est-il des pointeurs de caractères,
devrions-nous faire quelque chose comme
le premier et le dernier ont des
tableaux de caractères ou devrions-nous simplement faire quelque chose comme le premier et le
dernier avec des pointeurs de caractère comme éléments. Quelle est la meilleure option.
Eh bien, nous verrons. C'est vraiment encore une chose de notation, mais il y a des avantages à utiliser les pointeurs.
Ainsi, lorsque nous créons des pointeurs vers des caractères à l'intérieur de nos éléments,
c'est généralement un peu mieux.
Mais vous devez comprendre ce qui se passe ici lorsque vous
créez un tableau élément char array en tant qu'élément ou un pointeur en tant qu'élément, les
deux sont valides. Mais il y a une grande différence.
Donc, si nous disons les noms de structure
veep ou vp et que nous disons Talia et Summers, puis nous
disons nom du pointeur de structure. Rappelez-vous donc que les noms de structure contiennent les tableaux de caractères.
Les noms de pointeurs de structure contiennent les pointeurs.
Et nous initialisons ici les pointeurs égaux à Brad et Fallingjaw.
Et puis nous les imprimons, nous allons imprimer le premier élément,
qui est un caractère a et vp, puis
le premier élément de Treasury, qui est un pointeur vers le premier.
Ainsi, la structure nomme la variable veep.
Ce qui se passe ici, c'est que les chaînes sont stockées à l'intérieur de la structure.
La structure a alloué un total de 40 octets pour contenir les deux noms, ce
sont des tableaux de caractères.
C'est ce qui se passe lorsque nous créons des tableaux de caractères à l'intérieur d'un pointeur.
Nous allouons 40 octets pour contenir ces deux
noms, 20 et 20.
Pour la variable de noms de pointeur trés si nous avons deux pointeurs en premier et en dernier,
ce sont des chaînes qui sont stockées partout où le compilateur stocke des constantes de chaîne.
La structure contient les deux adresses
car ce sont des pointeurs. Les pointeurs contiennent, quoi, des valeurs qui sont des adresses.
Donc, tout ce qu'il va faire est d'allouer deux pointeurs à l'intérieur de cette structure.
C'est 16 octets pour la plupart des systèmes, les pointeurs généralement 8 octets ou 4 octets.
La structure de nom struct p n'alloue aucun espace pour stocker les chaînes
car elle n'alloue que de l'espace pour les pointeurs eux-mêmes.
Les pointeurs ont des valeurs qui sont des adresses.
L'adresse vers laquelle il pointe, il n'y a pas de mémoire allouée pour cela.
Ainsi, lorsque vous créez ces deux pointeurs, il n'y a pas de mémoire allouée pour ces deux pointeurs.
Il n'alloue aucun espace.
Il ne peut donc être utilisé qu'avec des chaînes pour lesquelles de l'espace leur est alloué ailleurs.
Chaque fois que vous avez des pointeurs à l'intérieur d'une structure,
vous devez utiliser malloc ou calloc.
Sinon, ils pourraient être stockés partout où les constantes de chaîne sont stockées.
Et c'est la grande différence. Ainsi, les pointeurs et la structure de nom
p doivent être utilisés uniquement pour gérer les chaînes qui ont été créées et allouées ailleurs dans le programme.
Vous ne voulez pas
attribuer de données à cela à moins que vous ne les ayez allouées dynamiquement
ou qu'elles aient été allouées ailleurs,
peut-être par une structure existante ou quelque chose. Mais en général, vous allez vouloir malaxer ces pointeurs.
Encore une fois, très différent.
Vous allouez 40 octets pour ces deux tableaux de caractères dans la structure de nom.
Pour la structure de nom p, vous avez deux pointeurs.
Il n'y a pas de mémoire allouée pour cela lorsque vous créez une variable de ce type.
Il s'agit simplement de créer de la mémoire pour les deux pointeurs de caractères, soit huit octets chacun.
Pour allouer réellement de la mémoire pour ce que le premier et le dernier pointent, vous devez faire un malloc.
Donc, une instance dans laquelle il est logique d'utiliser un pointeur et une structure
est de gérer
des chaînes est si vous allouez dynamiquement cette mémoire.
C'est généralement lorsque vous l'utilisez,
car d'autres types de données autorisés vont automatiquement allouer la mémoire pour vous.
Vous souhaitez donc utiliser un pointeur pour stocker l'adresse.
Cela présente l'avantage que vous pouvez demander à malloc d'allouer uniquement la quantité
d'espace nécessaire pour une chaîne. Nous avons parlé des avantages de l'allocation dynamique de mémoire.
Lorsque vous créez des éléments de manière statique au moment de la
compilation, vous ne créez qu'un nombre spécifique d'octets.
Que se passe-t-il si vous avez besoin de plus d'octets, que vous êtes foutu, que votre programme ne fonctionnera pas.
Vous devez revenir en arrière et recompiler. Avec des chaînes allouées dynamiquement,
vous pouvez réajuster, vous pouvez créer autant de mémoire que nécessaire, ce qui le
rend beaucoup plus efficace dans le programme.
Vous allez donc utiliser malloc sur tous les pointeurs créés à l'intérieur d'une structure.
Donc, dans ce cas, vous avez une structure nommée name count.
Vous avez deux pointeurs, des pointeurs de caractère fname et nom de famille.
Et puis vous avez un int, des lettres.
Les deux chaînes à l'intérieur ne sont pas stockées dans la structure.
Nous créons uniquement de la mémoire pour les pointeurs, qui contiennent des adresses.
Nous voulons créer de la mémoire pour fname et lname pour ce que les pointeurs pointent.
Nous voulons donc stocker cela dans un bloc géré par un emplacement de mémoire dynamique, qui utilise malloc.
L'adresse des deux chaînes est ce qui est stocké, pas ce vers quoi elles pointent.
Donc, les adresses sont ce avec quoi les fonctions de gestion de chaînes fonctionnent généralement,
ce qui est bien et c'est pourquoi vous voulez utiliser des pointeurs
là-dedans, car vous n'avez pas à cela, vous pouvez simplement les transmettre beaucoup plus facilement.
Voici donc un exemple. Nous avons une fonction appelée obtenir des informations.
Cela prend un pointeur.
Et nous pouvons passer ce pointeur très facilement.
Maintenant, nous allons également en créer un autre
ou pour notre tableau de pointeurs que nous
lui passons, nous allons lui allouer
de la mémoire.
Vous verrez donc que nous créons un personnage appelé temp,
puis nous stockons des données dans cette temp.
Nous demandons à l'utilisateur d'obtenir quelque chose. Nous ne sommes pas familiers avec les sgets, mais c'est la même chose que le scanf est un peu sauvegardé.
Ensuite, nous allouons de la mémoire pour fname à l'intérieur de ce pointeur et nous le faisons comme nous allouons
de la mémoire pour n'importe quel caractère. On appelle malloc,
on passe le nombre d'octets.
Dans ce cas, la longueur de chaîne de 10 plus 1 pour le terminateur nul.
Et puis rappelez-vous, malloc transforme une étoile vide, alors nous l'avons jetée en étoile de personnage.
Mais c'est essentiel ici. Cet appel malloc est nécessaire pour toutes les structures contenant des pointeurs.
Maintenant, nous avons passé ce pointeur et le pointeur n'a jamais eu de mémoire allouée
pour cela.
Nous allouons donc de la mémoire à l'intérieur ici. Nous pouvons alors faire notre copie très facilement.
Nous pouvons copier temp dans fname de notre structure pst qui a été
passé en paramètre.
Et puis nous pouvons leur faire entrer leur nom de famille, nous pouvons ajouter plus de mémoire
pour le nom de famille, puis les stocker dans la variable struct nom.
C'est ce que vous allez devoir faire lorsque vous avez des pointeurs vers des
personnages à l'intérieur de vos structures, vous devez faire le malloc.
Car encore une fois, ces pointeurs ne stockent que l'adresse.
Ils allouent suffisamment de mémoire pour stocker une adresse, pas
assez de mémoire pour stocker une chaîne.
Donc, quelle que soit cette adresse, vous devez allouer de la mémoire pour cela et
vous le faites comme d'habitude avec le
malloc, la seule différence est ici que vous utilisez le tiret supérieur au signe
pour accéder à l'élément réel à l'intérieur de cette structure, qui est un pointeur de caractère, afin
que vous puissiez lui attribuer et c'est faire le dé-référencement.
Vous aurez donc envie de jouer avec ce genre de choses. Ceci est très courant pour
les pointeurs de caractères à l'intérieur des structures.
Nous allons avoir un défi où vous allez devoir faire ça. Mais jouez avec ce code, entrez dans
les blocs de code, commencez à allouer de la mémoire pour les
chaînes ou les pointeurs de caractères à l'intérieur des structures
et voyez comment vous pouvez ensuite utiliser str copy pour y placer des données, mais
vous devez d'abord allouer la mémoire avant d'affecter .
Si vous faites des constantes comme dans l'exemple précédent, qui sait où cette mémoire est allouée.
Encore une fois, beaucoup de concepts importants présentés dans cette conférence.
Cette idée d'une structure qui est un pointeur dans cette
nouvelle syntaxe où
l'on peut utiliser le tiret alors plus grand que par opposition à
l'utilisation de l'opérateur d'indirection, très sympa.
Et puis en fait avoir des éléments comme pointeurs et comment vous
devez allouer de la mémoire pour les pointeurs de caractères. Merci.