Punteros y referencias en C + + Parte 1

19 de abril 2009 Publicado en C / C + +

Punteros y referencias son dos conceptos importantes en la informática. Aparecen en muchos lenguajes de programación con un vestido o un poco diferente, pero el tratamiento es básicamente el mismo. En C + +, con conocimientos punteros son esenciales.

El puntero es un tipo especial de datos, variables cuyo objetivo declarado de este tipo pueden (o no) a algunos otros datos en la memoria. Una variable puntero, contiene la dirección de otra cosa en la memoria. Esta cosa puede ser una variable, constante, el inicio de un conjunto de datos, una función, entre otros.

La declaración de punteros

La declaración de un puntero se suele hacer añadiendo un * antes de que el nombre de la variable. Una notación que se utiliza mucho el pegamento * el nombre del tipo de decir simbólicamente que es la que se declara un puntero "para escribir" en lugar de una variable "puntero", pero que son equivalentes. Por ejemplo:

  / / Puntero a un int.
 ptr_num1 ; int * ptr_num1;

 / / O al menos eso.
 ptr_num2 ; int * ptr_num2;

 / / Puntero a una doble.
 ptr_double1 ; * Ptr_double1 doble;

 / / O al menos eso.
 ptr_double2 ; * Ptr_double2 doble; 

Una vez declarado, el puntero existe, tiene un tamaño y por lo tanto tiene lugar en la memoria. El tamaño de un puntero es usualmente igual al número de bits de la máquina / sistema en cuestión, por ejemplo, 4 bytes en un sistema de 32-bit.

 17 18 19 20 21 22 23 24 25 26 27 28 29 30 
  pc ; c char * pc;
 pi ; int i, * pi;
 pd ; doble d, * pd;

 / / El operador sizeof dice que el tamaño del tipo de su argumento.
 "Size of char:    " << sizeof ( c ) << " bytes" << endl ; cout <<"Tamaño de char:" <<sizeof (c) <<"bytes" <<endl;
 "Size of int:     " << sizeof ( i ) << " bytes" << endl ; cout <<"El tamaño de int:" <<sizeof (i) <<"bytes" <<endl;
 "Size of double:  " << sizeof ( d ) << " bytes" << endl ; cout <<"Tamaño del matrimonio:" <<sizeof (d) <<"bytes" <<endl;

 endl ; cout <<endl;

 "Size of char*:   " << sizeof ( pc ) << " bytes" << endl ; cout <<"Tamaño de char *:" <<sizeof (pc) <<"bytes" <<endl;
 "Size of int*:    " << sizeof ( pi ) << " bytes" << endl ; cout <<"El tamaño de int *:" <<sizeof (pi) <<"bytes" <<endl;
 "Size of double*: " << sizeof ( pd ) << " bytes" << endl ; cout <<"* Tamaño de la doble" <<sizeof (pd) <<"bytes" <<endl; 

Uso de punteros

Después de su declaración, el contenido de un puntero es un valor aleatorio, la memoria de basura, como cualquier variable. Para que sea útil hay que darle algo. Como un puntero tiene una dirección de memoria, hay que asignar una dirección válida.

  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 ; px = & x;
 y ; & Py = y;

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

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

El operador & (ampersand o signo ) antes de un nombre de variable significa "dirección", porque su nombre es "dirección".

Lo que queda de la igualdad tiene que ser capaz de mantener exactamente el mismo tipo que en el otro lado de la igualdad. Un puntero almacena una dirección. Así que para asignar una dirección a un puntero en este caso, usted necesita para obtener una dirección con el operador &.

Salvo en el caso de que no hay conversiones implícitas de tipo (por ejemplo, entre los tipos numéricos), asignar una variable a algo con un tipo diferente al suyo, provocando un error de compilación. ¡Afortunadamente!

Después de un puntero ya apunta a una dirección válida, podemos acceder a los contenidos de esta dirección con el operador * ( asterisco ), cuyo nombre formal es "la referencia del operador de".

