Pointeurs et références en C + + Partie 1

19 avril 2009 · Posted in C / C + +

Pointeurs et références sont deux concepts très importants en 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 + +, les pointeurs sont des compétences essentielles.

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

Pointeurs Déclarer

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

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

 / / Ou si.
 ptr_num2 ; int * ptr_num2;

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

 / / Ou si.
 ptr_double2 ; * doubler ptr_double2; 

Après a déclaré, le pointeur existe, et il est dimensionné en conséquence prend place dans la mémoire. La taille d'un pointeur est généralement égal au nombre de bits du système de machine /, par exemple quatre octets dans un système à 32 bits.

  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 ; char c, * pc, int i, * pi, double d, pd * / / L'opérateur sizeof dit la taille du type de son argument cout << "Taille des caractères:". << sizeof (c) << " octets "<< endl; cout <<" Taille de int: "<< sizeof (i) <<" octets "<< endl; cout <<" Taille du double: "<< sizeof (d) <<" octets " << endl; cout << endl; cout << "Taille du char *:" << sizeof (cp) << "octets" << endl; cout << "Taille des int *:" << sizeof (pi) << "octets" << endl; cout << "Taille de la double *" << sizeof (pd) << "octets" << endl; 

Utilisation de pointeurs

Après sa déclaration, le contenu d'un pointeur est une valeur aléatoire, les déchets de la mémoire, comme n'importe quelle variable. Pour être utile, elle doit lui donner quelque chose. Comme un pointeur stocke une adresse mémoire, nous avons besoin de 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 * px, py *;

 ; x = 13;
 ; y = 10;

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

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

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

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

Qu'est-ce qui reste de l'égalité doit être capable de stocker exactement le même type comme c'est de l'autre côté de l'égalité. Un pointeur contient une adresse. Donc, pour attribuer une adresse à un pointeur dans ce cas, vous avez besoin pour obtenir une adresse avec l'opérateur &.

Sauf dans le cas où il ya des conversions de type implicites (comme par exemple entre les types numériques), assigner une variable à quelque chose avec un type différent du vôtre, provoquer une erreur de compilation. Heureusement!

Une fois que vous avez un pointeur pointant vers une adresse valide, nous pouvons accéder au contenu de cette adresse avec l'opérateur * ( astérisque ), dont le nom officiel est «de référence de l'opérateur."

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 "adresse de contenu" ou "contenu pointé par". Aussi soyez prudent de ne pas être confondu avec le symbole de produit arithmétique. Pour éviter toute confusion, n'oubliez pas que le tableau énorme de priorité des opérateurs , qui vous venez de passer de l'œil et est tombé dans l'oubli. Ici vous trouverez que l'opérateur de référence a la priorité sur l'opérateur de multiplication. Fait que vous vous rappellerez que l'opérateur de référence est évaluée avant 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 = * pa ** pb;
 pa * * pb ; c = * pa ** pb;
 pa * * pb ; c = * pa ** pb;
 pa ** pb ; c = * pa ** pb;
 * pa ) * ( * pb ) ; = C (* tr) * (* pb);

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

Ainsi, lorsque que tester des algorithmes de vous demander ce qui fait l'une quelconque des cinq dernières lignes de l'exemple, me direz-vous qu'il multiplie le contenu pointé par PA et PB. Plus besoin d'obtenir DP pour elle! Et la rupture dans la vie réelle, si vous avez vraiment besoin de faire cela, vous sauverez vos 4 générations passées et futures de 5 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

