Pointeurs et les références dans la partie C + + 1

Avril 19, 2009 Posté dans C / C + +

Pointeurs et les références sont deux concepts importants en science informatique. Ils apparaissent dans de nombreux langages de programmation avec une robe ou un peu différent, mais le traitement est essentiellement le même. En C + +, avec des compétences pointeurs sont essentiels.

Pointer est un type spécial de données, des variables dont l'objectif déclaré de ce genre peut (ou non) à d'autres données en mémoire. Une variable pointeur, contient l'adresse d'une autre chose dans la mémoire. Cette chose peut être une variable, une constante, ouverture d'un ensemble de données, une fonction, entre autres.

Déclarant Pointeurs

La déclaration d'un pointeur se fait généralement en ajoutant un * avant le nom de la variable. Une notation utilisée bien que la colle * le nom du type-à-dire symboliquement que c'est déclarer un pointeur "à type" au lieu d'une variable «pointeur», mais ils sont équivalents. Par exemple:

  / / Pointeur sur un int.
 ptr_num1 ; int * ptr_num1;

 / / Ou alors.
 ptr_num2 ; int * ptr_num2;

 / / Pointeur vers un double.
 ptr_double1 ; * Double ptr_double1;

 / / Ou alors.
 ptr_double2 ; * Double ptr_double2; 

Une fois déclarée, le pointeur existe, a la taille et par conséquent prend place dans la mémoire. La taille d'un pointeur est généralement égal au nombre de bits de la machine / système en question, par exemple 4 octets dans un système 32-bit.

  17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 pc ; int i, * pi ; double d, * pd ; // O operador sizeof diz o tamanho do tipo do seu argumento. cout << "Size of char:    " << sizeof ( c ) << " bytes" << endl ; cout << "Size of int:     " << sizeof ( i ) << " bytes" << endl ; cout << "Size of double:  " << sizeof ( d ) << " bytes" << endl ; cout << endl ; cout << "Size of char*:   " << sizeof ( pc ) << " bytes" << endl ; cout << "Size of int*:    " << sizeof ( pi ) << " bytes" << endl ; cout << "Size of double*: " << sizeof ( pd ) << " bytes" << endl ; c char *, PC, int i, pi *, Double D, * pd; / / L'opérateur sizeof dit la taille du type de son argument. cout <<"Taille du char:" <<sizeof (c) <<" octets "<<endl; cout <<" taille de int: "<<sizeof (i) <<" octets "<<endl; cout <<" Taille du double: "<<sizeof (d) <<" octets " <<endl; cout <<endl; cout <<"taille de char *:" <<sizeof (cp) <<"octets" <<endl; cout <<"taille de int *:" <<sizeof (pi) <<"octets" <<endl; cout <<"taille de la double *" <<sizeof (pd) <<"octets" <<endl; 

Utilisant des pointeurs

Après sa déclaration, le contenu d'un pointeur est une valeur aléatoire, la mémoire des déchets, comme n'importe quelle variable. Pour qu'elle soit utile, nous devons lui donner quelque chose. En tant que pointeur contient une adresse mémoire, nous devons lui attribuer une adresse valide.

  17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
  int x, y;
 px, * py ; int *, PY * px;

 ; x = 13;
 ; y = 10;

 x ; px = & x;
 y ; & Y = py;

 42 ; * Px = 42;
 py ) ++ ; (Py *) + +;

 * px << endl ; <<Cour * px <<endl;
 * py << endl ; cout <<* py <endl <;
 ( * px ) * ( * py ) << endl ; cout <<(* px) * (* py) <endl <; 

L'opérateur & (esperluette ou esperluette ) devant un nom de variable signifie «adresse», parce que son nom est «l'adresse».

Ce qui reste de l'égalité doit être capable de garder exactement le même genre que celle de l'autre côté de l'égalité. Un pointeur de magasins d'une adresse. Donc, pour attribuer une adresse à un pointeur dans ce cas, vous devez obtenir une adresse avec l'opérateur &.

Sauf dans le cas où il ya des conversions de type implicites (par exemple entre les types numériques), assigner une variable à quelque chose avec un autre type que le sien, ce qui provoque une erreur de compilation. Heureusement!

Après un pointeur points déjà à une adresse valide, nous pouvons accéder au contenu de cette adresse et l'opérateur * ( astérisque ), dont le nom officiel est «l'opérateur de référence de."