Tenga en cuenta que el asterisco en una declaración significa "puntero a tipo" y en el contexto de la lectura o la escritura del contenido de un puntero, significa "el contenido de la dirección" o "el contenido apuntado por". También tenga cuidado de no confundir el símbolo de producto aritmético. Para evitar confusiones, recuerda que gran mesa de precedencia de los operadores , que le acaba de pasar a los ojos y se dejó caer en el olvido. Allí encontrará que el operador de referencia tiene prioridad sobre el operador de multiplicación. Y os acordaréis de que el operador de referencia es evaluado antes de que el operador de multiplicación.

  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 = (* pa) * (* pb);

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

Por eso, cuando que la prueba de algoritmos de preguntarle lo que hace que cualquiera de las últimas cinco líneas del ejemplo se dice que se multiplica el contenido apuntado por AP y BP. No hay recogida más arriba DP por ello! Y rompiendo en la vida real, si realmente lo necesita para hacer esto, va a guardar el cuarto y quinto generaciones futuras pasado excomunión , si usted elige utilizar la última línea.

Todo es posible con una variable común que puede hacer con el contenido al que apunta un puntero, ya sea para leer o escribir (a menos que esté claro que el puntero es constante, pero eso es otra conversación ...).

Direcciones y punteros

Tomemos como ejemplo el siguiente código:

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

 "Antes de qualquer atribuição: \n " ) ; printf ("Antes de cualquier misión: \ n");

 "&a  = %p \n " , & a ) ; // Endereço válido dado pelo SO. printf ("& = p \ n% a", & a) / / Válido dirección indicada por el sistema operativo.
 "&b  = %p \n " , & b ) ; // Endereço válido dado pelo SO. printf ("& b =% p \ n", & b) / / Válido dirección indicada por el sistema operativo.
 "&pa = %p \n " , & pa ) ; // Endereço válido dado pelo SO. printf ("& pa =% p \ n", y pa) / / Válido dirección indicada por el sistema operativo.
 "&pb = %p \n " , & pb ) ; // Endereço válido dado pelo SO. printf ("& pb =% p \ n", & pb); / / Válido dirección indicada por el sistema operativo.

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

 "a   = %d \n " , a ) ; // Conteúdo não inicializado (aleatório). printf ("a =% d \ n", a); / / Contenido sin inicializar (al azar).
 "b   = %d \n " , b ) ; // Conteúdo não inicializado (aleatório). printf ("b =% d" \ n, b) / / no inicializadas de contenido (al azar).
 "pa  = %p \n " , pa ) ; // Conteúdo não inicializado (aleatório). printf ("pa =% p \ n", pa) / / no inicializadas de contenido (al azar).
 "pb  = %p \n " , pb ) ; // Conteúdo não inicializado (aleatório). printf ("pb =% p \ n", pb); / / Contenido sin inicializar (al azar).

 / / Por favor, quite las líneas siguientes y volver a compilar y ejecutar.
 / / Printf ("* pa =% d \ n", * pa) / / ¿Qué es (* azar)?
 / / Printf ("* pb =% d \ n", pb *) / / ¿Qué es (* azar)?

 " \n Após as inicializações dos ponteiros: \n " ) ; printf ("\ n Después de la inicialización de los punteros: \ n");

 a ; pa = & a;
 b ; pb = & b;

 "&a  = %p \n " , & a ) ; // Mesmo endereço válido dado pelo SO. printf ("& = p \ n% a", & a) / / Par dirección válida dada por el sistema operativo.
 "&b  = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ("& b =% p \ n", & b) / / Par dirección válida dada por el sistema operativo.
 "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("& pa =% p \ n", & PA); / / misma dirección como válido por el sistema operativo.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& pb =% p \ n", & pb); / / misma dirección como válido por el sistema operativo.

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

 "a   = %d \n " , a ) ; // Conteúdo não inicializado (aleatório). printf ("a =% d \ n", a); / / Contenido sin inicializar (al azar).
 "b   = %d \n " , b ) ; // Conteúdo não inicializado (aleatório). printf ("b =% d" \ n, b) / / no inicializadas de contenido (al azar).
 "pa  = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ("pa =% p \ n", pa) / / Contenido inicializado (y una).
 "pb  = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ("pb =% p \ n", pb); / / Contenido inicializado (& b).

 "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa (*pa == a). printf ("* pa =% d \ n", * pa) / / el contenido apuntado por ap (* pa == a).
 "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (*pb == b). printf ("* pb =% d \ n", * pb) / / el contenido apuntado por pares de bases (pb == * b).

 " \n Após as inicializações dos inteiros: \n " ) ; printf ("\ n Después de la inicialización de los números enteros: \ n");

 ; a = 10;
 ; b = 13;

 "&a  = %p \n " , & a ) ; // Mesmo endereço válido dado pelo SO. printf ("& = p \ n% a", & a) / / Par dirección válida dada por el sistema operativo.
 "&b  = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ("& b =% p \ n", & b) / / Par dirección válida dada por el sistema operativo.
 "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("& pa =% p \ n", & PA); / / misma dirección como válido por el sistema operativo.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& pb =% p \ n", & pb); / / misma dirección como válido por el sistema operativo.

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

 "a   = %d \n " , a ) ; // Conteúdo inicializado (10). printf ("a =% d \ n", a); / / inicia Contenido (10).
 "b   = %d \n " , b ) ; // Conteúdo inicializado (13). printf ("b =% d" \ n, b) / / comienza Contenido (13).
 "pa  = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ("pa =% p \ n", pa) / / Contenido inicializado (y una).
 "pb  = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ("pb =% p \ n", pb); / / Contenido inicializado (& b).

 "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa (*pa == a == 10). printf ("* pa =% d \ n", * pa) / / el contenido apuntado por ap (* pa == a == 10).
 "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (*pb == b == 13). printf ("* pb =% d \ n", pb *) / / el contenido apuntado por pb pb * (b == == 13).

 " \n Alterando os valores através dos ponteiros: \n " ) ; printf ("\ n Cambio de valores a través de punteros: \ n");

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

 "&a  = %p \n " , & a ) ; // Mesmo endereço válido dado pelo SO. printf ("& = p \ n% a", & a) / / Par dirección válida dada por el sistema operativo.
 "&b  = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ("& b =% p \ n", & b) / / Par dirección válida dada por el sistema operativo.
 "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("& pa =% p \ n", & PA); / / misma dirección como válido por el sistema operativo.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& pb =% p \ n", & pb); / / misma dirección como válido por el sistema operativo.

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

 "a   = %d \n " , a ) ; // Conteúdo inicializado (a == *pa ==  7). printf ("a =% d \ n", a); / / Contenido inicializado (* pa == a == 7).
 "b   = %d \n " , b ) ; // Conteúdo inicializado (b == *pb == 42). printf ("b =% d" \ n, b) / / Contenido inicializado (b == == pb * 42).
 "pa  = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ("pa =% p \ n", pa) / / Contenido inicializado (y una).
 "pb  = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ("pb =% p \ n", pb); / / Contenido inicializado (& b).

 "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa ( 7). printf ("* pa =% d \ n", * pa) / / Contenido nombrado por pa (7).
 "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (42). printf ("* pb =% d \ n", pb *) / / el contenido apuntado por pb (42). 

