Punteros y referencias en C + + Parte 1
Punteros y referencias son dos conceptos muy 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 + +, los punteros son habilidades esenciales.
Puntero es un tipo especial de datos, cuyas variables pueden declaradas como tales en (o no) a algunos otros datos en la memoria. Una variable de tipo puntero contiene la dirección de otra cosa en la memoria. Esto puede ser cualquier variable, constante, el comienzo de un conjunto de datos, una función, entre otros.
Punteros declarar
La declaración de un puntero se realiza habitualmente mediante la adición de un * antes de que el nombre de la variable. Una anotación muy utilizado * para pegar el nombre del tipo que dicen que estamos declarando simbólicamente un "puntero de tipo" en lugar de una "variable de puntero", pero son equivalentes. Por ejemplo:
/ / Puntero a un int. ptr_num1 ; int * ptr_num1; / / O al menos eso. ptr_num2 ; int * ptr_num2; / / Puntero a un doble. ptr_double1 ; doble * ptr_double1; / / O al menos eso. ptr_double2 ; doble * ptr_double2;
Una vez declarado, el puntero existe, tiene una longitud y por lo tanto se lleva a cabo en la memoria. El tamaño de un puntero es usualmente igual al número de bits de la máquina / instalación, por ejemplo 4 bytes en un sistema de 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, doble d, pd * / / El operador sizeof dice que el tamaño del tipo de su argumento cout <<"El tamaño de la charla:". <<sizeof (c) <<" bytes "<<endl; cout <<" El tamaño de int: "<<sizeof (i) <<" bytes "<<endl; cout <<" El tamaño del doble: "<<sizeof (d) <<" bytes " <<endl; cout <<endl; cout <<"El tamaño de char *:" <<sizeof (cp) <<"bytes" <<endl; cout <<"El tamaño de * int:" <<sizeof (pi) <<"bytes" <<endl; cout <<"* Tamaño de la doble:" <<sizeof (pd) <<"bytes" <<endl; |
El uso de punteros
Después de su declaración, el contenido de un puntero es un valor aleatorio, pérdida de memoria, como cualquier otra variable. Para que sea útil es necesario asignar algo a ella. Como un puntero almacena una dirección de memoria, tenemos 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 ; & X = px; y ; & Y = py; 42 ; * Px = 42; py ) ++ ; (* Py) + +; * px << endl ; cout <<* px <<endl; * py << endl ; cout <<* py <<endl; ( * px ) * ( * py ) << endl ; cout <<(* px) * (* py) <<endl; |
El operador & (ampersand o signo ) antes de un nombre de variable significa "la 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án en el otro lado de la igualdad. Un puntero tiene una dirección. Así que para asignar una dirección a un puntero, en este caso, debe obtener una dirección con el operador &.
Excepto 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 de la suya, porque un error de compilación. ¡Afortunadamente!
Una vez que haya un apuntador que apunta a una dirección válida, podemos acceder al contenido de esa dirección con el operador * ( asterisco ), cuyo nombre formal es "de referencia del operador."
Tenga en cuenta que el asterisco en una declaración significa "puntero de tipo" y en el contexto de la lectura o escritura de los contenidos de un puntero, significa "el contenido de la dirección" o "designados por el contenido." También tenga cuidado de no confundir con el símbolo de producto aritmético. 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. Hecho que se le recuerde que el operador de referencia se evalúa 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; |
Así que cuando la prueba de algoritmos de pedir lo que hace que cualquiera de los últimos cinco líneas del ejemplo, que va a decir que se multiplica el contenido señalado por PA y PB. No hay más necesidad de conseguir DP por ello! Y la ruptura en la vida real, si usted realmente necesita para hacer esto, va a guardar el 4 generaciones pasadas y futuras de 5 excomunión , si usted elige utilizar la última línea.
Todo lo que puedes hacer con un elemento común que puede hacer con el contenido apuntado por un puntero, ya sea leyendo o escribiendo (a menos que esté claro que el puntero es constante, pero esa es otra diatriba ...).
Direcciones y punteros
Tome 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 tarea: \ n"); "&a = %p \n " , & a ) ; // Endereço válido dado pelo SO. printf ("& a =% p \ n", & a) / / dirección válida dada por el sistema operativo. "&b = %p \n " , & b ) ; // Endereço válido dado pelo SO. printf ("& b =% p \ n", & b) / / Dirección de validación dada por el sistema operativo. "&pa = %p \n " , & pa ) ; // Endereço válido dado pelo SO. printf ("& ap =% p \ n", y pa), / / dirección como válida por el sistema operativo. "&pb = %p \n " , & pb ) ; // Endereço válido dado pelo SO. printf ("& sc =% p \ n", & 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 sin inicializar (al azar). "b = %d \n " , b ) ; // Conteúdo não inicializado (aleatório). printf ("b =% d \ n", b) / / Contenido sin inicializar (al azar). "pa = %p \n " , pa ) ; // Conteúdo não inicializado (aleatório). printf ("pa =% p \ n", pa) / / Contenido sin inicializar (al azar). "pb = %p \n " , pb ) ; // Conteúdo não inicializado (aleatório). printf ("sc =% p \ n", pb) / / Contenido sin inicializar (al azar). / / Prueba descomentar las siguientes líneas, volver a compilar y ejecutar. / / Printf ("* pa =% d \ n", * año) / / ¿Qué es (* al azar)? / / Printf ("* pb =% d \ n", * pb) / / ¿Qué es (* al 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 ("& a =% p \ n", & a) / / Incluso 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) / / Incluso dirección válida dada por el sistema operativo. "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("& ap =% p \ n", y pa) / / Incluso dirección válida dada por el sistema operativo. "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& sc =% p \ n", & pb) / / Incluso dirección válida 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 sin inicializar (al azar). "b = %d \n " , b ) ; // Conteúdo não inicializado (aleatório). printf ("b =% d \ n", b) / / Contenido sin inicializar (al azar). "pa = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ("pa =% p \ n", pa) / / Contenido inicializada (y uno). "pb = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ("sc =% p \ n", pb) / / comienza de contenido (& b). "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa (*pa == a). printf ("* pa =% d \ n", * año) / / Contenido nombrado por año (pa == * a). "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (*pb == b). printf ("* pb =% d \ n", * pb) / / a la que apunta Contenido pb (* 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 ("& a =% p \ n", & a) / / Incluso 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) / / Incluso dirección válida dada por el sistema operativo. "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("& ap =% p \ n", y pa) / / Incluso dirección válida dada por el sistema operativo. "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& sc =% p \ n", & pb) / / Incluso dirección válida dada por el sistema operativo. " \n " ) ; printf ("\ n"); "a = %d \n " , a ) ; // Conteúdo inicializado (10). printf ("a =% d \ n", a) / / Contenido inicializado (10). "b = %d \n " , b ) ; // Conteúdo inicializado (13). printf ("b =% d \ n", b) / / inicializa contenido (13). "pa = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ("pa =% p \ n", pa) / / Contenido inicializada (y uno). "pb = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ("sc =% p \ n", pb) / / comienza de contenido (& b). "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa (*pa == a == 10). printf ("* pa =% d \ n", * año) / / contenido de AP señaló por (* p == a == 10). "*pb = %d \n " , * pb ) ; // Conteúdo apontado por pb (*pb == b == 13). printf ("* pb =% d \ n", * pb) / / a la que apunta Contenido 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 ; * Bp = 42; "&a = %p \n " , & a ) ; // Mesmo endereço válido dado pelo SO. printf ("& a =% p \ n", & a) / / Incluso 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) / / Incluso dirección válida dada por el sistema operativo. "&pa = %p \n " , & pa ) ; // Mesmo endereço válido dado pelo SO. printf ("& ap =% p \ n", y pa) / / Incluso dirección válida dada por el sistema operativo. "&pb = %p \n " , & pb ) ; // Mesmo endereço válido dado pelo SO. printf ("& sc =% p \ n", & pb) / / Incluso dirección válida dada por el sistema operativo. " \n " ) ; printf ("\ n"); "a = %d \n " , a ) ; // Conteúdo inicializado (a == *pa == 7). printf ("a =% d \ n", a) / / Contenido inicializado (* p == a == 7). "b = %d \n " , b ) ; // Conteúdo inicializado (b == *pb == 42). printf ("b =% d \ n", b) / / Contenido inicializado (* pb == == b 42). "pa = %p \n " , pa ) ; // Conteúdo inicializado (&a). printf ("pa =% p \ n", pa) / / Contenido inicializada (y uno). "pb = %p \n " , pb ) ; // Conteúdo inicializado (&b). printf ("sc =% p \ n", pb) / / comienza de contenido (& b). "*pa = %d \n " , * pa ) ; // Conteúdo apontado por pa ( 7). printf ("* pa =% d \ n", * año) / / ap señalado por el contenido (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.
Líneas 23 a 26 muestran las direcciones de mis variables. Estas direcciones fueron dadas por el sistema operativo y mientras que estas variables se fijan allí. Una variable no cambia la dirección en la ejecución del programa, pero puede cambiar de una aplicación a otra. ¿Quién define lo que es esta dirección es el sistema operativo en el momento de la ejecución del programa. El compilador sólo sabe que los bytes x son necesarios para cada variable, y de la interpretación (tipo) que el programa le dará a este espacio.
Líneas 30 a 33 muestran el contenido de estas variables, que no se ha inicializado. Es basura, el último valor que alguien (no sé que) poner esos lugares en la memoria del ordenador y que ahora pertenece a mi variables.
Tenga en cuenta que es seguro a las líneas de descomentar 36 y 37 que tratan de acceder a los contenidos señalados por PA y PB, que no se ha inicializado. Durante este intento, el programa tratará de interpretar los valores de la basura al azar, como las variables int direcciones válidas. Según el compilador, el sistema operativo utilizado y su destino puede ser inofensivo o no. Lo cierto es que el resultado de estas líneas es la fuente impredecible y algunos de los problemas.
En las líneas 41 y 42 los punteros son inicializados con las direcciones de las variables enteras A y B. A partir de ahí las huellas se repiten.
Ver las direcciones de los punteros que no cambian, lo que se esperaba. ¿Cuáles son sus contenidos el cambio. Las variables PA y PB reciben las direcciones de A y B respectivamente. Tenga en cuenta que el contenido de las manos es precisamente el valor de la dirección de las variables A y B que fueron dados por el sistema operativo al inicio del programa. Consulte con las impresiones anteriores. El contenido señalado por PA y PB es el contenido mismo de a y b, que no se ha inicializado, o basura. Sin embargo, a diferencia del paso anterior, ahora el punto de 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 basura la memoria ahora apuntan a las variables que ya han sido asignados.
En las líneas 61 y 62 variables de tipo entero se inicializa con los valores 10 y 13, repite una y otra impresiones.
Esta vez el coteúdos de A y B ya no son basura. Los valores son bien conocidos. Tenga en cuenta que no hay ningún cambio en el direccionamiento de las variables en relación a los pasos anteriores, sólo los valores.
Ver también que después de A y B se han iniciado, el contenido apuntado por PA y PB son también cambia automáticamente. Esto ocurre precisamente porque el punto PA y PB de las áreas de memoria que utilizan los del pa variables y pb. Esto significa que el contenido apuntado por un puntero se puede modificar cambiando el contenido de las variables originales señalados 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 de entender esta forma de pensar de las frases en portugués que mirar el código.
Por ahora ...
Esta fue de las operaciones básicas con punteros. Todavía hay cosas interesantes por ver como punteros a funciones, por ejemplo, pero que se considera un tema más avanzado. Después de esta serie, que está prevista para cuatro puestos de trabajo, ver las referencias, las diferencias y similitudes entre los punteros y referencias y, finalmente, los punteros a funciones.
Enlaces
- ponteiros.zip (todas las fuentes del mensaje);
- 01-declaracao.cpp
- 02-tamanhos.cpp
- 03-utilizando.cpp
- 04-pegadinha.cpp
- 05-enderecos.cpp
- Indicaciones sobre cplusplus.com
- Presunto homicida
Comentarios
- http://blog.blabos.org/2009/05/ponteiros-e-referencias-em-c-parte-2/ punteros y referencias en C + + Parte 2: Blog Blaber de la ampolla
- http://www.caloni.com.br/blog/archives/ultimas-pesquisas-na-blogosfera-nacional Caloni.com.br »Blog Archive» Las últimas investigaciones en la blogosfera nacional
- Punteros y matrices http://blog.blabos.org/2009/05/ponteiros-e-arrays/: Blaber blog de la ampolla
- Fernando
- Fernando
- http://blabos.pip.verisignlabs.com/ blab
- http://blabos.pip.verisignlabs.com/ blab
- Bruno http://www.brunodanielmarinho.com
- Bruno http://www.brunodanielmarinho.com