Notez que l'astérisque dans un communiqué signifie "pointeur de type" et dans le contexte de la lecture ou l'écriture du contenu d'un pointeur, signifie "le contenu de l'adresse» ou «le contenu pointé par". Faites également attention à ne pas confondre le symbole du produit arithmétique. Pour éviter toute confusion, rappelons que immense table de priorité des opérateurs , ce qui vous vient de passer de l'œil et est tombé dans l'oubli. Vous y trouverez que l'opérateur de référence-a priorité sur l'opérateur de multiplication. Alors vous vous souviendrez que l'opérateur de référence est évaluée avant de l'opérateur de multiplication.

  17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
  pa, * pb ; int a, b, c, pa *, * pb;
 ; a = 2;
 ; b = 3;

 a ; PA = & A;
 b ; PB = & b;

 pa * * pb ; c = * pb * pa;
 pa * * pb ; c = * pb * pa;
 pa * * pb ; c = * pb * pa;
 pa ** pb ; c = * pa ** pb;
 * pa ) * ( * pb ) ; c = (* pa) * pb (*);

 "Valor da Pegadinha: " << c << endl ; cout <<"Valeur de Gotcha:" <<c <<endl; 

Ainsi, lorsque que la preuve d'algorithmes de vous demander ce que fait l'un des cinq dernières lignes de l'exemple que vous dira qu'il multiplie le contenu pointé par AP et BP. Pas plus ramasser DP pour elle! Et la rupture dans la vie réelle, si vous avez vraiment besoin de faire cela, vous allez économiser votre et cinquième quatrième générations futures passé excommunication , si vous choisissez d'utiliser la dernière ligne.

Tout est possible avec une variable commune, vous pouvez faire avec le contenu pointé par un pointeur, soit la lecture ou l'écriture (sauf s'il est clair que le pointeur est const, mais c'est une autre conversation ...).

Adresses et pointeurs

