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 básicamente el tratamiento es el mismo. En C + +, con punteros habilidades son esenciales.

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

La declaración de punteros

La declaración de un puntero se realiza generalmente mediante la adición de un * antes de que el nombre de variable. Una anotación utiliza mucho la cola * El nombre del tipo que decir que simbólicamente se declara un "apuntador del tipo" en lugar de una variable "puntero", pero son equivalentes. Por ejemplo:

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

 / / O así.
 ptr_num2 ; int * ptr_num2;

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

 / / O así.
 ptr_double2 ; ptr_double2 doble *; 

Una vez declarado, el puntero es, es de tamaño y por lo tanto tiene lugar en la memoria. El tamaño de un puntero es generalmente igual a la cantidad de bits de la máquina / sistema en cuestión, por ejemplo 4 bytes en un 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 ; char c, * pc, int i, * pi, Double D, * pd / / El operador sizeof dice que el tamaño del tipo de su argumento. tribunal << "Tamaño de char:" <<sizeof (c) << " bytes "<<endl <<" Tamaño de int: "<<sizeof (i) <<" bytes "<<endl <<" Tamaño de la doble: "<<sizeof (d) <<" bytes " <<endl <<endl << "Tamaño de char *:" <<sizeof (PC) << "bytes" <<endl << "Tamaño de int *:" <<sizeof (pi) << "bytes" <<endl << "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, los residuos de la memoria, como cualquier otra variable. Para que sea útil hay que darle algo. Como un puntero tiene una dirección de memoria, le asignamos 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 ; * px, int * py;

 ; x = 13;
 ; y = 10;

 x ; px = & x;
 y ; & Py = y;

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

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

El operador & (ampersand o comercial) antes de que el nombre de un medio variable "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 está al otro lado de la igualdad. Un puntero de una dirección de tiendas. Así que para asignar una dirección a un puntero, en este caso, usted debe obtener una dirección con el operador &.

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

Después de un puntero tiene que apuntar a una dirección válida, podemos acceder al contenido de esa dirección con el operador * (asterisco), cuyo nombre oficial es "operador de referencia.

Tenga en cuenta que el asterisco en una declaración significa "puntero a tipo" en el contexto de leer o escribir el contenido de un puntero, significa "el contenido de la dirección" o "el contenido al que apunta." También tenga cuidado de no confundir con el símbolo de la aritmética del producto. Para evitar confusiones, recuerda que gran mesa de precedencia de los operadores, que acaba de pasar a los ojos y se dejó caer en el olvido. Aquí usted encontrará que el operador de referencia tiene prioridad sobre el operador de multiplicación. Una vez que ha hecho usted recordará 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 ** BP;
 * pa ) * ( * pb ) ; c = (* PA) * (* pb);

 "Valor da Pegadinha: " << c << endl ; cout << "Valor Anécdota:" <<c <<endl; 

Así que cuando las pruebas de los algoritmos nos preguntamos ¿qué hace que cualquiera de los últimos 5 líneas del ejemplo se dice que se multiplica el contenido apuntado por PA y PB. Tendrá que recoger PD por esto! Y de última hora en la vida real, si realmente necesitas hacer esto, guardar sus 4 generaciones pasadas y futuras, de 5 de excomunión, si usted elige utilizar la última línea.

Todo lo que puedes hacer con una variable común que puede hacer con el contenido apuntado por un puntero, ya sea de lectura o escritura (a menos que esté claro que el puntero es constante, pero esa es otra ...). Rant

Direcciones y punteros

Tomemos por 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 ( "& a =% p \ n", & a) / / Valida la dirección dada por el sistema operativo.
 "&b  = %p \n " , & b ) ; // Endereço válido dado pelo SO. printf ( "& b =% p \ n", & b) / / Valida la dirección dada por el sistema operativo.
 "&pa = %p \n " , & pa ) ; // Endereço válido dado pelo SO. printf ( "& pa =% p \ n", & PA) / / Valida la dirección dada por el sistema operativo.
 "&pb = %p \n " , & pb ) ; // Endereço válido dado pelo SO. printf ( "& pb =% p \ n", y PB) / / Dirección de validación dada por el sistema operativo.

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

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

 / / Por favor, elimine las líneas siguientes, volver a compilar y ejecutar.
 / / Printf ( "* pa =% d \ n", * PA) / / ¿Cuál será (random *)?
 / / Printf ( "* pb =% d \ n", * pb); / / ¿Qué es (random *)?

 " \n Após as inicializações dos ponteiros: \n " ) ; printf ( "\ 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 ( "& a =% p \ n", & a); / / dirección Incluso válido dado por el sistema operativo.
 "&b  = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ( "& b =% p \ n", & b) / / dirección Incluso válido dado por el sistema operativo.
 "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ( "& pa =% p \ n", & PA); / / dirección Incluso válido dado por el sistema operativo.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ( "& pb =% p \ n", y PB); / / dirección Incluso válido dado por el sistema operativo.

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

 "a   = %d \n " , a ) ; // Conteúdo não inicializado (aleatório). printf ( "a =% d \ n", a); / / Contenido no inicializada (al azar).
 "b   = %d \n " , b ) ; // Conteúdo não inicializado (aleatório). printf ( "b =% d \ n", b) / / Contenido no inicializada (al azar).
 "pa  = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ( "p =% anual \ n", pa) / / Contenido inicializa (& A).
 "pb  = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ( "p = pb% \ n", pb); / / Contenido inicializa (& b).

 "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa (*pa == a). printf ( "* pa =% d \ n", * PA); / / Contenido nombrados por año (* pa == a).
 "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (*pb == b). printf ( "* pb =% d \ n", * pb); / / el contenido apuntado por pb (* pb == b).

 " \n Após as inicializações dos inteiros: \n " ) ; printf ( "\ 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 ( "& a =% p \ n", & a); / / dirección Incluso válido dado por el sistema operativo.
 "&b  = %p \n " , & b ) ; // Mesmo endereço válido dado pelo SO. printf ( "& b =% p \ n", & b) / / dirección Incluso válido dado por el sistema operativo.
 "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ( "& pa =% p \ n", & PA); / / dirección Incluso válido dado por el sistema operativo.
 "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ( "& pb =% p \ n", y PB); / / dirección Incluso válido dado por el sistema operativo.

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

 "a   = %d \n " , a ) ; // Conteúdo inicializado (10). printf ( "a =% d \ n", a); / / botas de contenido (10).
 "b   = %d \n " , b ) ; // Conteúdo inicializado (13). printf ( "b =% d \ n", b) / / botas de contenido (13).
 "pa  = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ( "p =% anual \ n", pa) / / Contenido inicializa (& A).
 "pb  = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ( "p = pb% \ n", pb); / / inicio de contenido (& b).

 "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa (*pa == a == 10). printf ( "* pa =% d \ n", * PA); / / Contenido nombrados por año (* 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 los valores a través de punteros: \ n");

 7 ; * Pa = 7;
 42 ; * Pb = 42;

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

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

 "a   = %d \n " , a ) ; // Conteúdo inicializado (a == *pa ==  7). printf ( "a =% d \ n", a); / / inicio de contenido (a == == * PA 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 ( "p =% anual \ n", pa) / / Contenido inicializa (& A).
 "pb  = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ( "p = pb% \ n", pb); / / Contenido inicializa (& 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). 