Líneas 18:19 respectivamnete declarar dos enteros y dos punteros a enteros.

Las líneas 23-26 muestran las direcciones de mis variables. Estas direcciones fueron dadas por el sistema operativo y son fijos, mientras que estas variables existen. Una variable no cambia de dirección durante el programa, pero puede cambiar entre una ejecución y otro. ¿Quién define lo que tratan es el sistema operativo en el momento de la ejecución del programa. El compilador sabe que los bytes x son necesarios para cada variable, y de la interpretación (estilo) que el programa le dará a ese espacio.

Las líneas 30-33 muestran el contenido de estas variables, que no se ha inicializado. Es una basura, el último valor que alguien (no sé quién) poner esos lugares en la memoria del ordenador y que ahora pertenecen a mi variables.

Tenga en cuenta que no es seguro que descomentar las líneas 36 y 37 que tratan de acceder al contenido apuntado por AP y BP, que no se ha inicializado. Durante este intento, el programa tratará de interpretar esos valores como si fueran basura variables aleatorias int direcciones válidas. Dependiendo del compilador, el sistema operativo utilizado y su destino puede ser inofensivo o no. Lo que es seguro es que el resultado de estas líneas es impredecible y segura fuente de problemas.

En las líneas 41 y 42 punteros son inicializados con las direcciones de las variables de tipo entero a y b. Desde entonces, las huellas se repiten.