Prenons par exemple le code ci-dessous:

  18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
  int a, b;
 pa, * pb ; int *, Pb * pa;

 "Antes de qualquer atribuição: \n " ) ; printf ("Avant toute cession: \ n");

 "&a  = %p \n " , & a ) ; // Endereço válido dado pelo SO. printf ("& = \ p n% a", & a) / / valide l'adresse donnée par le système d'exploitation.
 "&b  = %p \n " , & b ) ; // Endereço válido dado pelo SO. printf ("& b = p% \ n", et b) / / valide l'adresse donnée par le système d'exploitation.
 "&pa = %p \n " , & pa ) ; // Endereço válido dado pelo SO. printf ("& pa = p% \ n", & PA) / / valide l'adresse donnée par le système d'exploitation.
 "&pb = %p \n " , & pb ) ; // Endereço válido dado pelo SO. printf ("& pb = p% \ n", et BP); / / valide l'adresse donnée par le système d'exploitation.

 " \n " ) ; printf ("\ n");

 "a   = %d \n " , a ) ; // Conteúdo não inicializado (aleatório). printf ("a =% d \ n", a) / / non initialisée contenu (aléatoire).
 "b   = %d \n " , b ) ; // Conteúdo não inicializado (aleatório). printf ("b =% d \ n", b) / / non initialisée contenu (aléatoire).
 "pa  = %p \n " , pa ) ; // Conteúdo não inicializado (aleatório). printf ("% pa = p \ n", PA) / / non initialisée contenu (aléatoire).
 "pb  = %p \n " , pb ) ; // Conteúdo não inicializado (aleatório). printf ("% p = BP \ n", pb); / / non initialisée contenu (aléatoire).

 / / S'il vous plaît, décommentez les lignes suivantes, recompiler et exécuter.
 / / Printf ("* pa =% \ n" d, * PA) / / Quel est (* au hasard)?
 / Printf ("* PB =% d \ n" /, PB *) / / Quel est (* au hasard)?

 " \n Após as inicializações dos ponteiros: \n " ) ; printf ("\ n Après l'initialisation des pointeurs: \ n");

 a ; PA = & A;
 b ; PB = & b;

 "&a  = %p \n " , & a ) ; // Mesmo endereço válido dado pelo SO. printf ("& = \ p n% a", & a) / / Même adresse valide donnée par le système d'exploitation.
 "&b  = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ("& b = p% \ n", et b) / / Même adresse valide donnée par le système d'exploitation.
 "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("& pa = p% \ n", & PA) / / même adresse comme valide par le système d'exploitation.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& pb = p% \ n", et BP); / / même adresse comme valide par le système d'exploitation.

 " \n " ) ; printf ("\ n");

 "a   = %d \n " , a ) ; // Conteúdo não inicializado (aleatório). printf ("a =% d \ n", a) / / non initialisée contenu (aléatoire).
 "b   = %d \n " , b ) ; // Conteúdo não inicializado (aleatório). printf ("b =% d \ n", b) / / non initialisée contenu (aléatoire).
 "pa  = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ("% pa = p \ n", PA) / / Contenu initialisée (et a).
 "pb  = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ("% p = BP \ n", pb); / / Contenu initialisé (& b).

 "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa (*pa == a). printf ("* pa =% \ n" d, * PA) / / le contenu pointé par AP (AP == * a).
 "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (*pb == b). printf ("* PB =% \ n" d, Pb *) / / le contenu pointé par BP (BP == * b).

 " \n Após as inicializações dos inteiros: \n " ) ; printf ("\ n Après les initialisations des entiers: \ n");

 ; a = 10;
 ; b = 13;

 "&a  = %p \n " , & a ) ; // Mesmo endereço válido dado pelo SO. printf ("& = \ p n% a", & a) / / Même adresse valide donnée par le système d'exploitation.
 "&b  = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ("& b = p% \ n", et b) / / Même adresse valide donnée par le système d'exploitation.
 "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("& pa = p% \ n", & PA) / / même adresse comme valide par le système d'exploitation.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& pb = p% \ n", et BP); / / même adresse comme valide par le système d'exploitation.

 " \n " ) ; printf ("\ n");

 "a   = %d \n " , a ) ; // Conteúdo inicializado (10). printf ("a =% d \ n", a); / / démarre le contenu (10).
 "b   = %d \n " , b ) ; // Conteúdo inicializado (13). printf ("b =% d \ n", b) / / démarre le contenu (13).
 "pa  = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ("% pa = p \ n", PA) / / Contenu initialisée (et a).
 "pb  = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ("% p = BP \ n", pb); / / Contenu initialisé (& b).

 "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa (*pa == a == 10). printf ("* pa =% \ n" d, * PA) / / le contenu pointé par AP (* pa == a == 10).
 "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (*pb == b == 13). printf ("* PB =% \ n" d, Pb *) / / le contenu pointé par pb pb * (b == == 13).

 " \n Alterando os valores através dos ponteiros: \n " ) ; printf ("\ n L'évolution des valeurs via des pointeurs: \ n");

 7 ; * Pa = 7;
 42 ; * BP = 42;

 "&a  = %p \n " , & a ) ; // Mesmo endereço válido dado pelo SO. printf ("& = \ p n% a", & a) / / Même adresse valide donnée par le système d'exploitation.
 "&b  = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ("& b = p% \ n", et b) / / Même adresse valide donnée par le système d'exploitation.
 "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("& pa = p% \ n", & PA) / / même adresse comme valide par le système d'exploitation.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& pb = p% \ n", et BP); / / même adresse comme valide par le système d'exploitation.

 " \n " ) ; printf ("\ n");

 "a   = %d \n " , a ) ; // Conteúdo inicializado (a == *pa ==  7). printf ("a =% d \ n", a); / / Contenu initialisé (* pa == a == 7).
 "b   = %d \n " , b ) ; // Conteúdo inicializado (b == *pb == 42). printf ("b =% d \ n", b) / / Contenu initialisé (b == PB * == 42).
 "pa  = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ("% pa = p \ n", PA) / / Contenu initialisée (et a).
 "pb  = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ("% p = BP \ n", pb); / / Contenu initialisé (& b).

 "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa ( 7). printf ("* pa =% \ n" d, * PA) / / Contenu nommé par an (7).
 "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (42). printf ("* PB =% \ n" d, Pb *) / / le contenu pointé par BP (42). 

Lignes 18:19 respectivamnete déclarer deux entiers et deux pointeurs sur des entiers.