La línea de 18 y 19 que declaró respectivamnete dos y dos punteros a enteros.

Las líneas 23 a 26 muestra la dirección de mi variables. Estas direcciones fueron dadas por el sistema operativo y son fijos mientras que las variables existentes. Una variable no cambia de dirección durante el programa, pero puede cambiar entre una ejecución y otra. ¿Quién define lo que la dirección es el sistema operativo en el momento del programa. El compilador sólo sabe que X bytes son necesarios para cada variable, y de la interpretación (estilo) que el programa dará a este espacio.

Líneas 30 a 33 muestran el contenido de estas variables, que no han sido inicializadas. Es una basura, el último valor que alguien (no sé quién) poner los lugares en memoria de la computadora y que ahora pertenecen a mi variables.

Tenga en cuenta que es seguro que descomentar las líneas 36 y 37 que tratan de acceder al contenido apuntado por PA y PB, que no se ha inicializado. Durante este intento, el programa va a tratar de interpretar los valores de la basura al azar como si se trata de variables int válida. Dependiendo del compilador, el sistema operativo utilizado y su destino puede ser inofensivo o no. Lo cierto es que el resultado de estas líneas es impredecible y segura fuente de problemas.

En las líneas 41 y 42, los punteros se inicializan con las direcciones de las variables enteras A y B. Desde entonces se repiten las impresiones.

Tenga en cuenta que las direcciones de los punteros no cambian, lo que se esperaba. ¿Qué cambios son su contenido. Variables de PA y PB recibir las direcciones de A y B, respectivamente. Tenga en cuenta que el contenido de las manos es exactamente el valor de la 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 apuntado por PA y PB es el contenido mismo de A y B, que no se ha inicializado, es decir, basura. Sin embargo, a diferencia del paso anterior, ahora los punteros a las 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 han sido asignados.

En las líneas 61 y 62 de las variables enteras se inicializan con los valores 10 y 13, y las estampas repetirse.

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

Véase también que, después de A y B han sido inicializado, el contenido apuntado por PA y PB también se cambiará automáticamente. Esto sucede precisamente porque la Autoridad Palestina y el punto pb a las mismas áreas de memoria utilizada por la Autoridad Palestina variables y PB. Esto significa que el contenido apuntado por un puntero puede ser modificado por cambiar el contenido de las variables originales señalado por él. Y, por último, las líneas 81 a 97 muestran que el contrario también es cierto, es decir, cambiar el contenido apuntado por un puntero, cambia automáticamente el contenido de las variables originales señalado por ellos.

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

Por ahora ...

Esta fue la operación básica con punteros. Todavía hay cosas interesantes para ser vistos como punteros a funciones, por ejemplo, pero que se considera un tema más avanzado. A raíz de esta serie, que está previsto para 4 puestos, véanse las referencias, las diferencias y similitudes entre los punteros y las referencias y, finalmente, los punteros a funciones.

Enlaces

Comentarios

5 Respuestas a "punteros y referencias en C + + Part 1"

  1. [...] Con este intento de serie de posts sobre los punteros y referencias, que comenzó a hablar de los punteros, hoy en día hablar de [...]

  2. [...] [...] Pointeiros y Referencias

  3. [...] Primer puesto de esta serie, hablamos un poco acerca de los punteros. En el segundo caso, hablamos de referencias. Hoy nos centraremos en la relación íntima (ui!) Entre apuntadores y [...]

  4. Fernando el 26 de diciembre 2009 18:50

    Amigo, tienes que enseñarme cómo se hace cargo el código a medida que los envió?
    Dentro de una caja en particular, el marcado de las líneas y poner de relieve las palabras clave del lenguaje?

  5. BLAB 28 de diciembre de 2009 08:48

    No hay problema!

    El Wordpress tiene un plugin llamado WP-sintaxis, que usa detrás de las escenas de la GeSHi.

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

    El GeSHi también puede ser explotado para añadir esta característica en wikis.

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

    Abrazos

Deje una contestación




Powered by WP Hashcash