Prenez 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, b;
 pa, * pb ; int * pa, pb *;

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

 "&a = %p \n " , & a ) ; // Endereço válido dado pelo SO. printf ("& a =% p \ n", & a) / adresse / Valable donnée par le SO.
 "&b = %p \n " , & b ) ; // Endereço válido dado pelo SO. printf ("& b =% p \ n", et b) l'adresse / / Valide donnée par le SO.
 "&pa = %p \n " , & pa ) ; // Endereço válido dado pelo SO. printf ("& ap =% p \ n", & pa) / adresse / Valable donnée par le SO.
 "&pb = %p \n " , & pb ) ; // Endereço válido dado pelo SO. printf ("& sc =% p \ n", & pb); l'adresse / / Valide donnée par le SO.

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

 "a = %d \n " , a ) ; // Conteúdo não inicializado (aleatório). printf ("un =% d \ n", a) / / Contenu non initialisée (au hasard).
 "b = %d \n " , b ) ; // Conteúdo não inicializado (aleatório). printf ("b =% d \ n", b) / / Contenu non initialisée (au hasard).
 "pa = %p \n " , pa ) ; // Conteúdo não inicializado (aleatório). printf ("% pa = p \ n", pa) / / Contenu non initialisée (au hasard).
 "pb = %p \n " , pb ) ; // Conteúdo não inicializado (aleatório). printf ("% sc = p \ n", pb); / / Contenu non initialisée (au hasard).

 / / Essayez de décommenter les lignes ci-dessous, recompiler et exécuter.
 / / Printf ("* pa =% d \ n", * pa) / / Qu'est-ce que (* aléatoire)?
 / / Printf ("* pb =% d \ n", * pb) / / Qu'est-ce que (* aléatoire)?

 " \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 ("& a =% p \ n", & a) / / Même adresse valide donnée par le SO.
 "&b = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ("& b =% p \ n", & 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 ("& ap =% p \ n", & pa) / / Même adresse valide donnée par le SO.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& sc =% p \ n", & pb); / / Même adresse valide donnée par le SO.

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

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

 "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa (*pa == a). printf ("* pa =% d \ n", * par an); / / Contenu nommé par an (pa == * a).
 "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (*pb == b). printf ("* pb =% d \ n", * pb) / / pointée par le contenu pb (pb * == b).

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

 ; a = 10;
 ; b = 13;

 "&a = %p \n " , & a ) ; // Mesmo endereço válido dado pelo SO. printf ("& a =% p \ n", & a) / / Même adresse valide donnée par le SO.
 "&b = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ("& b =% p \ n", & b) / / Même adresse valide donnée par le SO.
 "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("& ap =% p \ n", & pa) / / Même adresse valide donnée par le SO.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& sc =% p \ n", & pb); / / Même adresse valide donnée par le SO.

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

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

 "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa (*pa == a == 10). printf ("* pa =% d \ n", * par an); / / Contenu ap pointé par (* pa == a == 10).
 "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (*pb == b == 13). printf ("* pb =% d \ n", * pb) / / pointée par le contenu pb (pb * == b == 13).

 " \n Alterando os valores através dos ponteiros: \n " ) ; printf ("\ n Modification des valeurs par l'intermédiaire des pointeurs: \ n");

 7 ; * Pa = 7;
 42 ; * Bp = 42;

 "&a = %p \n " , & a ) ; // Mesmo endereço válido dado pelo SO. printf ("& a =% p \ n", & a) / / Même adresse valide donnée par le SO.
 "&b = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ("& b =% p \ n", & b) / / Même adresse valide donnée par le SO.
 "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("& ap =% p \ n", & pa) / / Même adresse valide donnée par le SO.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& sc =% p \ n", & pb); / / Même adresse valide donnée par le SO.

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

 "a = %d \n " , a ) ; // Conteúdo inicializado (a == *pa == 7). printf ("un =% 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é (* pb == b == 42).
 "pa = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ("% pa = p \ n", pa) / / initialisé contenu (et a).
 "pb = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ("% sc = p \ n", pb) / / initialisé contenu (& b).

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

Les lignes 18 et 19 respectivamnete déclare deux entiers et deux pointeurs vers des entiers.

Lignes 23-26 indiquer 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 lors de l'exécution du programme, mais il peut changer d'une mise en œuvre à l'autre. Qui définit ce que l'adresse est le système d'exploitation au niveau du programme d'exécution. Le compilateur sait seulement que x octets sont nécessaires pour chaque variable, et quelle interprétation (type) que le programme donnera cet espace.

Lignes 30-33 afficher le contenu de ces variables, ce qui n'a pas été initialisées. C'est ordures, la dernière valeur que quelqu'un (pas sûr de qui) mettre ces endroits en mémoire de l'ordinateur et qui appartiennent maintenant à mes variables.

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

Dans les lignes 41 et 42 pointeurs sont initialisés avec les adresses des variables entières a et b. De là, les impressions sont répétées.