Ver las direcciones de los punteros no cambian, lo que se esperaba. ¿Cuáles son sus contenidos el cambio. Variables y pa pb recibir las direcciones de ayb, respectivamente. Tenga en cuenta que el contenido de las manos es exactamente el valor de dirección de las variables A y B que fueron dadas por el sistema operativo al inicio del programa. Consulte con las impresiones anteriores. El contenido al que apunta ap y bp es el mismo contenido y b, que no se ha inicializado, o basura. Sin embargo, a diferencia del paso anterior, ahora los punteros apuntan a direcciones válidas (las direcciones de a y b), y que el contenido de A y B son los punteros de memoria de basura ahora apuntan a las variables que ya han sido asignados.

En las líneas 61 y 62 las variables enteras se inicializan con los valores 10 y 13, repite una y grabados.

Esta vez el coteúdos de A y B ya no son basura. Los valores son adecuadamente conocidos. Tenga en cuenta que no hay ningún cambio en el direccionamiento de las variables relativas a los pasos anteriores, sólo los valores.

Véase también que después de a y b se han inicializado, el contenido apuntado por AP y BP han variado de forma automática. Esto ocurre precisamente porque pa pb y apuntan a las áreas de memoria utilizada por el mismo pa variables y pb. Esto significa que el contenido al que apunta un puntero se puede modificar cambiando el contenido de las variables originales señalado por él. Y, por último, las líneas 81-97 muestran que lo contrario también es verdadero, es decir, cambiar el contenido apuntado por un puntero, automáticamente cambia el contenido de las variables originales, señalaron.

Es más fácil entender esta forma de pensar en frases en portugués que mirando el código.

Por ahora ...

Esta fue la base de operaciones con punteros. Todavía hay cosas interesantes por ver como punteros a funciones, por ejemplo, pero que se considera un tema más avanzado. A raíz de esta serie, que está prevista para cuatro puestos, ver referencias, similitudes y diferencias entre los punteros y referencias y, finalmente, los punteros a funciones.

Enlaces

Comentarios

  • Bellas muestran el mismo artículo, espero que siga los puestos proxximos.
  • No hay problema!

    Wordpress tiene un plugin llamado WP-Sintaxis , que utiliza detrás de las escenas de la GeSHi .

    Una vez instalado usted puede poner su código en las etiquetas PRE, añadiendo el atributo "lenguaje" y "línea". El lenguaje se explica por sí y tiene una lista de idiomas en la documentación y la línea es la línea de salida.

    El GeSHi también se puede utilizar para agregar esta capacidad en los wikis.

    Consejo: Antes de copiar y pegar el código, reemplace todas las pestañas por 4 espacios. Esto hará que el código independiente del estilo aplicado a las pestañas.

    Abrazos
  • Fernando
    Amigo, ¿cómo has enseñarme que te hace publicar el código a medida que envió?
    Dentro de una caja especial, que marca las líneas y poner de relieve las palabras de la lengua?
blog alimentado por los comentarios Disqus