Lignes 23-26 indiquent les adresses de mes variables. Ces adresses ont été données par le système d'exploitation et sont fixes, tandis que ces variables existent. Une variable ne change pas d'adresse au cours du programme, mais peut changer entre une exécution et un autre. Qui définit ce que cette adresse est le système d'exploitation au moment de l'exécution du programme. Le compilateur sait seulement que X octets sont nécessaires pour chaque variable, et de l'interprétation (de style) que le programme donnera cet espace.

Lignes 30-33 afficher le contenu de ces variables, ce qui n'a pas été initialisé. Il est des ordures, la dernière valeur que quelqu'un (je ne sais qui) a mis les places en mémoire de l'ordinateur et qui appartiennent maintenant à mes variables.

Notez qu'il n'est pas sûr de décommenter les lignes 36 et 37 alors qu'ils tentent d'accéder au contenu pointé par AP et BP, qui n'a pas été initialisé. Au cours de cette tentative, le programme tentera d'interpréter ces valeurs comme si elles étaient des ordures variables aléatoires int adresses valides. Selon le compilateur, le système d'exploitation utilisé et de leur destin peut être sans danger ou non. Ce qui est certain, c'est que le résultat de ces lignes est imprévisible et que la source des problèmes.

Sur les lignes 41 et 42 les pointeurs sont initialisés avec les adresses des variables de type entier a et b. Depuis lors, les tirages sont répétés.

Voir les adresses des pointeurs ne changent pas, ce qui était attendu. Quelles sont ses modifier le contenu. Variables pa et pb de recevoir les adresses de A et B respectivement. Notez que le contenu des mains est exactement la valeur de l'adresse des variables A et B qui ont été donnés par l'OS au début du programme. Vérifiez auprès de l'affiche ci-dessus. Le contenu pointé par AP et BP est le même contenu et B, qui n'a pas été initialisé, ou les déchets. Cependant, contrairement à l'étape précédente, maintenant les pointeurs pointez adresses valides (les adresses de A et B) et que le contenu de a et b sont des pointeurs de la mémoire des ordures pointent maintenant sur les variables qui ont déjà été attribués.

Sur les lignes 61 et 62 les variables entières sont initialisés avec les valeurs 10 et 13, répété et estampes.

Cette fois, le coteúdos de A et B ne sont plus indésirable. Les valeurs sont bien connus. Notez qu'il n'y a pas de changement dans l'adressage des variables par rapport aux étapes précédentes, seules les valeurs.

Voir aussi que, après A et B ont été initialisés, le contenu pointé par AP et BP ont également été modifiés automatiquement. Cela se produit précisément parce pb par an et pointez sur les zones de mémoire utilisé par le PA et PB variables. Cela signifie que le contenu pointé par un pointeur peut être modifié en changeant le contenu des variables d'origine a souligné par lui. Et enfin, les lignes 81-97 montrent que l'inverse est également vrai, c'est à dire, en changeant le contenu pointé par un pointeur, modifie automatiquement le contenu des variables d'origine, ils souligné.

Il est plus facile de comprendre cette pensée dans des phrases en portugais que de regarder le code.

Pour l'instant ...

Cela a été les opérations de base avec des pointeurs. Il ya encore des choses intéressantes à voir que des pointeurs vers les fonctions, par exemple, mais qui est considérée comme un sujet plus avancé. À la suite de cette série, ce qui est prévu pour quatre postes, voir les références, les similitudes et les différences entre les pointeurs et les références et, enfin, des pointeurs vers des fonctions.

Liens

Commentaires

  • Beaux montrent le même article, je l'espère, de poursuivre les postes proxximos.
  • Pas de problème!

    Wordpress a un plugin appelé WP-Syntax , qui utilise les coulisses de la GeSHi .

    Une fois installé, vous pouvez mettre votre code dans PRE tags, ajouter l'attribut «langue» et «en ligne». La langue est évident et a une liste de langues dans la documentation et la ligne est la ligne de départ.

    Le GeSHi peut également être utilisé pour ajouter cette fonctionnalité dans les wikis.

    Astuce: Avant de copier et coller le code, remplacer tous les onglets de 4 espaces. Cela rendra le code indépendant du style appliqué aux onglets.

    Hugs
  • Fernando
    Dude, comment avez-vous m'apprendre qui vous fait après le code que vous avez publié?
    Dans une boîte, notamment, le marquage des lignes et de souligner les mots-clés de la langue?
commentaires de blog actionnés par Disqus