Voir les adresses des pointeurs qui ne changent pas, ce qui était attendu. Quels sont son contenu change. Les variables PA et PB sont donnés traite a et b, respectivement. Noter que la teneur des mains est exactement la valeur d'adresse des variables a et b qui ont été proposés par le système d'exploitation au début du programme. Renseignez-vous auprès des tirages précédents. La teneur en pointée par PA et PB est la même contenu de a et b, qui n'ont pas été initialisé, par exemple les déchets. Cependant, contrairement à l'étape précédente, maintenant le point de pointeurs vers des adresses valides (adresses et b) et que le contenu de a et b sont des déchets de la mémoire, les pointeurs pointent maintenant à des variables qui ont déjà été alloués.

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

Cette fois, les coteúdos de a et b ne sont plus trash. Les valeurs sont bien connus. Notez qu'il n'y a pas de changement dans l'adressage des variables en relation avec les étapes précédentes, seules les valeurs.

Voir aussi qu'au bout d'un et b ont été initialisés, le contenu pointé par PA et PB ont également été modifiées automatiquement. Ce qui se passe précisément parce que le point PA et PB les mêmes zones mémoires utilisées par les variables PA et PB. Cela signifie que le contenu pointé par un pointeur peut être modifié en changeant le contenu des variables d'origine indiquées par lui. Et enfin, les lignes 81-97 montrent l'inverse est également vrai, c'est à dire, changer le contenu indiqué par un pointeur, de modifier automatiquement le contenu des variables d'origine indiquées par eux.

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

Pour l'instant ...

Ce sont les opérations de base avec des pointeurs. Il ya encore des choses intéressantes à être considérées comme des pointeurs vers des fonctions, par exemple, mais qui est considérée comme un sujet plus avancé. Suite à cette série, qui est prévu pour 4 messages, voir les références, les différences et les similitudes entre les pointeurs et les références et, enfin, des pointeurs vers des fonctions.

Liens

Commentaires

  • pointeurs et les références http://blog.blabos.org/2009/05/ponteiros-e-referencias-em-c-parte-2/~~HEAD=NNS en C + + Partie 2: Blog pour les Blabos Blebe

    [...] Avec cette tentative de série de messages sur les pointeurs et les références, les pointeurs qui ont commencé à parler aujourd'hui de discuter [...]

  • http://www.caloni.com.br/blog/archives/ultimas-pesquisas-na-blogosfera-nacional Caloni.com.br »Blog Archive recherche récente» dans la blogosphère nationale

    [...] Et les références Pointeiros [...]

  • Pointeurs et tableaux: http://blog.blabos.org/2009/05/ponteiros-e-arrays/~~HEAD=NNS Blabos blog de ​​Blebe

    [...] Première de cette série, nous avons parlé un peu de pointeurs. Dans le second, on parle de références. Aujourd'hui, nous discutons de la relation intime (ui!) entre les pointeurs et [...]

  • Fernando

    Mec, tu as à me montrer comment faire pour afficher le code que vous avez posté?
    L'intérieur d'une boîte de mettre en évidence, le marquage des lignes et souligner les mots clés de la langue?

  • Fernando

    Mec, tu as à me montrer comment faire pour afficher le code que vous avez posté?
    L'intérieur d'une boîte de mettre en évidence, le marquage des lignes et souligner les mots clés de la langue?

  • blabos http://blabos.pip.verisignlabs.com/~~HEAD=NNS

    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 les balises PRE, ajout de l'attribut "langue" et "en ligne". La langue est auto-explicatif et avoir la liste des langues dans la documentation et la ligne est la ligne de départ.

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

    Astuce: Avant de vous copiez et collez le code, remplacer tous les onglets de 4 espaces. Cela rendra le code indépendant du style appliqué à l'onglet.

    Étreintes

  • blabos http://blabos.pip.verisignlabs.com/~~HEAD=NNS

    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 les balises PRE, ajout de l'attribut "langue" et "en ligne". La langue est auto-explicatif et avoir la liste des langues dans la documentation et la ligne est la ligne de départ.

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

    Astuce: Avant de vous copiez et collez le code, remplacer tous les onglets de 4 espaces. Cela rendra le code indépendant du style appliqué à l'onglet.

    Étreintes

  • Bruno http://www.brunodanielmarinho.com

    Beaux montrent le même article, j'espère continuer les messages proxximos.

  • Bruno http://www.brunodanielmarinho.com

    Beaux montrent le même article, j'espère continuer les messages proxximos.

blog comments powered by Disqus