punteros destinada a ingpara el bienestar de la población, o bien, que puedan ser perjudiciales...

14
.2 Punteros §1 Presentación Al hablar de punteros es inevitablemente hablar de la memoria, así que permitidme una pequeña introducción al tema. A efectos del programador, la memoria RAM puede suponerse como una sucesión de contenedores capaces de albergar datos (podríamos imaginarlos como una sucesión de vagones de tren). Estos contenedores tienen dos atributos: dirección y contenido. Dirección: un identificativo que sirve para distinguirlos. Para esto es suficiente un número entero positivo progresivamente creciente desde la posición más baja, la dirección 0 (que correspondería al primer vagón), a la posición más alta XXXXX (que correspondería al último). Es tradición informática que estos números se representen enhexadecimal ( 2.2.4b ), de forma que las direcciones se suelen representar como xxxxxh en los textos de programación. Los ordenadores modernos utilizan un modelo de memoria denominado "plano" ("Flat memory model") en el cual la memoria se presenta como un todo continuo desde el punto más bajo hasta el máximo soportado por el hardware (máximo que puede direccionar). En la práctica la RAM instalada en un equipo es siempre inferior a este valor máximo permitido por su arquitectura [3 ], pero el mecanismo de memoria virtual ( H5.1 ) puede simular la existencia de RAM adicional mientras exista espacio en disco. Contenido: el contenido correspondiente a cada dirección está siempre en binario (la memoria física solo puede contener este tipo de variables 0.1 ), y la capacidad de cada vagón depende de la plataforma. En la arquitectura PC, el espacio señalado por cada dirección puede contener un byte (octeto). Como esto es muy poco (solo los tipos char caben en un octeto) para representar datos se utilizan vagones sucesivos en número suficiente. Por ejemplo, si ordenamos al compilador que traiga un dato que está en la dirección xxxxh y es un int. El compilador ya sabe que tiene que traer el contenido de esa celda y las tres siguientes ( 2.2.4 ). Como corolario de lo anterior, recordemos que al hablar de la " dirección de un objeto " nos referimos siempre a la dirección donde comienza su almacenamiento. Por contra, la expresión " dirección de memoria " se refiere a un vagón específico. Como veremos a continuación, los punteros son un tipo de dato que sirven para almacenar direcciones de memoria, y su importancia radica en que la programación de máquinas de Von Newmann tal como las conocemos hoy ( 2 ), gira en torno al concepto de dirección de memoria. §2 Sinopsis

Upload: ricardo-chavarry-alvarado

Post on 29-Jan-2016

212 views

Category:

Documents


0 download

DESCRIPTION

en este archivo se encuentra de manera detallada los diferentes campos de estudio y desarrollo de punteros así como de sus operadores de apuntador y dirección e rescindir de memoria.para el bienestar de la población, o bien, que puedan serperjudiciales para la vida vegetal o animal, o impidan el uso normal de laspropiedades y lugares de recreación y goce de los mismos. Lacontaminación ambiental es también la incorporación a los cuerposreceptores de sustancias sólidas, liquidas o gaseosas, o mezclas de ellas,para el bienestar de la población, o bien, que puedan serperjudiciales para la vida vegetal o animal, o impidan el uso normal de laspropiedades y lugares de recreación y goce de los mismos. Lacontaminación ambiental es también la incorporación a los cuerposreceptores de sustancias sólidas, liquidas o gaseosas, o mezclas de ellas,siempre que alteren desfavorablemente las cpara el bienestar de la población, o bien, que puedan serperjudiciales para la vida vegetal o animal, o impidan el uso normal de laspropiedades y lugares de recreación y goce de los mismos. Lacontaminación ambiental es también la incorporación a los cuerposreceptores de sustancias sólidas, liquidas o gaseosas, o mezclas de ellas,siempre que alteren desfavorablemente las cpara el bienestar de la población, o bien, que puedan serperjudiciales para la vida vegetal o animal, o impidan el uso normal de laspropiedades y lugares de recreación y goce de los mismos. Lacontaminación ambiental es también la incorporación a los cuerposreceptores de sustancias sólidas, liquidas o gaseosas, o mezclas de ellas,siempre que alteren desfavorablemente las cpara el bienestar de la población, o bien, que puedan serperjudiciales para la vida vegetal o animal, o impidan el uso normal de laspropiedades y lugares de recreación y goce de los mismos. Lacontaminación ambiental es también la incorporación a los cuerposreceptores de sustancias sólidas, liquidas o gaseosas, o mezclas de ellas,siempre que alteren desfavorablemente las cpara el bienestar de la población, o bien, que puedan serperjudiciales para la vida vegetal o animal, o impidan el uso normal de laspropiedades y lugares de recreación y goce de los mismos. Lacontaminación ambiental es también la incorporación a los cuerposreceptores de sustancias sólidas, liquidas o gaseosas, o mezclas de ellas,siempre que alteren desfavorablemente las cpara el bienestar de la población, o bien, que puedan serperjudiciales para la vida vegetal o animal, o impidan el uso normal de laspropiedades y lugares de recreación y goce de los mismos. Lacontaminación ambiental es también la incorporación a los cuerposreceptores de sustancias sólidas, liquidas o gaseosas, o mezclas de ellas,siempre que alteren desfavorablemente las cpara el bienestar de la población, o bien, que puedan serperjudiciales para la vida vegetal o animal, o impidan el uso normal de laspropiedades y lugares de recreación y goce de los mismos. Lacontaminación ambiental es también la incorporación a los cuerposreceptores de sustancias sólidas, liquidas o gaseosas, o mezclas de ellas,siempre que alteren desfavorablemente las cpara el bienestar de la población, o bien, que puedan serperjudiciales para la vida vegetal o animal, o impidan el uso normal de laspropiedades y lugares de recreación y goce de los mismos. Lacontaminación ambiental es también la incorporación a los cuerposreceptores de sustancias sólidas, liquidas o gaseosas, o mezclas de ellas,siempre que alteren desfavorablemente las cpara el bienestar de la población, o bien, que puedan serperjudiciales para la vida vegetal o animal, o impidan el uso normal de laspropiedades y lugares de recreación y goce de los mismos. Lacontaminación ambiental es también la incorporación a los cuerposreceptores de sustancias sólidas, liquidas o gaseosas, o mezclas de ellas,siempre que alteren desfavorablemente las cpara el bienestar de

TRANSCRIPT

Page 1: Punteros destinada a ingpara el bienestar de la población, o bien, que puedan ser perjudiciales para la vida vegetal o animal, o impidan el uso normal de las propiedades y lugares

2 Punteros

sect1 Presentacioacuten

Al hablar de punteros es inevitablemente hablar de la memoria asiacute que permitidme una pequentildea introduccioacuten al tema

A efectos del programador la memoria RAM puede suponerse como una sucesioacuten de contenedores capaces de albergar datos (podriacuteamos imaginarlos como una sucesioacuten de vagones de tren) Estos contenedores tienen dos atributos direccioacuten y contenido

Direccioacuten un identificativo que sirve para distinguirlos Para esto es suficiente un nuacutemero entero positivo progresivamente creciente desde la posicioacuten maacutes baja la direccioacuten 0 (que corresponderiacutea al primer vagoacuten) a la posicioacuten maacutes alta XXXXX (que corresponderiacutea al uacuteltimo) Es tradicioacuten informaacutetica

que estos nuacutemeros se representen enhexadecimal ( 224b) de forma que las direcciones se suelen representar como xxxxxh en los textos de programacioacuten

Los ordenadores modernos utilizan un modelo de memoria denominado plano (Flat memory model) en el cual la memoria se presenta como un todo continuo desde el punto maacutes bajo hasta el maacuteximo soportado por el hardware (maacuteximo que puede direccionar) En la praacutectica la RAM instalada en un equipo es siempre inferior a este valor maacuteximo permitido por su arquitectura [3] pero el

mecanismo de memoria virtual ( H51) puede simular la existencia de RAM adicional mientras exista espacio en disco

Contenido el contenido correspondiente a cada direccioacuten estaacute siempre en binario (la memoria fiacutesica

solo puede contener este tipo de variables 01) y la capacidad de cada vagoacuten depende de la plataforma En la arquitectura PC el espacio sentildealado por cada direccioacuten puede contener un byte (octeto) Como esto es muy poco (solo los tipos char caben en un octeto) para representar datos se utilizan vagones sucesivos en nuacutemero suficiente Por ejemplo si ordenamos al compilador que traiga un dato que estaacute en la direccioacuten xxxxh y es un int El compilador ya sabe que tiene que traer el

contenido de esa celda y las tres siguientes ( 224)

Como corolario de lo anterior recordemos que al hablar de la direccioacuten de un objeto nos referimos siempre a la direccioacuten donde comienza su almacenamiento Por contra la expresioacuten direccioacuten de memoria se refiere a un vagoacuten especiacutefico

Como veremos a continuacioacuten los punteros son un tipo de dato que sirven para almacenar direcciones de memoria y su importancia radica en que la programacioacuten de maacutequinas de Von Newmann tal como las

conocemos hoy ( 2) gira en torno al concepto de direccioacuten de memoria

sect2 Sinopsis

Los punteros son un tipo especial de datos C++ cuyo fin especiacutefico es almacenar direcciones de objetos Comparten las caracteriacutesticas de las variables Es decir tienen un valor (tienen Rvalue) pueden ser asignados (tienen Lvalue) tienen un aacutelgebra especiacutefica (se pueden realizar con ellos determinadas operaciones) pueden ser almacenados en matrices pasados como paraacutemetros a funciones y devueltos por estas Comprenden dos categoriacuteas principales punteros-a-objeto y punteros-a-funcioacuten seguacuten el tipo de objeto sentildealado Ambas categoriacuteas comparten ciertas operaciones pero tienen uso propiedades y reglas de manipulacioacuten distintas

Nota maacutes que un tipo deberiacuteamos decir mejor una familia de tipos Tendremos ocasioacuten de ver que existen tantos sub-tipos de puntero como tipos de objetos distintos pueden ser sentildealados por ellos Tambieacuten veremos que cuando se declara un puntero se especifica a que tipo de objeto puede sentildealar en el futuro se limitaraacute a contener direcciones de objetos de ese tipo

sect3 Generalidades

El tratamiento de punteros en C++ utiliza su propio vocabulario con el que es aconsejable familiarizarse desde el principio En general decimos coloquialmente que un puntero apunta o sentildeala a un objeto determinado cuando su valor (del puntero) es la direccioacuten del objeto (direccioacuten de memoria donde comienza su almacenamiento) El objeto sentildealado por el puntero se denominareferente Por esta razoacuten tambieacuten se dice que el puntero referencia al objeto El operador que permite obtener la direccioacuten de un objeto (para asignarlo

a un puntero) se denomina operador de referencia ( 4911) y la operacioacuten de obtener el referente a partir

del puntero se denomina deferenciar ( 4911)

Como veremos a lo largo de este capiacutetulo los punteros representan magnitudes escalares (nuacutemeros) con casi todas las propiedades de los enteros sin signo pero tienen sus propias reglas y restricciones para asignacioacuten conversioacuten y aritmeacutetica (disponen de ciertos operadores aritmeacuteticos) Por supuesto su tamantildeo es el suficiente para almacenar una direccioacuten de memoria en la arquitectura de la computadora utilizada

Nota en la mayoriacutea de compiladores de 32 bits los punteros ocupan 4 bytes es decir coincide con el de un entero de forma que sizeof(int) == sizeof(void) no obstatante no tiene porqueacute ser asiacute necesariamene Por ejemplo en algunos compiladores para 64 bits el tamantildeo del puntero es mayor que el tamantildeo de un entero

En cualquier caso el tamantildeo de un puntero Ptr puede comprobarse mediante el operador sizeof ( 4913) y una sentencia del tipo

cout ltlt sizeof Ptr ltlt endl

Considere el siguiente ejemplo

char ptc = Aint entero = 100int pti = ampenteroprintf(Tamantildeo de puntero a caraacutecter4d bytesn sizeof(ptc) )printf(Tamantildeo de puntero a entero4d bytesn sizeof(pti) )

Salida (compilador C++Builder de Borland para Windows 32)

Tamantildeo de puntero a caraacutecter 4 bytesTamantildeo de puntero a entero 4 bytes

sect4 En el ordenador digital todo estaacute almacenado en memoria yo en los registros del procesador Incluso los datos almacenados en dispositivos externos deben ser volcados a memoria para su utilizacioacuten Habida cuenta que esta memoria es manejada por el procesador y su circuiteriacutea asociada (chipset) por medio de direcciones parece evidente que los punteros son un tipo de dato especial e importante tanto en C++ como en casi cualquier lenguaje de programacioacuten [1]

Los registros del procesador reciban un tratamiento especial para su acceso (distinto del de la memoria) lo que explica que los punteros no sirvan para contener las direcciones de tales registros y que el operador de

referencia amp ( 4911) tampoco pueda ser aplicado para obtener su direccioacuten (de los registros) Como consecuencia directa de lo anterior los punteros tampoco pueden ser utilizados para almacenar las direcciones de valores devueltos por funciones dado que estos valores se almacenan en los registros

Los punteros son un recurso que en cierta forma podriacutea considerarse de muy bajo nivel ya que permiten manipular directamente contenidos de memoria Por esta razoacuten su utilizacioacuten puede presentar algunos problemas y exigen que se preste una especial atencioacuten a aquellas secciones del coacutedigo que los utilizan Recuerde que los errores maacutes insidiosos y difiacuteciles de depurar que se presentan en los programas C++ estaacuten relacionados con el uso descuidado de punteros Precisamente por razoacuten del comentario de KampR apuntado al principio y porque son frecuentemente origen de errores algunos lenguajes prefieren evitarlos por completo al menos su utilizacioacuten expliacutecita y en otros casos su utilizacioacuten estaacute muy restringida [2] En cambio el lenguaje ensamblador estaacute plagado de ellos y desde luego en C++ que no se distingue precisamente por soslayar los peligros constituyen un capiacutetulo extraordinariamente importante

Como epiacutelogo de lo anterior y aclaracioacuten para el estudiante en especial los que no se han enfrentado antes a estos conceptos o los hayan utilizado indirectamente (en lenguajes que los encapsulan en un envoltorio maacutes amable) digamos que la utilizacioacuten de punteros exige un cierto entrenamiento mental ya que en principio son difiacuteciles de ver [4] en especial los casos en que se utilizan punteros-a-punteros y que cuesta un cierto esfuerzo distinguir fluidamente entre valor del puntero el valor del objeto sentildealado por este valor y el significado de las operaciones asociadas (referencia y deferencia) Si este es su caso Dont panic sepa que es bastante normal y que basta un poco de praacutectica para que estos conceptos fluyan raacutepidamente y sin problema

DIRECCIOacuteN

Un identificativo Que sirve para Distinguirlos

MEMORIA RAM COMPARTIMIENTOS DE MEMORIA

CONTENIDO

El contenido correspondiente a cada direccioacuten estaacute siempre en binario (la memoria fiacutesica solo puede contener este tipo de variables

422 Aritmeacutetica de punteros

sect1 Sinopsis

La aritmeacutetica de punteros se limita a suma resta comparacioacuten y asignacioacuten Las operaciones aritmeacuteticas en los punteros de tipoX (punteros-a-tipoX) tienen automaacuteticamente en cuenta el tamantildeo real de tipoX Es decir el nuacutemero de bytes necesario para almacenar un objeto tipoX [2] Por ejemplo suponiendo una matriz de double con 100 elementos si ptr es un puntero a dicha matriz la sentencia ptr++ supone incrementar el Rvalue de ptr en 6400 bits porque el tamantildeo de la matriz es precisamente 100x64 bits

Nota no confundir el puntero-a-matriz con un puntero a su primer elemento (que aquiacute seriacutea puntero-a-double)

La aritmeacutetica realizada internamente en los punteros depende del modelo de memoria en uso y de la presencia de cualquier modificador superpuesto

Las operaciones que implican dos punteros exigen que sean del mismo tipo o se realice

previamente un modelado apropiado

sect2 Operaciones permitidas

Sean ptr1 ptr2 punteros a objetos del mismo tipo y n un tipo entero o una enumeracioacuten las operaciones permitidas y los resultados obtenidos con ellas son

Operacioacuten Resultado Comentario

pt1++ punteroDesplazamiento ascendente de 1 elemento(desplazamiento de una direccion)

pt1-- puntero Desplazamiento descendente de 1 elemento

pt1 + n puntero Desplazamiento ascendente n elementos [4]

pt1 - n puntero Desplazamiento descendente n elementos [4]

pt1 - pt2 entero Distancia entre elementos

pt1 == NULL booleano Siempre se puede comprobar la igualdad o desigualdad con NULL

pt1 = NULL booleano ( 321b)

pt1 ltRgt pt2 booleano ltRgt es una expresioacuten relacional ( 4912)

pt1 = pt2 puntero Asignacioacuten

pt1 = voidpuntero geneacuterico

Asignacioacuten

La comparacioacuten de punteros solo tiene sentido entre punteros a elementos de la misma matriz en estas condiciones los operadores relacionales == = lt gt lt= gt= funcionan correctamente

Hemos sentildealado que cuando se realizan operaciones aritmeacuteticas con punteros se tiene en cuenta el tamantildeo de los objetos apuntados de modo que si un puntero es declarado apuntando-a-tipoX antildeadirle un entero n (al puntero) supone hacerlo hace avanzar un nuacutemero n de objetos tipoX Si tipoX tiene un tamantildeo de 10 bytes antildeadir 5 al puntero-a-tipoX lo hace avanzar 50 bytes en memoria (si se trata de punteros a elementos de una matriz supone avanzar n elementos en la matriz [3])

Del mismo modo la diferencia entre dos punteros resulta ser el nuacutemero de objetos tipoX que separa a dos punteros-a-tipoX Por ejemplo si ptr1 apunta al tercer elemento de una matriz y ptr2 apunta al deacutecimo elemento el resultado ptr2-ptr1 es 7 (en realidad la diferencia de dos punteros solo tiene sentido cuando ambos apuntan a la misma matriz)

observe que no estaacute definida la suma entre punteros

Si ptr es un puntero a un elemento de una matriz desde luego no existe un elemento tal como uno despueacutes del uacuteltimo pero se permite que ptr tenga dicho valor Si ptr1 apunta al uacuteltimo elemento del array ptr+1 es legal pero ptr+2 es indefinido (lo que a efectos praacutecticos significa que devolveraacute basura o un runtime volcado de memoria etc)

Si ptr apunta a uno despueacutes del uacuteltimo ptr-1 es legal (puntero al uacuteltimo elemento) Sin embargo aplicando el operador de indireccioacuten a un puntero despueacutes del uacuteltimo conduce a una indefinicioacuten

Informalmente puede pensarse en ptr + n como avanzar el puntero en (n sizeof(tipoX)) bytes siempre que ptr se mantenga en su rango legal (entre el primer elemento y uno despueacutes del uacuteltimo)

La resta de dos punteros a elementos de la misma matriz ptr1-ptr2 produce un entero n del tipo ptrdiff_t definido en ltstddefhgt Este nuacutemero representa la diferencia entre los subiacutendices i y j de los dos elementos referenciados (n = i-j) Para esto es necesario que ptr1 y ptr2 apunten a elementos existentes o uno despueacutes del uacuteltimo

sect4 Ejemplos

N Expresioacuten Resultado

1 ip+10 Produce otro puntero Si ip es un puntero al elemento m[j] de una matriz (dicho de otro modo si ip == ampm[j] ) el nuevo puntero apunta a otro elemento m[j+10] de la misma matriz con lo que (ip+10) == ampm[j+10]

2 y = ip+10 Antildeade 10 al objeto ip (objeto referenciado por ip) y lo asigna a y

3 ip += 1

Equivale a ip = ip + 1 Incrementa en 1 el valor (Rvalue) del objeto referenciado por ip

4 ++ip Igual que el anterior incrementa en 1 el valor del objeto referenciado por ip

5 ++ip El resultado es otro puntero Equivale a ip = ip+1 es decir incrementa en 1 el valor del puntero con lo que el nuevo puntero sentildeala a otra posicioacuten (ver caso 1)

6 ip++ Igual que el caso anterior Incrementa en 1 el valor del puntero

7 (ip)++ Igual que el caso 4 Dado que el pareacutentesis tiene maacutexima precedencia y asocia de

izquierda a derecha ( 490a) incrementa en 1 el valor del objeto referenciado por ip

Observe que el pareacutentesis es necesario sin eacutel la expresioacuten modifica la posicioacuten de memoria sentildealado porip Es decir se realiza ip++ Si ip es un puntero al elemento m[j] de una matriz el resultado es un puntero al elemento m[j+1] Despueacutes se tomariacutea la indireccioacuten es decir el resultado final seriacutea el valor del elemento m[j+1]

Por tanto la expresioacuten ip++ equivale a (ip++)

8 ip+1 El valor resultante es el de incrementar en 1 el valor del objeto apuntado por ip

sect5 Ejemplos

Consideremos copiar una cadena NTBS ( 323f) definida por un puntero a su origen s en un destino definido por un punterop Considerando que el final de la cadena estaacute sentildealado por el caraacutecter nulo el proceso podriacutea ser

while (s = 0) p = s copiar caraacutecter s++ p++

Teniendo en cuenta que estamos usando el postincremento ( 491) para s y p y que cualquier ltexpresioacutengt es cierta si ltexpresioacutengt = 0 Lo anterior seriacutea equivalente a

while (s ) p = s s++

p++

El incremento se puede expresar en la misma sentencia de asignacioacuten

while (s ) p++ = s++

La razoacuten es que p++ indica el caraacutecter apuntado por p antes que sea incrementado El postincremento ++ no cambia p hasta que el caraacutecter ha sido actualizado (primero se efectuacutea la asignacioacuten y despueacutes se incrementa) El orden de ejecucioacuten de las operaciones involucradas es

1- Se asigna p s2- Se incrementa s3- Se incrementa p

La comparacioacuten puede hacerse en el mismo momento que la copia de caracteres

while ( p++ = s++) sect51

La razoacuten es que despueacutes de la uacuteltima asignacioacuten que corresponderiacutea al caraacutecter 0 de s el resultado de la asignacioacuten seriacutea justamente este valor (0 == falso) y se saldriacutea del while

Por la razoacuten inversa la expresioacuten ++p indica el caraacutecter apuntado por p despueacutes que ha sido incrementado Ambos tipos de expresiones de asignacioacuten con punteros simultaneadas con prepost incrementosdecrementos son muy frecuentes en los bucles que involucran punteros De hecho las expresiones

p++ = val cargar la pila con valval = --p sacar de la pila el uacuteltimo valor asignarlo a val

son las sentencias estaacutendar de cargardescargar valores val de una pila LIFO [1] manejada por un puntero p

Nota esta capacidad de C++ para permitir formas de coacutedigo tan extraordinariamente compactas tiene fervientes defensores y aceacuterrimos detractores En mi opinioacuten el uacutenico problema es que sin un entrenamiento previo la primera vez que se topa uno con una expresioacuten como la sect51 anterior puede quedarse bastante perplejo Aunque en realidad solo

se trate de uno maacutes de los idioms ( 413) de fondo de armario de cualquier programador C++

sect6 Conversioacuten de punteros

Un puntero de un tipo (tipoX) puede ser convertido a otro (tipoY) usando el mecanismo de conversioacuten o modelado de tipos que utiliza el operador (tipoY)

Ejemplo

char str str puntero a charint ip ip puntero a intstr = (char )ip asignacioacuten str = ip (ip puntero a char)

De forma general el operador-moldeador (tipoX ) puede convertir el operando (un puntero de cualquier tipo) a un puntero-a-tipoX

Como ejemplo de lo insidioso que pueden llegar a ser algunos rincones de los compiladores C++ considere el siguiente ejemplo

long strRchr (const Stringamp str char needle) unsigned long stLen = strlen() for (register unsigned long i = stLen - 1 igt=0 --i) if ((strcptr + i) == needle) return i return -1L

Se trata de una funcioacuten que proporciona la posicioacuten de la uacuteltima ocurrencia de un caraacutecter (needle) en un una cadena de caracteres (str) En nuestro caso los objetos de la clase String albergan cadenas alfanumeacutericas En concreto el meacutetodo len() proporciona la longitud de la cadena y el miembro cptr es un puntero al primer caraacutecter La funcioacuten devuelve -1 si el caraacutecter no se encuentre en la cadena En caso contrario devuelve la posicioacuten empezando a contar desde cero para el primer caraacutecter

Aunque compila sin dificultad la rutina anterior produce un extrantildeo resultado negativo en las pruebas realizadas con el compilador BC++ 55 mientras que con GNU G++ 342-20040916-1 para Windows produce un error fatal de runtime Despueacutes de perder un par de horas intentando diagnosticar el problema y haber sopesado todas las posibilidades (incluyendo que el compilador estuviese poseido -) resultoacute que estaba en el resultado de strcptr + i (suma del puntero con el incremento) Cuando i es un unsigned long la suma con el puntero produce un resultado negativo Ninguacuten otro tipo para i produciacutea error Por ejemplo int o long

Observe que este comportamiento anoacutemalo se produce a pesar de lo sentildealado al respecto por el Estaacutendar [4] y de que los unsigned long son tipos enteros

421 Puntero a objeto

sect1 Sinopsis

Un puntero-a-tipoX (puntero a un objeto de tipoX) almacena la direccioacuten de un objeto del tipo sentildealado es decir sentildeala a un objeto tipoX Puesto que los punteros son objetos puede haber un puntero apuntando a un puntero (asiacute sucesivamente) Los objetos a los que se apunta suelen ser matrices estructuras uniones y clases

Nota aquiacute consideramos que un objeto es una regioacuten especiacutefica de memoria que puede contener un valor (o conjunto de valores) fijo o variable Esta acepcioacuten del vocablo es diferente (maacutes amplia) que cuando designa la instancia de una clase

Las explicaciones que siguen son vaacutelidas para punteros objetos de cualquier tipo (que no sean funciones) pero cuando se trata especiacuteficamente de punteros a clases e instancias de clases existen ciertas particularidades en la notacioacuten asiacute que les hemos dedicado un epiacutegrafe especiacutefico

con algunos comentarios ( 421f)

Nota tradicionalmente se considera que punteros y matrices estaacuten estrechamente relacionados [1] hasta el punto de ser estudiados simultaacuteneamente De hecho cualquier operacioacuten que puede efectuarse entre subiacutendices de matrices puede efectuarse con punteros en general de forma maacutes raacutepida (aunque algo maacutes difiacutecil de entender por el principiante)

Ademaacutes el operador de elemento de matriz [ ] se define en teacuterminos de ser un puntero ( 4916)

Los punteros a objeto tiene su propia aritmeacutetica (rudimentaria) de forma que pueden ser incrementados disminuidos y comparados cuando se exploran matrices u otras estructuras complejas

sect2 Puntero nulo

Un puntero nulo es un puntero que apunta a una direccioacuten que no corresponde a ninguacuten objeto del programa Asignando la constante entera 0 a un puntero se le asigna el valor nulo Para mejor ligibilidad puede utilizarse la constante manifiesta NULL(definida en la libreriacutea de cabeceras estaacutendar ltstdiohgt) Ejemplo

int punt1 L1 Declara punt1punt1 = 0 L2 define punt1 como puntero nulopunt1 = NULL Equivalente a la anterior

Nota la cuestioacuten de la inicializacioacuten del puntero nulo es uno de los puntos de controversia para los teoacutericos del lenguaje En rigor la sentencia L2 anterior es erroacutenea ya que el tipo de punt1 es

puntero-a-int mientras que 0 es una constante numeacuterica (int por defecto) a pesar de lo cual es aceptada sin rechistar por el compilador [2] Lo sintaacutecticamente correcto seriacutea realizar un modelado

adecuado ( 499)

punt1 = static_castltintgt (0)

Es interesante observar que los punteros nulos de tipos distintos son distintos entre si Por ejemplo

un puntero nulo-a-int es de tipo distinto de un puntero nulo-a-char (aunque ambos coincidan en que su Rvalue es 0) por tanto no pueden ser comparados La comparacioacuten de dos punteros nulos del mismo tipo conduce a que son iguales Ejemplo

int pint = NULLchar pchar = NULLif (pint == pchar) cout ltlt Iguales Error

La uacuteltima sentencia produce un error de compilacioacuten Error Nonportable pointer comparison in

Es un error deferenciar ( 4911) un puntero nulo ademaacutes el intento de utilizar el valor obtenido puede dar lugar a un error de ejecucioacuten Por ejemplo refirieacutendonos al caso anterior

int x = pint Error

Recordar que cuando falla el operador de modelado dynamic_cast ( 499c) sobre un puntero el resultado es un puntero nulo Tambieacuten que algunas funciones de la Libreriacutea Estaacutendar devuelven punteros incluso el operador new devuelve un puntero y en algunas implementaciones antiguas el aviso de error en la operacioacuten de este operador se realizaba devolviendo un puntero nulo

sect3 Inicializar punteros

En general los punteros pueden ser inicializados como otra variable cualquiera desde luego solo tiene sentido que el valor sea la direccioacuten de inicio del almacenamiento de un objeto del tipo adecuado En otras palabras un valor que sea una direccioacuten de memoria Como existe un operador que precisamente proporciona la direccioacuten de una variable (operador de

referencia amp 4911) la forma usual de inicializar un puntero suele ser asignaacutendole el valor devuelto por dicho operador Ejemplo

int x = 100int ptr declaracioacuten de ptr como puntero-a-intptr = ampx se le asigna la direccioacuten de una variable

Tambieacuten es muy frecuente iniciarlos con el valor devuelto por el operador new ( 4920) que precisamente devuelve un puntero a objeto Ejemplo

class C definicioacuten de una clase CC cptr declara cptr como puntero-a-Ccptr = new C() new crea una instancia de la clase y devuelve un puntero al objeto cuyo valor que es asignado a cptr

Nota los enteros y los punteros no son intercambiables con excepcioacuten del cero El cero es un valor que nunca puede adoptar un puntero en condiciones normales por esta razoacuten se utiliza para significar no asignado u otra circunstancia especial Recordar que la aritmeacutetica de punteros permite comparar dos punteros para igualdad o desigualdad conNULL

sect4 Punteros como argumentos

En muchas ocasiones los punteros se utilizan como argumentos a funciones De hecho la mayoriacutea de las veces en que las matrices o las cadenas de caracteres pasan como argumentos lo que en realidad pasa es un puntero al primer elemento Por ejemplo

char str = La Tacita de Plataprintf(La ciudad es sn str)

En este caso la funcioacuten printf recibe como segundo argumento str que es un puntero a la posicioacuten de memoria donde comienza el almacenamiento de la cadena La Tacita de Plata0

En cualquier caso es necesario declarar esta circunstancia en el prototipo y en la definicioacuten de la funcioacuten para que el compilador conozca que el argumento pasado es una variable tipo puntero Ejemplo

include ltiostreamhgt void func(int ) prototipo argumento definido como puntero-a-int void main () ============= int x = 35 int ptr = ampx func (ptr) se pasa puntero-a-int como argumento cout ltlt El valor es ahora ltlt x ltlt endl void func (int p) el argumento se define como puntero-a-int p += 10 el argumento es tratado como puntero

Salida

El valor es ahora 45

  • 2 Punteros
    • sect1 Presentacioacuten
    • sect2 Sinopsis
    • sect3 Generalidades
    • 422 Aritmeacutetica de punteros
      • sect1 Sinopsis
      • sect2 Operaciones permitidas
      • sect4 Ejemplos
      • sect5 Ejemplos
      • sect6 Conversioacuten de punteros
        • 421 Puntero a objeto
          • sect1 Sinopsis
          • sect2 Puntero nulo
          • sect3 Inicializar punteros
          • sect4 Punteros como argumentos
Page 2: Punteros destinada a ingpara el bienestar de la población, o bien, que puedan ser perjudiciales para la vida vegetal o animal, o impidan el uso normal de las propiedades y lugares

Nota maacutes que un tipo deberiacuteamos decir mejor una familia de tipos Tendremos ocasioacuten de ver que existen tantos sub-tipos de puntero como tipos de objetos distintos pueden ser sentildealados por ellos Tambieacuten veremos que cuando se declara un puntero se especifica a que tipo de objeto puede sentildealar en el futuro se limitaraacute a contener direcciones de objetos de ese tipo

sect3 Generalidades

El tratamiento de punteros en C++ utiliza su propio vocabulario con el que es aconsejable familiarizarse desde el principio En general decimos coloquialmente que un puntero apunta o sentildeala a un objeto determinado cuando su valor (del puntero) es la direccioacuten del objeto (direccioacuten de memoria donde comienza su almacenamiento) El objeto sentildealado por el puntero se denominareferente Por esta razoacuten tambieacuten se dice que el puntero referencia al objeto El operador que permite obtener la direccioacuten de un objeto (para asignarlo

a un puntero) se denomina operador de referencia ( 4911) y la operacioacuten de obtener el referente a partir

del puntero se denomina deferenciar ( 4911)

Como veremos a lo largo de este capiacutetulo los punteros representan magnitudes escalares (nuacutemeros) con casi todas las propiedades de los enteros sin signo pero tienen sus propias reglas y restricciones para asignacioacuten conversioacuten y aritmeacutetica (disponen de ciertos operadores aritmeacuteticos) Por supuesto su tamantildeo es el suficiente para almacenar una direccioacuten de memoria en la arquitectura de la computadora utilizada

Nota en la mayoriacutea de compiladores de 32 bits los punteros ocupan 4 bytes es decir coincide con el de un entero de forma que sizeof(int) == sizeof(void) no obstatante no tiene porqueacute ser asiacute necesariamene Por ejemplo en algunos compiladores para 64 bits el tamantildeo del puntero es mayor que el tamantildeo de un entero

En cualquier caso el tamantildeo de un puntero Ptr puede comprobarse mediante el operador sizeof ( 4913) y una sentencia del tipo

cout ltlt sizeof Ptr ltlt endl

Considere el siguiente ejemplo

char ptc = Aint entero = 100int pti = ampenteroprintf(Tamantildeo de puntero a caraacutecter4d bytesn sizeof(ptc) )printf(Tamantildeo de puntero a entero4d bytesn sizeof(pti) )

Salida (compilador C++Builder de Borland para Windows 32)

Tamantildeo de puntero a caraacutecter 4 bytesTamantildeo de puntero a entero 4 bytes

sect4 En el ordenador digital todo estaacute almacenado en memoria yo en los registros del procesador Incluso los datos almacenados en dispositivos externos deben ser volcados a memoria para su utilizacioacuten Habida cuenta que esta memoria es manejada por el procesador y su circuiteriacutea asociada (chipset) por medio de direcciones parece evidente que los punteros son un tipo de dato especial e importante tanto en C++ como en casi cualquier lenguaje de programacioacuten [1]

Los registros del procesador reciban un tratamiento especial para su acceso (distinto del de la memoria) lo que explica que los punteros no sirvan para contener las direcciones de tales registros y que el operador de

referencia amp ( 4911) tampoco pueda ser aplicado para obtener su direccioacuten (de los registros) Como consecuencia directa de lo anterior los punteros tampoco pueden ser utilizados para almacenar las direcciones de valores devueltos por funciones dado que estos valores se almacenan en los registros

Los punteros son un recurso que en cierta forma podriacutea considerarse de muy bajo nivel ya que permiten manipular directamente contenidos de memoria Por esta razoacuten su utilizacioacuten puede presentar algunos problemas y exigen que se preste una especial atencioacuten a aquellas secciones del coacutedigo que los utilizan Recuerde que los errores maacutes insidiosos y difiacuteciles de depurar que se presentan en los programas C++ estaacuten relacionados con el uso descuidado de punteros Precisamente por razoacuten del comentario de KampR apuntado al principio y porque son frecuentemente origen de errores algunos lenguajes prefieren evitarlos por completo al menos su utilizacioacuten expliacutecita y en otros casos su utilizacioacuten estaacute muy restringida [2] En cambio el lenguaje ensamblador estaacute plagado de ellos y desde luego en C++ que no se distingue precisamente por soslayar los peligros constituyen un capiacutetulo extraordinariamente importante

Como epiacutelogo de lo anterior y aclaracioacuten para el estudiante en especial los que no se han enfrentado antes a estos conceptos o los hayan utilizado indirectamente (en lenguajes que los encapsulan en un envoltorio maacutes amable) digamos que la utilizacioacuten de punteros exige un cierto entrenamiento mental ya que en principio son difiacuteciles de ver [4] en especial los casos en que se utilizan punteros-a-punteros y que cuesta un cierto esfuerzo distinguir fluidamente entre valor del puntero el valor del objeto sentildealado por este valor y el significado de las operaciones asociadas (referencia y deferencia) Si este es su caso Dont panic sepa que es bastante normal y que basta un poco de praacutectica para que estos conceptos fluyan raacutepidamente y sin problema

DIRECCIOacuteN

Un identificativo Que sirve para Distinguirlos

MEMORIA RAM COMPARTIMIENTOS DE MEMORIA

CONTENIDO

El contenido correspondiente a cada direccioacuten estaacute siempre en binario (la memoria fiacutesica solo puede contener este tipo de variables

422 Aritmeacutetica de punteros

sect1 Sinopsis

La aritmeacutetica de punteros se limita a suma resta comparacioacuten y asignacioacuten Las operaciones aritmeacuteticas en los punteros de tipoX (punteros-a-tipoX) tienen automaacuteticamente en cuenta el tamantildeo real de tipoX Es decir el nuacutemero de bytes necesario para almacenar un objeto tipoX [2] Por ejemplo suponiendo una matriz de double con 100 elementos si ptr es un puntero a dicha matriz la sentencia ptr++ supone incrementar el Rvalue de ptr en 6400 bits porque el tamantildeo de la matriz es precisamente 100x64 bits

Nota no confundir el puntero-a-matriz con un puntero a su primer elemento (que aquiacute seriacutea puntero-a-double)

La aritmeacutetica realizada internamente en los punteros depende del modelo de memoria en uso y de la presencia de cualquier modificador superpuesto

Las operaciones que implican dos punteros exigen que sean del mismo tipo o se realice

previamente un modelado apropiado

sect2 Operaciones permitidas

Sean ptr1 ptr2 punteros a objetos del mismo tipo y n un tipo entero o una enumeracioacuten las operaciones permitidas y los resultados obtenidos con ellas son

Operacioacuten Resultado Comentario

pt1++ punteroDesplazamiento ascendente de 1 elemento(desplazamiento de una direccion)

pt1-- puntero Desplazamiento descendente de 1 elemento

pt1 + n puntero Desplazamiento ascendente n elementos [4]

pt1 - n puntero Desplazamiento descendente n elementos [4]

pt1 - pt2 entero Distancia entre elementos

pt1 == NULL booleano Siempre se puede comprobar la igualdad o desigualdad con NULL

pt1 = NULL booleano ( 321b)

pt1 ltRgt pt2 booleano ltRgt es una expresioacuten relacional ( 4912)

pt1 = pt2 puntero Asignacioacuten

pt1 = voidpuntero geneacuterico

Asignacioacuten

La comparacioacuten de punteros solo tiene sentido entre punteros a elementos de la misma matriz en estas condiciones los operadores relacionales == = lt gt lt= gt= funcionan correctamente

Hemos sentildealado que cuando se realizan operaciones aritmeacuteticas con punteros se tiene en cuenta el tamantildeo de los objetos apuntados de modo que si un puntero es declarado apuntando-a-tipoX antildeadirle un entero n (al puntero) supone hacerlo hace avanzar un nuacutemero n de objetos tipoX Si tipoX tiene un tamantildeo de 10 bytes antildeadir 5 al puntero-a-tipoX lo hace avanzar 50 bytes en memoria (si se trata de punteros a elementos de una matriz supone avanzar n elementos en la matriz [3])

Del mismo modo la diferencia entre dos punteros resulta ser el nuacutemero de objetos tipoX que separa a dos punteros-a-tipoX Por ejemplo si ptr1 apunta al tercer elemento de una matriz y ptr2 apunta al deacutecimo elemento el resultado ptr2-ptr1 es 7 (en realidad la diferencia de dos punteros solo tiene sentido cuando ambos apuntan a la misma matriz)

observe que no estaacute definida la suma entre punteros

Si ptr es un puntero a un elemento de una matriz desde luego no existe un elemento tal como uno despueacutes del uacuteltimo pero se permite que ptr tenga dicho valor Si ptr1 apunta al uacuteltimo elemento del array ptr+1 es legal pero ptr+2 es indefinido (lo que a efectos praacutecticos significa que devolveraacute basura o un runtime volcado de memoria etc)

Si ptr apunta a uno despueacutes del uacuteltimo ptr-1 es legal (puntero al uacuteltimo elemento) Sin embargo aplicando el operador de indireccioacuten a un puntero despueacutes del uacuteltimo conduce a una indefinicioacuten

Informalmente puede pensarse en ptr + n como avanzar el puntero en (n sizeof(tipoX)) bytes siempre que ptr se mantenga en su rango legal (entre el primer elemento y uno despueacutes del uacuteltimo)

La resta de dos punteros a elementos de la misma matriz ptr1-ptr2 produce un entero n del tipo ptrdiff_t definido en ltstddefhgt Este nuacutemero representa la diferencia entre los subiacutendices i y j de los dos elementos referenciados (n = i-j) Para esto es necesario que ptr1 y ptr2 apunten a elementos existentes o uno despueacutes del uacuteltimo

sect4 Ejemplos

N Expresioacuten Resultado

1 ip+10 Produce otro puntero Si ip es un puntero al elemento m[j] de una matriz (dicho de otro modo si ip == ampm[j] ) el nuevo puntero apunta a otro elemento m[j+10] de la misma matriz con lo que (ip+10) == ampm[j+10]

2 y = ip+10 Antildeade 10 al objeto ip (objeto referenciado por ip) y lo asigna a y

3 ip += 1

Equivale a ip = ip + 1 Incrementa en 1 el valor (Rvalue) del objeto referenciado por ip

4 ++ip Igual que el anterior incrementa en 1 el valor del objeto referenciado por ip

5 ++ip El resultado es otro puntero Equivale a ip = ip+1 es decir incrementa en 1 el valor del puntero con lo que el nuevo puntero sentildeala a otra posicioacuten (ver caso 1)

6 ip++ Igual que el caso anterior Incrementa en 1 el valor del puntero

7 (ip)++ Igual que el caso 4 Dado que el pareacutentesis tiene maacutexima precedencia y asocia de

izquierda a derecha ( 490a) incrementa en 1 el valor del objeto referenciado por ip

Observe que el pareacutentesis es necesario sin eacutel la expresioacuten modifica la posicioacuten de memoria sentildealado porip Es decir se realiza ip++ Si ip es un puntero al elemento m[j] de una matriz el resultado es un puntero al elemento m[j+1] Despueacutes se tomariacutea la indireccioacuten es decir el resultado final seriacutea el valor del elemento m[j+1]

Por tanto la expresioacuten ip++ equivale a (ip++)

8 ip+1 El valor resultante es el de incrementar en 1 el valor del objeto apuntado por ip

sect5 Ejemplos

Consideremos copiar una cadena NTBS ( 323f) definida por un puntero a su origen s en un destino definido por un punterop Considerando que el final de la cadena estaacute sentildealado por el caraacutecter nulo el proceso podriacutea ser

while (s = 0) p = s copiar caraacutecter s++ p++

Teniendo en cuenta que estamos usando el postincremento ( 491) para s y p y que cualquier ltexpresioacutengt es cierta si ltexpresioacutengt = 0 Lo anterior seriacutea equivalente a

while (s ) p = s s++

p++

El incremento se puede expresar en la misma sentencia de asignacioacuten

while (s ) p++ = s++

La razoacuten es que p++ indica el caraacutecter apuntado por p antes que sea incrementado El postincremento ++ no cambia p hasta que el caraacutecter ha sido actualizado (primero se efectuacutea la asignacioacuten y despueacutes se incrementa) El orden de ejecucioacuten de las operaciones involucradas es

1- Se asigna p s2- Se incrementa s3- Se incrementa p

La comparacioacuten puede hacerse en el mismo momento que la copia de caracteres

while ( p++ = s++) sect51

La razoacuten es que despueacutes de la uacuteltima asignacioacuten que corresponderiacutea al caraacutecter 0 de s el resultado de la asignacioacuten seriacutea justamente este valor (0 == falso) y se saldriacutea del while

Por la razoacuten inversa la expresioacuten ++p indica el caraacutecter apuntado por p despueacutes que ha sido incrementado Ambos tipos de expresiones de asignacioacuten con punteros simultaneadas con prepost incrementosdecrementos son muy frecuentes en los bucles que involucran punteros De hecho las expresiones

p++ = val cargar la pila con valval = --p sacar de la pila el uacuteltimo valor asignarlo a val

son las sentencias estaacutendar de cargardescargar valores val de una pila LIFO [1] manejada por un puntero p

Nota esta capacidad de C++ para permitir formas de coacutedigo tan extraordinariamente compactas tiene fervientes defensores y aceacuterrimos detractores En mi opinioacuten el uacutenico problema es que sin un entrenamiento previo la primera vez que se topa uno con una expresioacuten como la sect51 anterior puede quedarse bastante perplejo Aunque en realidad solo

se trate de uno maacutes de los idioms ( 413) de fondo de armario de cualquier programador C++

sect6 Conversioacuten de punteros

Un puntero de un tipo (tipoX) puede ser convertido a otro (tipoY) usando el mecanismo de conversioacuten o modelado de tipos que utiliza el operador (tipoY)

Ejemplo

char str str puntero a charint ip ip puntero a intstr = (char )ip asignacioacuten str = ip (ip puntero a char)

De forma general el operador-moldeador (tipoX ) puede convertir el operando (un puntero de cualquier tipo) a un puntero-a-tipoX

Como ejemplo de lo insidioso que pueden llegar a ser algunos rincones de los compiladores C++ considere el siguiente ejemplo

long strRchr (const Stringamp str char needle) unsigned long stLen = strlen() for (register unsigned long i = stLen - 1 igt=0 --i) if ((strcptr + i) == needle) return i return -1L

Se trata de una funcioacuten que proporciona la posicioacuten de la uacuteltima ocurrencia de un caraacutecter (needle) en un una cadena de caracteres (str) En nuestro caso los objetos de la clase String albergan cadenas alfanumeacutericas En concreto el meacutetodo len() proporciona la longitud de la cadena y el miembro cptr es un puntero al primer caraacutecter La funcioacuten devuelve -1 si el caraacutecter no se encuentre en la cadena En caso contrario devuelve la posicioacuten empezando a contar desde cero para el primer caraacutecter

Aunque compila sin dificultad la rutina anterior produce un extrantildeo resultado negativo en las pruebas realizadas con el compilador BC++ 55 mientras que con GNU G++ 342-20040916-1 para Windows produce un error fatal de runtime Despueacutes de perder un par de horas intentando diagnosticar el problema y haber sopesado todas las posibilidades (incluyendo que el compilador estuviese poseido -) resultoacute que estaba en el resultado de strcptr + i (suma del puntero con el incremento) Cuando i es un unsigned long la suma con el puntero produce un resultado negativo Ninguacuten otro tipo para i produciacutea error Por ejemplo int o long

Observe que este comportamiento anoacutemalo se produce a pesar de lo sentildealado al respecto por el Estaacutendar [4] y de que los unsigned long son tipos enteros

421 Puntero a objeto

sect1 Sinopsis

Un puntero-a-tipoX (puntero a un objeto de tipoX) almacena la direccioacuten de un objeto del tipo sentildealado es decir sentildeala a un objeto tipoX Puesto que los punteros son objetos puede haber un puntero apuntando a un puntero (asiacute sucesivamente) Los objetos a los que se apunta suelen ser matrices estructuras uniones y clases

Nota aquiacute consideramos que un objeto es una regioacuten especiacutefica de memoria que puede contener un valor (o conjunto de valores) fijo o variable Esta acepcioacuten del vocablo es diferente (maacutes amplia) que cuando designa la instancia de una clase

Las explicaciones que siguen son vaacutelidas para punteros objetos de cualquier tipo (que no sean funciones) pero cuando se trata especiacuteficamente de punteros a clases e instancias de clases existen ciertas particularidades en la notacioacuten asiacute que les hemos dedicado un epiacutegrafe especiacutefico

con algunos comentarios ( 421f)

Nota tradicionalmente se considera que punteros y matrices estaacuten estrechamente relacionados [1] hasta el punto de ser estudiados simultaacuteneamente De hecho cualquier operacioacuten que puede efectuarse entre subiacutendices de matrices puede efectuarse con punteros en general de forma maacutes raacutepida (aunque algo maacutes difiacutecil de entender por el principiante)

Ademaacutes el operador de elemento de matriz [ ] se define en teacuterminos de ser un puntero ( 4916)

Los punteros a objeto tiene su propia aritmeacutetica (rudimentaria) de forma que pueden ser incrementados disminuidos y comparados cuando se exploran matrices u otras estructuras complejas

sect2 Puntero nulo

Un puntero nulo es un puntero que apunta a una direccioacuten que no corresponde a ninguacuten objeto del programa Asignando la constante entera 0 a un puntero se le asigna el valor nulo Para mejor ligibilidad puede utilizarse la constante manifiesta NULL(definida en la libreriacutea de cabeceras estaacutendar ltstdiohgt) Ejemplo

int punt1 L1 Declara punt1punt1 = 0 L2 define punt1 como puntero nulopunt1 = NULL Equivalente a la anterior

Nota la cuestioacuten de la inicializacioacuten del puntero nulo es uno de los puntos de controversia para los teoacutericos del lenguaje En rigor la sentencia L2 anterior es erroacutenea ya que el tipo de punt1 es

puntero-a-int mientras que 0 es una constante numeacuterica (int por defecto) a pesar de lo cual es aceptada sin rechistar por el compilador [2] Lo sintaacutecticamente correcto seriacutea realizar un modelado

adecuado ( 499)

punt1 = static_castltintgt (0)

Es interesante observar que los punteros nulos de tipos distintos son distintos entre si Por ejemplo

un puntero nulo-a-int es de tipo distinto de un puntero nulo-a-char (aunque ambos coincidan en que su Rvalue es 0) por tanto no pueden ser comparados La comparacioacuten de dos punteros nulos del mismo tipo conduce a que son iguales Ejemplo

int pint = NULLchar pchar = NULLif (pint == pchar) cout ltlt Iguales Error

La uacuteltima sentencia produce un error de compilacioacuten Error Nonportable pointer comparison in

Es un error deferenciar ( 4911) un puntero nulo ademaacutes el intento de utilizar el valor obtenido puede dar lugar a un error de ejecucioacuten Por ejemplo refirieacutendonos al caso anterior

int x = pint Error

Recordar que cuando falla el operador de modelado dynamic_cast ( 499c) sobre un puntero el resultado es un puntero nulo Tambieacuten que algunas funciones de la Libreriacutea Estaacutendar devuelven punteros incluso el operador new devuelve un puntero y en algunas implementaciones antiguas el aviso de error en la operacioacuten de este operador se realizaba devolviendo un puntero nulo

sect3 Inicializar punteros

En general los punteros pueden ser inicializados como otra variable cualquiera desde luego solo tiene sentido que el valor sea la direccioacuten de inicio del almacenamiento de un objeto del tipo adecuado En otras palabras un valor que sea una direccioacuten de memoria Como existe un operador que precisamente proporciona la direccioacuten de una variable (operador de

referencia amp 4911) la forma usual de inicializar un puntero suele ser asignaacutendole el valor devuelto por dicho operador Ejemplo

int x = 100int ptr declaracioacuten de ptr como puntero-a-intptr = ampx se le asigna la direccioacuten de una variable

Tambieacuten es muy frecuente iniciarlos con el valor devuelto por el operador new ( 4920) que precisamente devuelve un puntero a objeto Ejemplo

class C definicioacuten de una clase CC cptr declara cptr como puntero-a-Ccptr = new C() new crea una instancia de la clase y devuelve un puntero al objeto cuyo valor que es asignado a cptr

Nota los enteros y los punteros no son intercambiables con excepcioacuten del cero El cero es un valor que nunca puede adoptar un puntero en condiciones normales por esta razoacuten se utiliza para significar no asignado u otra circunstancia especial Recordar que la aritmeacutetica de punteros permite comparar dos punteros para igualdad o desigualdad conNULL

sect4 Punteros como argumentos

En muchas ocasiones los punteros se utilizan como argumentos a funciones De hecho la mayoriacutea de las veces en que las matrices o las cadenas de caracteres pasan como argumentos lo que en realidad pasa es un puntero al primer elemento Por ejemplo

char str = La Tacita de Plataprintf(La ciudad es sn str)

En este caso la funcioacuten printf recibe como segundo argumento str que es un puntero a la posicioacuten de memoria donde comienza el almacenamiento de la cadena La Tacita de Plata0

En cualquier caso es necesario declarar esta circunstancia en el prototipo y en la definicioacuten de la funcioacuten para que el compilador conozca que el argumento pasado es una variable tipo puntero Ejemplo

include ltiostreamhgt void func(int ) prototipo argumento definido como puntero-a-int void main () ============= int x = 35 int ptr = ampx func (ptr) se pasa puntero-a-int como argumento cout ltlt El valor es ahora ltlt x ltlt endl void func (int p) el argumento se define como puntero-a-int p += 10 el argumento es tratado como puntero

Salida

El valor es ahora 45

  • 2 Punteros
    • sect1 Presentacioacuten
    • sect2 Sinopsis
    • sect3 Generalidades
    • 422 Aritmeacutetica de punteros
      • sect1 Sinopsis
      • sect2 Operaciones permitidas
      • sect4 Ejemplos
      • sect5 Ejemplos
      • sect6 Conversioacuten de punteros
        • 421 Puntero a objeto
          • sect1 Sinopsis
          • sect2 Puntero nulo
          • sect3 Inicializar punteros
          • sect4 Punteros como argumentos
Page 3: Punteros destinada a ingpara el bienestar de la población, o bien, que puedan ser perjudiciales para la vida vegetal o animal, o impidan el uso normal de las propiedades y lugares

Los registros del procesador reciban un tratamiento especial para su acceso (distinto del de la memoria) lo que explica que los punteros no sirvan para contener las direcciones de tales registros y que el operador de

referencia amp ( 4911) tampoco pueda ser aplicado para obtener su direccioacuten (de los registros) Como consecuencia directa de lo anterior los punteros tampoco pueden ser utilizados para almacenar las direcciones de valores devueltos por funciones dado que estos valores se almacenan en los registros

Los punteros son un recurso que en cierta forma podriacutea considerarse de muy bajo nivel ya que permiten manipular directamente contenidos de memoria Por esta razoacuten su utilizacioacuten puede presentar algunos problemas y exigen que se preste una especial atencioacuten a aquellas secciones del coacutedigo que los utilizan Recuerde que los errores maacutes insidiosos y difiacuteciles de depurar que se presentan en los programas C++ estaacuten relacionados con el uso descuidado de punteros Precisamente por razoacuten del comentario de KampR apuntado al principio y porque son frecuentemente origen de errores algunos lenguajes prefieren evitarlos por completo al menos su utilizacioacuten expliacutecita y en otros casos su utilizacioacuten estaacute muy restringida [2] En cambio el lenguaje ensamblador estaacute plagado de ellos y desde luego en C++ que no se distingue precisamente por soslayar los peligros constituyen un capiacutetulo extraordinariamente importante

Como epiacutelogo de lo anterior y aclaracioacuten para el estudiante en especial los que no se han enfrentado antes a estos conceptos o los hayan utilizado indirectamente (en lenguajes que los encapsulan en un envoltorio maacutes amable) digamos que la utilizacioacuten de punteros exige un cierto entrenamiento mental ya que en principio son difiacuteciles de ver [4] en especial los casos en que se utilizan punteros-a-punteros y que cuesta un cierto esfuerzo distinguir fluidamente entre valor del puntero el valor del objeto sentildealado por este valor y el significado de las operaciones asociadas (referencia y deferencia) Si este es su caso Dont panic sepa que es bastante normal y que basta un poco de praacutectica para que estos conceptos fluyan raacutepidamente y sin problema

DIRECCIOacuteN

Un identificativo Que sirve para Distinguirlos

MEMORIA RAM COMPARTIMIENTOS DE MEMORIA

CONTENIDO

El contenido correspondiente a cada direccioacuten estaacute siempre en binario (la memoria fiacutesica solo puede contener este tipo de variables

422 Aritmeacutetica de punteros

sect1 Sinopsis

La aritmeacutetica de punteros se limita a suma resta comparacioacuten y asignacioacuten Las operaciones aritmeacuteticas en los punteros de tipoX (punteros-a-tipoX) tienen automaacuteticamente en cuenta el tamantildeo real de tipoX Es decir el nuacutemero de bytes necesario para almacenar un objeto tipoX [2] Por ejemplo suponiendo una matriz de double con 100 elementos si ptr es un puntero a dicha matriz la sentencia ptr++ supone incrementar el Rvalue de ptr en 6400 bits porque el tamantildeo de la matriz es precisamente 100x64 bits

Nota no confundir el puntero-a-matriz con un puntero a su primer elemento (que aquiacute seriacutea puntero-a-double)

La aritmeacutetica realizada internamente en los punteros depende del modelo de memoria en uso y de la presencia de cualquier modificador superpuesto

Las operaciones que implican dos punteros exigen que sean del mismo tipo o se realice

previamente un modelado apropiado

sect2 Operaciones permitidas

Sean ptr1 ptr2 punteros a objetos del mismo tipo y n un tipo entero o una enumeracioacuten las operaciones permitidas y los resultados obtenidos con ellas son

Operacioacuten Resultado Comentario

pt1++ punteroDesplazamiento ascendente de 1 elemento(desplazamiento de una direccion)

pt1-- puntero Desplazamiento descendente de 1 elemento

pt1 + n puntero Desplazamiento ascendente n elementos [4]

pt1 - n puntero Desplazamiento descendente n elementos [4]

pt1 - pt2 entero Distancia entre elementos

pt1 == NULL booleano Siempre se puede comprobar la igualdad o desigualdad con NULL

pt1 = NULL booleano ( 321b)

pt1 ltRgt pt2 booleano ltRgt es una expresioacuten relacional ( 4912)

pt1 = pt2 puntero Asignacioacuten

pt1 = voidpuntero geneacuterico

Asignacioacuten

La comparacioacuten de punteros solo tiene sentido entre punteros a elementos de la misma matriz en estas condiciones los operadores relacionales == = lt gt lt= gt= funcionan correctamente

Hemos sentildealado que cuando se realizan operaciones aritmeacuteticas con punteros se tiene en cuenta el tamantildeo de los objetos apuntados de modo que si un puntero es declarado apuntando-a-tipoX antildeadirle un entero n (al puntero) supone hacerlo hace avanzar un nuacutemero n de objetos tipoX Si tipoX tiene un tamantildeo de 10 bytes antildeadir 5 al puntero-a-tipoX lo hace avanzar 50 bytes en memoria (si se trata de punteros a elementos de una matriz supone avanzar n elementos en la matriz [3])

Del mismo modo la diferencia entre dos punteros resulta ser el nuacutemero de objetos tipoX que separa a dos punteros-a-tipoX Por ejemplo si ptr1 apunta al tercer elemento de una matriz y ptr2 apunta al deacutecimo elemento el resultado ptr2-ptr1 es 7 (en realidad la diferencia de dos punteros solo tiene sentido cuando ambos apuntan a la misma matriz)

observe que no estaacute definida la suma entre punteros

Si ptr es un puntero a un elemento de una matriz desde luego no existe un elemento tal como uno despueacutes del uacuteltimo pero se permite que ptr tenga dicho valor Si ptr1 apunta al uacuteltimo elemento del array ptr+1 es legal pero ptr+2 es indefinido (lo que a efectos praacutecticos significa que devolveraacute basura o un runtime volcado de memoria etc)

Si ptr apunta a uno despueacutes del uacuteltimo ptr-1 es legal (puntero al uacuteltimo elemento) Sin embargo aplicando el operador de indireccioacuten a un puntero despueacutes del uacuteltimo conduce a una indefinicioacuten

Informalmente puede pensarse en ptr + n como avanzar el puntero en (n sizeof(tipoX)) bytes siempre que ptr se mantenga en su rango legal (entre el primer elemento y uno despueacutes del uacuteltimo)

La resta de dos punteros a elementos de la misma matriz ptr1-ptr2 produce un entero n del tipo ptrdiff_t definido en ltstddefhgt Este nuacutemero representa la diferencia entre los subiacutendices i y j de los dos elementos referenciados (n = i-j) Para esto es necesario que ptr1 y ptr2 apunten a elementos existentes o uno despueacutes del uacuteltimo

sect4 Ejemplos

N Expresioacuten Resultado

1 ip+10 Produce otro puntero Si ip es un puntero al elemento m[j] de una matriz (dicho de otro modo si ip == ampm[j] ) el nuevo puntero apunta a otro elemento m[j+10] de la misma matriz con lo que (ip+10) == ampm[j+10]

2 y = ip+10 Antildeade 10 al objeto ip (objeto referenciado por ip) y lo asigna a y

3 ip += 1

Equivale a ip = ip + 1 Incrementa en 1 el valor (Rvalue) del objeto referenciado por ip

4 ++ip Igual que el anterior incrementa en 1 el valor del objeto referenciado por ip

5 ++ip El resultado es otro puntero Equivale a ip = ip+1 es decir incrementa en 1 el valor del puntero con lo que el nuevo puntero sentildeala a otra posicioacuten (ver caso 1)

6 ip++ Igual que el caso anterior Incrementa en 1 el valor del puntero

7 (ip)++ Igual que el caso 4 Dado que el pareacutentesis tiene maacutexima precedencia y asocia de

izquierda a derecha ( 490a) incrementa en 1 el valor del objeto referenciado por ip

Observe que el pareacutentesis es necesario sin eacutel la expresioacuten modifica la posicioacuten de memoria sentildealado porip Es decir se realiza ip++ Si ip es un puntero al elemento m[j] de una matriz el resultado es un puntero al elemento m[j+1] Despueacutes se tomariacutea la indireccioacuten es decir el resultado final seriacutea el valor del elemento m[j+1]

Por tanto la expresioacuten ip++ equivale a (ip++)

8 ip+1 El valor resultante es el de incrementar en 1 el valor del objeto apuntado por ip

sect5 Ejemplos

Consideremos copiar una cadena NTBS ( 323f) definida por un puntero a su origen s en un destino definido por un punterop Considerando que el final de la cadena estaacute sentildealado por el caraacutecter nulo el proceso podriacutea ser

while (s = 0) p = s copiar caraacutecter s++ p++

Teniendo en cuenta que estamos usando el postincremento ( 491) para s y p y que cualquier ltexpresioacutengt es cierta si ltexpresioacutengt = 0 Lo anterior seriacutea equivalente a

while (s ) p = s s++

p++

El incremento se puede expresar en la misma sentencia de asignacioacuten

while (s ) p++ = s++

La razoacuten es que p++ indica el caraacutecter apuntado por p antes que sea incrementado El postincremento ++ no cambia p hasta que el caraacutecter ha sido actualizado (primero se efectuacutea la asignacioacuten y despueacutes se incrementa) El orden de ejecucioacuten de las operaciones involucradas es

1- Se asigna p s2- Se incrementa s3- Se incrementa p

La comparacioacuten puede hacerse en el mismo momento que la copia de caracteres

while ( p++ = s++) sect51

La razoacuten es que despueacutes de la uacuteltima asignacioacuten que corresponderiacutea al caraacutecter 0 de s el resultado de la asignacioacuten seriacutea justamente este valor (0 == falso) y se saldriacutea del while

Por la razoacuten inversa la expresioacuten ++p indica el caraacutecter apuntado por p despueacutes que ha sido incrementado Ambos tipos de expresiones de asignacioacuten con punteros simultaneadas con prepost incrementosdecrementos son muy frecuentes en los bucles que involucran punteros De hecho las expresiones

p++ = val cargar la pila con valval = --p sacar de la pila el uacuteltimo valor asignarlo a val

son las sentencias estaacutendar de cargardescargar valores val de una pila LIFO [1] manejada por un puntero p

Nota esta capacidad de C++ para permitir formas de coacutedigo tan extraordinariamente compactas tiene fervientes defensores y aceacuterrimos detractores En mi opinioacuten el uacutenico problema es que sin un entrenamiento previo la primera vez que se topa uno con una expresioacuten como la sect51 anterior puede quedarse bastante perplejo Aunque en realidad solo

se trate de uno maacutes de los idioms ( 413) de fondo de armario de cualquier programador C++

sect6 Conversioacuten de punteros

Un puntero de un tipo (tipoX) puede ser convertido a otro (tipoY) usando el mecanismo de conversioacuten o modelado de tipos que utiliza el operador (tipoY)

Ejemplo

char str str puntero a charint ip ip puntero a intstr = (char )ip asignacioacuten str = ip (ip puntero a char)

De forma general el operador-moldeador (tipoX ) puede convertir el operando (un puntero de cualquier tipo) a un puntero-a-tipoX

Como ejemplo de lo insidioso que pueden llegar a ser algunos rincones de los compiladores C++ considere el siguiente ejemplo

long strRchr (const Stringamp str char needle) unsigned long stLen = strlen() for (register unsigned long i = stLen - 1 igt=0 --i) if ((strcptr + i) == needle) return i return -1L

Se trata de una funcioacuten que proporciona la posicioacuten de la uacuteltima ocurrencia de un caraacutecter (needle) en un una cadena de caracteres (str) En nuestro caso los objetos de la clase String albergan cadenas alfanumeacutericas En concreto el meacutetodo len() proporciona la longitud de la cadena y el miembro cptr es un puntero al primer caraacutecter La funcioacuten devuelve -1 si el caraacutecter no se encuentre en la cadena En caso contrario devuelve la posicioacuten empezando a contar desde cero para el primer caraacutecter

Aunque compila sin dificultad la rutina anterior produce un extrantildeo resultado negativo en las pruebas realizadas con el compilador BC++ 55 mientras que con GNU G++ 342-20040916-1 para Windows produce un error fatal de runtime Despueacutes de perder un par de horas intentando diagnosticar el problema y haber sopesado todas las posibilidades (incluyendo que el compilador estuviese poseido -) resultoacute que estaba en el resultado de strcptr + i (suma del puntero con el incremento) Cuando i es un unsigned long la suma con el puntero produce un resultado negativo Ninguacuten otro tipo para i produciacutea error Por ejemplo int o long

Observe que este comportamiento anoacutemalo se produce a pesar de lo sentildealado al respecto por el Estaacutendar [4] y de que los unsigned long son tipos enteros

421 Puntero a objeto

sect1 Sinopsis

Un puntero-a-tipoX (puntero a un objeto de tipoX) almacena la direccioacuten de un objeto del tipo sentildealado es decir sentildeala a un objeto tipoX Puesto que los punteros son objetos puede haber un puntero apuntando a un puntero (asiacute sucesivamente) Los objetos a los que se apunta suelen ser matrices estructuras uniones y clases

Nota aquiacute consideramos que un objeto es una regioacuten especiacutefica de memoria que puede contener un valor (o conjunto de valores) fijo o variable Esta acepcioacuten del vocablo es diferente (maacutes amplia) que cuando designa la instancia de una clase

Las explicaciones que siguen son vaacutelidas para punteros objetos de cualquier tipo (que no sean funciones) pero cuando se trata especiacuteficamente de punteros a clases e instancias de clases existen ciertas particularidades en la notacioacuten asiacute que les hemos dedicado un epiacutegrafe especiacutefico

con algunos comentarios ( 421f)

Nota tradicionalmente se considera que punteros y matrices estaacuten estrechamente relacionados [1] hasta el punto de ser estudiados simultaacuteneamente De hecho cualquier operacioacuten que puede efectuarse entre subiacutendices de matrices puede efectuarse con punteros en general de forma maacutes raacutepida (aunque algo maacutes difiacutecil de entender por el principiante)

Ademaacutes el operador de elemento de matriz [ ] se define en teacuterminos de ser un puntero ( 4916)

Los punteros a objeto tiene su propia aritmeacutetica (rudimentaria) de forma que pueden ser incrementados disminuidos y comparados cuando se exploran matrices u otras estructuras complejas

sect2 Puntero nulo

Un puntero nulo es un puntero que apunta a una direccioacuten que no corresponde a ninguacuten objeto del programa Asignando la constante entera 0 a un puntero se le asigna el valor nulo Para mejor ligibilidad puede utilizarse la constante manifiesta NULL(definida en la libreriacutea de cabeceras estaacutendar ltstdiohgt) Ejemplo

int punt1 L1 Declara punt1punt1 = 0 L2 define punt1 como puntero nulopunt1 = NULL Equivalente a la anterior

Nota la cuestioacuten de la inicializacioacuten del puntero nulo es uno de los puntos de controversia para los teoacutericos del lenguaje En rigor la sentencia L2 anterior es erroacutenea ya que el tipo de punt1 es

puntero-a-int mientras que 0 es una constante numeacuterica (int por defecto) a pesar de lo cual es aceptada sin rechistar por el compilador [2] Lo sintaacutecticamente correcto seriacutea realizar un modelado

adecuado ( 499)

punt1 = static_castltintgt (0)

Es interesante observar que los punteros nulos de tipos distintos son distintos entre si Por ejemplo

un puntero nulo-a-int es de tipo distinto de un puntero nulo-a-char (aunque ambos coincidan en que su Rvalue es 0) por tanto no pueden ser comparados La comparacioacuten de dos punteros nulos del mismo tipo conduce a que son iguales Ejemplo

int pint = NULLchar pchar = NULLif (pint == pchar) cout ltlt Iguales Error

La uacuteltima sentencia produce un error de compilacioacuten Error Nonportable pointer comparison in

Es un error deferenciar ( 4911) un puntero nulo ademaacutes el intento de utilizar el valor obtenido puede dar lugar a un error de ejecucioacuten Por ejemplo refirieacutendonos al caso anterior

int x = pint Error

Recordar que cuando falla el operador de modelado dynamic_cast ( 499c) sobre un puntero el resultado es un puntero nulo Tambieacuten que algunas funciones de la Libreriacutea Estaacutendar devuelven punteros incluso el operador new devuelve un puntero y en algunas implementaciones antiguas el aviso de error en la operacioacuten de este operador se realizaba devolviendo un puntero nulo

sect3 Inicializar punteros

En general los punteros pueden ser inicializados como otra variable cualquiera desde luego solo tiene sentido que el valor sea la direccioacuten de inicio del almacenamiento de un objeto del tipo adecuado En otras palabras un valor que sea una direccioacuten de memoria Como existe un operador que precisamente proporciona la direccioacuten de una variable (operador de

referencia amp 4911) la forma usual de inicializar un puntero suele ser asignaacutendole el valor devuelto por dicho operador Ejemplo

int x = 100int ptr declaracioacuten de ptr como puntero-a-intptr = ampx se le asigna la direccioacuten de una variable

Tambieacuten es muy frecuente iniciarlos con el valor devuelto por el operador new ( 4920) que precisamente devuelve un puntero a objeto Ejemplo

class C definicioacuten de una clase CC cptr declara cptr como puntero-a-Ccptr = new C() new crea una instancia de la clase y devuelve un puntero al objeto cuyo valor que es asignado a cptr

Nota los enteros y los punteros no son intercambiables con excepcioacuten del cero El cero es un valor que nunca puede adoptar un puntero en condiciones normales por esta razoacuten se utiliza para significar no asignado u otra circunstancia especial Recordar que la aritmeacutetica de punteros permite comparar dos punteros para igualdad o desigualdad conNULL

sect4 Punteros como argumentos

En muchas ocasiones los punteros se utilizan como argumentos a funciones De hecho la mayoriacutea de las veces en que las matrices o las cadenas de caracteres pasan como argumentos lo que en realidad pasa es un puntero al primer elemento Por ejemplo

char str = La Tacita de Plataprintf(La ciudad es sn str)

En este caso la funcioacuten printf recibe como segundo argumento str que es un puntero a la posicioacuten de memoria donde comienza el almacenamiento de la cadena La Tacita de Plata0

En cualquier caso es necesario declarar esta circunstancia en el prototipo y en la definicioacuten de la funcioacuten para que el compilador conozca que el argumento pasado es una variable tipo puntero Ejemplo

include ltiostreamhgt void func(int ) prototipo argumento definido como puntero-a-int void main () ============= int x = 35 int ptr = ampx func (ptr) se pasa puntero-a-int como argumento cout ltlt El valor es ahora ltlt x ltlt endl void func (int p) el argumento se define como puntero-a-int p += 10 el argumento es tratado como puntero

Salida

El valor es ahora 45

  • 2 Punteros
    • sect1 Presentacioacuten
    • sect2 Sinopsis
    • sect3 Generalidades
    • 422 Aritmeacutetica de punteros
      • sect1 Sinopsis
      • sect2 Operaciones permitidas
      • sect4 Ejemplos
      • sect5 Ejemplos
      • sect6 Conversioacuten de punteros
        • 421 Puntero a objeto
          • sect1 Sinopsis
          • sect2 Puntero nulo
          • sect3 Inicializar punteros
          • sect4 Punteros como argumentos
Page 4: Punteros destinada a ingpara el bienestar de la población, o bien, que puedan ser perjudiciales para la vida vegetal o animal, o impidan el uso normal de las propiedades y lugares

422 Aritmeacutetica de punteros

sect1 Sinopsis

La aritmeacutetica de punteros se limita a suma resta comparacioacuten y asignacioacuten Las operaciones aritmeacuteticas en los punteros de tipoX (punteros-a-tipoX) tienen automaacuteticamente en cuenta el tamantildeo real de tipoX Es decir el nuacutemero de bytes necesario para almacenar un objeto tipoX [2] Por ejemplo suponiendo una matriz de double con 100 elementos si ptr es un puntero a dicha matriz la sentencia ptr++ supone incrementar el Rvalue de ptr en 6400 bits porque el tamantildeo de la matriz es precisamente 100x64 bits

Nota no confundir el puntero-a-matriz con un puntero a su primer elemento (que aquiacute seriacutea puntero-a-double)

La aritmeacutetica realizada internamente en los punteros depende del modelo de memoria en uso y de la presencia de cualquier modificador superpuesto

Las operaciones que implican dos punteros exigen que sean del mismo tipo o se realice

previamente un modelado apropiado

sect2 Operaciones permitidas

Sean ptr1 ptr2 punteros a objetos del mismo tipo y n un tipo entero o una enumeracioacuten las operaciones permitidas y los resultados obtenidos con ellas son

Operacioacuten Resultado Comentario

pt1++ punteroDesplazamiento ascendente de 1 elemento(desplazamiento de una direccion)

pt1-- puntero Desplazamiento descendente de 1 elemento

pt1 + n puntero Desplazamiento ascendente n elementos [4]

pt1 - n puntero Desplazamiento descendente n elementos [4]

pt1 - pt2 entero Distancia entre elementos

pt1 == NULL booleano Siempre se puede comprobar la igualdad o desigualdad con NULL

pt1 = NULL booleano ( 321b)

pt1 ltRgt pt2 booleano ltRgt es una expresioacuten relacional ( 4912)

pt1 = pt2 puntero Asignacioacuten

pt1 = voidpuntero geneacuterico

Asignacioacuten

La comparacioacuten de punteros solo tiene sentido entre punteros a elementos de la misma matriz en estas condiciones los operadores relacionales == = lt gt lt= gt= funcionan correctamente

Hemos sentildealado que cuando se realizan operaciones aritmeacuteticas con punteros se tiene en cuenta el tamantildeo de los objetos apuntados de modo que si un puntero es declarado apuntando-a-tipoX antildeadirle un entero n (al puntero) supone hacerlo hace avanzar un nuacutemero n de objetos tipoX Si tipoX tiene un tamantildeo de 10 bytes antildeadir 5 al puntero-a-tipoX lo hace avanzar 50 bytes en memoria (si se trata de punteros a elementos de una matriz supone avanzar n elementos en la matriz [3])

Del mismo modo la diferencia entre dos punteros resulta ser el nuacutemero de objetos tipoX que separa a dos punteros-a-tipoX Por ejemplo si ptr1 apunta al tercer elemento de una matriz y ptr2 apunta al deacutecimo elemento el resultado ptr2-ptr1 es 7 (en realidad la diferencia de dos punteros solo tiene sentido cuando ambos apuntan a la misma matriz)

observe que no estaacute definida la suma entre punteros

Si ptr es un puntero a un elemento de una matriz desde luego no existe un elemento tal como uno despueacutes del uacuteltimo pero se permite que ptr tenga dicho valor Si ptr1 apunta al uacuteltimo elemento del array ptr+1 es legal pero ptr+2 es indefinido (lo que a efectos praacutecticos significa que devolveraacute basura o un runtime volcado de memoria etc)

Si ptr apunta a uno despueacutes del uacuteltimo ptr-1 es legal (puntero al uacuteltimo elemento) Sin embargo aplicando el operador de indireccioacuten a un puntero despueacutes del uacuteltimo conduce a una indefinicioacuten

Informalmente puede pensarse en ptr + n como avanzar el puntero en (n sizeof(tipoX)) bytes siempre que ptr se mantenga en su rango legal (entre el primer elemento y uno despueacutes del uacuteltimo)

La resta de dos punteros a elementos de la misma matriz ptr1-ptr2 produce un entero n del tipo ptrdiff_t definido en ltstddefhgt Este nuacutemero representa la diferencia entre los subiacutendices i y j de los dos elementos referenciados (n = i-j) Para esto es necesario que ptr1 y ptr2 apunten a elementos existentes o uno despueacutes del uacuteltimo

sect4 Ejemplos

N Expresioacuten Resultado

1 ip+10 Produce otro puntero Si ip es un puntero al elemento m[j] de una matriz (dicho de otro modo si ip == ampm[j] ) el nuevo puntero apunta a otro elemento m[j+10] de la misma matriz con lo que (ip+10) == ampm[j+10]

2 y = ip+10 Antildeade 10 al objeto ip (objeto referenciado por ip) y lo asigna a y

3 ip += 1

Equivale a ip = ip + 1 Incrementa en 1 el valor (Rvalue) del objeto referenciado por ip

4 ++ip Igual que el anterior incrementa en 1 el valor del objeto referenciado por ip

5 ++ip El resultado es otro puntero Equivale a ip = ip+1 es decir incrementa en 1 el valor del puntero con lo que el nuevo puntero sentildeala a otra posicioacuten (ver caso 1)

6 ip++ Igual que el caso anterior Incrementa en 1 el valor del puntero

7 (ip)++ Igual que el caso 4 Dado que el pareacutentesis tiene maacutexima precedencia y asocia de

izquierda a derecha ( 490a) incrementa en 1 el valor del objeto referenciado por ip

Observe que el pareacutentesis es necesario sin eacutel la expresioacuten modifica la posicioacuten de memoria sentildealado porip Es decir se realiza ip++ Si ip es un puntero al elemento m[j] de una matriz el resultado es un puntero al elemento m[j+1] Despueacutes se tomariacutea la indireccioacuten es decir el resultado final seriacutea el valor del elemento m[j+1]

Por tanto la expresioacuten ip++ equivale a (ip++)

8 ip+1 El valor resultante es el de incrementar en 1 el valor del objeto apuntado por ip

sect5 Ejemplos

Consideremos copiar una cadena NTBS ( 323f) definida por un puntero a su origen s en un destino definido por un punterop Considerando que el final de la cadena estaacute sentildealado por el caraacutecter nulo el proceso podriacutea ser

while (s = 0) p = s copiar caraacutecter s++ p++

Teniendo en cuenta que estamos usando el postincremento ( 491) para s y p y que cualquier ltexpresioacutengt es cierta si ltexpresioacutengt = 0 Lo anterior seriacutea equivalente a

while (s ) p = s s++

p++

El incremento se puede expresar en la misma sentencia de asignacioacuten

while (s ) p++ = s++

La razoacuten es que p++ indica el caraacutecter apuntado por p antes que sea incrementado El postincremento ++ no cambia p hasta que el caraacutecter ha sido actualizado (primero se efectuacutea la asignacioacuten y despueacutes se incrementa) El orden de ejecucioacuten de las operaciones involucradas es

1- Se asigna p s2- Se incrementa s3- Se incrementa p

La comparacioacuten puede hacerse en el mismo momento que la copia de caracteres

while ( p++ = s++) sect51

La razoacuten es que despueacutes de la uacuteltima asignacioacuten que corresponderiacutea al caraacutecter 0 de s el resultado de la asignacioacuten seriacutea justamente este valor (0 == falso) y se saldriacutea del while

Por la razoacuten inversa la expresioacuten ++p indica el caraacutecter apuntado por p despueacutes que ha sido incrementado Ambos tipos de expresiones de asignacioacuten con punteros simultaneadas con prepost incrementosdecrementos son muy frecuentes en los bucles que involucran punteros De hecho las expresiones

p++ = val cargar la pila con valval = --p sacar de la pila el uacuteltimo valor asignarlo a val

son las sentencias estaacutendar de cargardescargar valores val de una pila LIFO [1] manejada por un puntero p

Nota esta capacidad de C++ para permitir formas de coacutedigo tan extraordinariamente compactas tiene fervientes defensores y aceacuterrimos detractores En mi opinioacuten el uacutenico problema es que sin un entrenamiento previo la primera vez que se topa uno con una expresioacuten como la sect51 anterior puede quedarse bastante perplejo Aunque en realidad solo

se trate de uno maacutes de los idioms ( 413) de fondo de armario de cualquier programador C++

sect6 Conversioacuten de punteros

Un puntero de un tipo (tipoX) puede ser convertido a otro (tipoY) usando el mecanismo de conversioacuten o modelado de tipos que utiliza el operador (tipoY)

Ejemplo

char str str puntero a charint ip ip puntero a intstr = (char )ip asignacioacuten str = ip (ip puntero a char)

De forma general el operador-moldeador (tipoX ) puede convertir el operando (un puntero de cualquier tipo) a un puntero-a-tipoX

Como ejemplo de lo insidioso que pueden llegar a ser algunos rincones de los compiladores C++ considere el siguiente ejemplo

long strRchr (const Stringamp str char needle) unsigned long stLen = strlen() for (register unsigned long i = stLen - 1 igt=0 --i) if ((strcptr + i) == needle) return i return -1L

Se trata de una funcioacuten que proporciona la posicioacuten de la uacuteltima ocurrencia de un caraacutecter (needle) en un una cadena de caracteres (str) En nuestro caso los objetos de la clase String albergan cadenas alfanumeacutericas En concreto el meacutetodo len() proporciona la longitud de la cadena y el miembro cptr es un puntero al primer caraacutecter La funcioacuten devuelve -1 si el caraacutecter no se encuentre en la cadena En caso contrario devuelve la posicioacuten empezando a contar desde cero para el primer caraacutecter

Aunque compila sin dificultad la rutina anterior produce un extrantildeo resultado negativo en las pruebas realizadas con el compilador BC++ 55 mientras que con GNU G++ 342-20040916-1 para Windows produce un error fatal de runtime Despueacutes de perder un par de horas intentando diagnosticar el problema y haber sopesado todas las posibilidades (incluyendo que el compilador estuviese poseido -) resultoacute que estaba en el resultado de strcptr + i (suma del puntero con el incremento) Cuando i es un unsigned long la suma con el puntero produce un resultado negativo Ninguacuten otro tipo para i produciacutea error Por ejemplo int o long

Observe que este comportamiento anoacutemalo se produce a pesar de lo sentildealado al respecto por el Estaacutendar [4] y de que los unsigned long son tipos enteros

421 Puntero a objeto

sect1 Sinopsis

Un puntero-a-tipoX (puntero a un objeto de tipoX) almacena la direccioacuten de un objeto del tipo sentildealado es decir sentildeala a un objeto tipoX Puesto que los punteros son objetos puede haber un puntero apuntando a un puntero (asiacute sucesivamente) Los objetos a los que se apunta suelen ser matrices estructuras uniones y clases

Nota aquiacute consideramos que un objeto es una regioacuten especiacutefica de memoria que puede contener un valor (o conjunto de valores) fijo o variable Esta acepcioacuten del vocablo es diferente (maacutes amplia) que cuando designa la instancia de una clase

Las explicaciones que siguen son vaacutelidas para punteros objetos de cualquier tipo (que no sean funciones) pero cuando se trata especiacuteficamente de punteros a clases e instancias de clases existen ciertas particularidades en la notacioacuten asiacute que les hemos dedicado un epiacutegrafe especiacutefico

con algunos comentarios ( 421f)

Nota tradicionalmente se considera que punteros y matrices estaacuten estrechamente relacionados [1] hasta el punto de ser estudiados simultaacuteneamente De hecho cualquier operacioacuten que puede efectuarse entre subiacutendices de matrices puede efectuarse con punteros en general de forma maacutes raacutepida (aunque algo maacutes difiacutecil de entender por el principiante)

Ademaacutes el operador de elemento de matriz [ ] se define en teacuterminos de ser un puntero ( 4916)

Los punteros a objeto tiene su propia aritmeacutetica (rudimentaria) de forma que pueden ser incrementados disminuidos y comparados cuando se exploran matrices u otras estructuras complejas

sect2 Puntero nulo

Un puntero nulo es un puntero que apunta a una direccioacuten que no corresponde a ninguacuten objeto del programa Asignando la constante entera 0 a un puntero se le asigna el valor nulo Para mejor ligibilidad puede utilizarse la constante manifiesta NULL(definida en la libreriacutea de cabeceras estaacutendar ltstdiohgt) Ejemplo

int punt1 L1 Declara punt1punt1 = 0 L2 define punt1 como puntero nulopunt1 = NULL Equivalente a la anterior

Nota la cuestioacuten de la inicializacioacuten del puntero nulo es uno de los puntos de controversia para los teoacutericos del lenguaje En rigor la sentencia L2 anterior es erroacutenea ya que el tipo de punt1 es

puntero-a-int mientras que 0 es una constante numeacuterica (int por defecto) a pesar de lo cual es aceptada sin rechistar por el compilador [2] Lo sintaacutecticamente correcto seriacutea realizar un modelado

adecuado ( 499)

punt1 = static_castltintgt (0)

Es interesante observar que los punteros nulos de tipos distintos son distintos entre si Por ejemplo

un puntero nulo-a-int es de tipo distinto de un puntero nulo-a-char (aunque ambos coincidan en que su Rvalue es 0) por tanto no pueden ser comparados La comparacioacuten de dos punteros nulos del mismo tipo conduce a que son iguales Ejemplo

int pint = NULLchar pchar = NULLif (pint == pchar) cout ltlt Iguales Error

La uacuteltima sentencia produce un error de compilacioacuten Error Nonportable pointer comparison in

Es un error deferenciar ( 4911) un puntero nulo ademaacutes el intento de utilizar el valor obtenido puede dar lugar a un error de ejecucioacuten Por ejemplo refirieacutendonos al caso anterior

int x = pint Error

Recordar que cuando falla el operador de modelado dynamic_cast ( 499c) sobre un puntero el resultado es un puntero nulo Tambieacuten que algunas funciones de la Libreriacutea Estaacutendar devuelven punteros incluso el operador new devuelve un puntero y en algunas implementaciones antiguas el aviso de error en la operacioacuten de este operador se realizaba devolviendo un puntero nulo

sect3 Inicializar punteros

En general los punteros pueden ser inicializados como otra variable cualquiera desde luego solo tiene sentido que el valor sea la direccioacuten de inicio del almacenamiento de un objeto del tipo adecuado En otras palabras un valor que sea una direccioacuten de memoria Como existe un operador que precisamente proporciona la direccioacuten de una variable (operador de

referencia amp 4911) la forma usual de inicializar un puntero suele ser asignaacutendole el valor devuelto por dicho operador Ejemplo

int x = 100int ptr declaracioacuten de ptr como puntero-a-intptr = ampx se le asigna la direccioacuten de una variable

Tambieacuten es muy frecuente iniciarlos con el valor devuelto por el operador new ( 4920) que precisamente devuelve un puntero a objeto Ejemplo

class C definicioacuten de una clase CC cptr declara cptr como puntero-a-Ccptr = new C() new crea una instancia de la clase y devuelve un puntero al objeto cuyo valor que es asignado a cptr

Nota los enteros y los punteros no son intercambiables con excepcioacuten del cero El cero es un valor que nunca puede adoptar un puntero en condiciones normales por esta razoacuten se utiliza para significar no asignado u otra circunstancia especial Recordar que la aritmeacutetica de punteros permite comparar dos punteros para igualdad o desigualdad conNULL

sect4 Punteros como argumentos

En muchas ocasiones los punteros se utilizan como argumentos a funciones De hecho la mayoriacutea de las veces en que las matrices o las cadenas de caracteres pasan como argumentos lo que en realidad pasa es un puntero al primer elemento Por ejemplo

char str = La Tacita de Plataprintf(La ciudad es sn str)

En este caso la funcioacuten printf recibe como segundo argumento str que es un puntero a la posicioacuten de memoria donde comienza el almacenamiento de la cadena La Tacita de Plata0

En cualquier caso es necesario declarar esta circunstancia en el prototipo y en la definicioacuten de la funcioacuten para que el compilador conozca que el argumento pasado es una variable tipo puntero Ejemplo

include ltiostreamhgt void func(int ) prototipo argumento definido como puntero-a-int void main () ============= int x = 35 int ptr = ampx func (ptr) se pasa puntero-a-int como argumento cout ltlt El valor es ahora ltlt x ltlt endl void func (int p) el argumento se define como puntero-a-int p += 10 el argumento es tratado como puntero

Salida

El valor es ahora 45

  • 2 Punteros
    • sect1 Presentacioacuten
    • sect2 Sinopsis
    • sect3 Generalidades
    • 422 Aritmeacutetica de punteros
      • sect1 Sinopsis
      • sect2 Operaciones permitidas
      • sect4 Ejemplos
      • sect5 Ejemplos
      • sect6 Conversioacuten de punteros
        • 421 Puntero a objeto
          • sect1 Sinopsis
          • sect2 Puntero nulo
          • sect3 Inicializar punteros
          • sect4 Punteros como argumentos
Page 5: Punteros destinada a ingpara el bienestar de la población, o bien, que puedan ser perjudiciales para la vida vegetal o animal, o impidan el uso normal de las propiedades y lugares

pt1 = voidpuntero geneacuterico

Asignacioacuten

La comparacioacuten de punteros solo tiene sentido entre punteros a elementos de la misma matriz en estas condiciones los operadores relacionales == = lt gt lt= gt= funcionan correctamente

Hemos sentildealado que cuando se realizan operaciones aritmeacuteticas con punteros se tiene en cuenta el tamantildeo de los objetos apuntados de modo que si un puntero es declarado apuntando-a-tipoX antildeadirle un entero n (al puntero) supone hacerlo hace avanzar un nuacutemero n de objetos tipoX Si tipoX tiene un tamantildeo de 10 bytes antildeadir 5 al puntero-a-tipoX lo hace avanzar 50 bytes en memoria (si se trata de punteros a elementos de una matriz supone avanzar n elementos en la matriz [3])

Del mismo modo la diferencia entre dos punteros resulta ser el nuacutemero de objetos tipoX que separa a dos punteros-a-tipoX Por ejemplo si ptr1 apunta al tercer elemento de una matriz y ptr2 apunta al deacutecimo elemento el resultado ptr2-ptr1 es 7 (en realidad la diferencia de dos punteros solo tiene sentido cuando ambos apuntan a la misma matriz)

observe que no estaacute definida la suma entre punteros

Si ptr es un puntero a un elemento de una matriz desde luego no existe un elemento tal como uno despueacutes del uacuteltimo pero se permite que ptr tenga dicho valor Si ptr1 apunta al uacuteltimo elemento del array ptr+1 es legal pero ptr+2 es indefinido (lo que a efectos praacutecticos significa que devolveraacute basura o un runtime volcado de memoria etc)

Si ptr apunta a uno despueacutes del uacuteltimo ptr-1 es legal (puntero al uacuteltimo elemento) Sin embargo aplicando el operador de indireccioacuten a un puntero despueacutes del uacuteltimo conduce a una indefinicioacuten

Informalmente puede pensarse en ptr + n como avanzar el puntero en (n sizeof(tipoX)) bytes siempre que ptr se mantenga en su rango legal (entre el primer elemento y uno despueacutes del uacuteltimo)

La resta de dos punteros a elementos de la misma matriz ptr1-ptr2 produce un entero n del tipo ptrdiff_t definido en ltstddefhgt Este nuacutemero representa la diferencia entre los subiacutendices i y j de los dos elementos referenciados (n = i-j) Para esto es necesario que ptr1 y ptr2 apunten a elementos existentes o uno despueacutes del uacuteltimo

sect4 Ejemplos

N Expresioacuten Resultado

1 ip+10 Produce otro puntero Si ip es un puntero al elemento m[j] de una matriz (dicho de otro modo si ip == ampm[j] ) el nuevo puntero apunta a otro elemento m[j+10] de la misma matriz con lo que (ip+10) == ampm[j+10]

2 y = ip+10 Antildeade 10 al objeto ip (objeto referenciado por ip) y lo asigna a y

3 ip += 1

Equivale a ip = ip + 1 Incrementa en 1 el valor (Rvalue) del objeto referenciado por ip

4 ++ip Igual que el anterior incrementa en 1 el valor del objeto referenciado por ip

5 ++ip El resultado es otro puntero Equivale a ip = ip+1 es decir incrementa en 1 el valor del puntero con lo que el nuevo puntero sentildeala a otra posicioacuten (ver caso 1)

6 ip++ Igual que el caso anterior Incrementa en 1 el valor del puntero

7 (ip)++ Igual que el caso 4 Dado que el pareacutentesis tiene maacutexima precedencia y asocia de

izquierda a derecha ( 490a) incrementa en 1 el valor del objeto referenciado por ip

Observe que el pareacutentesis es necesario sin eacutel la expresioacuten modifica la posicioacuten de memoria sentildealado porip Es decir se realiza ip++ Si ip es un puntero al elemento m[j] de una matriz el resultado es un puntero al elemento m[j+1] Despueacutes se tomariacutea la indireccioacuten es decir el resultado final seriacutea el valor del elemento m[j+1]

Por tanto la expresioacuten ip++ equivale a (ip++)

8 ip+1 El valor resultante es el de incrementar en 1 el valor del objeto apuntado por ip

sect5 Ejemplos

Consideremos copiar una cadena NTBS ( 323f) definida por un puntero a su origen s en un destino definido por un punterop Considerando que el final de la cadena estaacute sentildealado por el caraacutecter nulo el proceso podriacutea ser

while (s = 0) p = s copiar caraacutecter s++ p++

Teniendo en cuenta que estamos usando el postincremento ( 491) para s y p y que cualquier ltexpresioacutengt es cierta si ltexpresioacutengt = 0 Lo anterior seriacutea equivalente a

while (s ) p = s s++

p++

El incremento se puede expresar en la misma sentencia de asignacioacuten

while (s ) p++ = s++

La razoacuten es que p++ indica el caraacutecter apuntado por p antes que sea incrementado El postincremento ++ no cambia p hasta que el caraacutecter ha sido actualizado (primero se efectuacutea la asignacioacuten y despueacutes se incrementa) El orden de ejecucioacuten de las operaciones involucradas es

1- Se asigna p s2- Se incrementa s3- Se incrementa p

La comparacioacuten puede hacerse en el mismo momento que la copia de caracteres

while ( p++ = s++) sect51

La razoacuten es que despueacutes de la uacuteltima asignacioacuten que corresponderiacutea al caraacutecter 0 de s el resultado de la asignacioacuten seriacutea justamente este valor (0 == falso) y se saldriacutea del while

Por la razoacuten inversa la expresioacuten ++p indica el caraacutecter apuntado por p despueacutes que ha sido incrementado Ambos tipos de expresiones de asignacioacuten con punteros simultaneadas con prepost incrementosdecrementos son muy frecuentes en los bucles que involucran punteros De hecho las expresiones

p++ = val cargar la pila con valval = --p sacar de la pila el uacuteltimo valor asignarlo a val

son las sentencias estaacutendar de cargardescargar valores val de una pila LIFO [1] manejada por un puntero p

Nota esta capacidad de C++ para permitir formas de coacutedigo tan extraordinariamente compactas tiene fervientes defensores y aceacuterrimos detractores En mi opinioacuten el uacutenico problema es que sin un entrenamiento previo la primera vez que se topa uno con una expresioacuten como la sect51 anterior puede quedarse bastante perplejo Aunque en realidad solo

se trate de uno maacutes de los idioms ( 413) de fondo de armario de cualquier programador C++

sect6 Conversioacuten de punteros

Un puntero de un tipo (tipoX) puede ser convertido a otro (tipoY) usando el mecanismo de conversioacuten o modelado de tipos que utiliza el operador (tipoY)

Ejemplo

char str str puntero a charint ip ip puntero a intstr = (char )ip asignacioacuten str = ip (ip puntero a char)

De forma general el operador-moldeador (tipoX ) puede convertir el operando (un puntero de cualquier tipo) a un puntero-a-tipoX

Como ejemplo de lo insidioso que pueden llegar a ser algunos rincones de los compiladores C++ considere el siguiente ejemplo

long strRchr (const Stringamp str char needle) unsigned long stLen = strlen() for (register unsigned long i = stLen - 1 igt=0 --i) if ((strcptr + i) == needle) return i return -1L

Se trata de una funcioacuten que proporciona la posicioacuten de la uacuteltima ocurrencia de un caraacutecter (needle) en un una cadena de caracteres (str) En nuestro caso los objetos de la clase String albergan cadenas alfanumeacutericas En concreto el meacutetodo len() proporciona la longitud de la cadena y el miembro cptr es un puntero al primer caraacutecter La funcioacuten devuelve -1 si el caraacutecter no se encuentre en la cadena En caso contrario devuelve la posicioacuten empezando a contar desde cero para el primer caraacutecter

Aunque compila sin dificultad la rutina anterior produce un extrantildeo resultado negativo en las pruebas realizadas con el compilador BC++ 55 mientras que con GNU G++ 342-20040916-1 para Windows produce un error fatal de runtime Despueacutes de perder un par de horas intentando diagnosticar el problema y haber sopesado todas las posibilidades (incluyendo que el compilador estuviese poseido -) resultoacute que estaba en el resultado de strcptr + i (suma del puntero con el incremento) Cuando i es un unsigned long la suma con el puntero produce un resultado negativo Ninguacuten otro tipo para i produciacutea error Por ejemplo int o long

Observe que este comportamiento anoacutemalo se produce a pesar de lo sentildealado al respecto por el Estaacutendar [4] y de que los unsigned long son tipos enteros

421 Puntero a objeto

sect1 Sinopsis

Un puntero-a-tipoX (puntero a un objeto de tipoX) almacena la direccioacuten de un objeto del tipo sentildealado es decir sentildeala a un objeto tipoX Puesto que los punteros son objetos puede haber un puntero apuntando a un puntero (asiacute sucesivamente) Los objetos a los que se apunta suelen ser matrices estructuras uniones y clases

Nota aquiacute consideramos que un objeto es una regioacuten especiacutefica de memoria que puede contener un valor (o conjunto de valores) fijo o variable Esta acepcioacuten del vocablo es diferente (maacutes amplia) que cuando designa la instancia de una clase

Las explicaciones que siguen son vaacutelidas para punteros objetos de cualquier tipo (que no sean funciones) pero cuando se trata especiacuteficamente de punteros a clases e instancias de clases existen ciertas particularidades en la notacioacuten asiacute que les hemos dedicado un epiacutegrafe especiacutefico

con algunos comentarios ( 421f)

Nota tradicionalmente se considera que punteros y matrices estaacuten estrechamente relacionados [1] hasta el punto de ser estudiados simultaacuteneamente De hecho cualquier operacioacuten que puede efectuarse entre subiacutendices de matrices puede efectuarse con punteros en general de forma maacutes raacutepida (aunque algo maacutes difiacutecil de entender por el principiante)

Ademaacutes el operador de elemento de matriz [ ] se define en teacuterminos de ser un puntero ( 4916)

Los punteros a objeto tiene su propia aritmeacutetica (rudimentaria) de forma que pueden ser incrementados disminuidos y comparados cuando se exploran matrices u otras estructuras complejas

sect2 Puntero nulo

Un puntero nulo es un puntero que apunta a una direccioacuten que no corresponde a ninguacuten objeto del programa Asignando la constante entera 0 a un puntero se le asigna el valor nulo Para mejor ligibilidad puede utilizarse la constante manifiesta NULL(definida en la libreriacutea de cabeceras estaacutendar ltstdiohgt) Ejemplo

int punt1 L1 Declara punt1punt1 = 0 L2 define punt1 como puntero nulopunt1 = NULL Equivalente a la anterior

Nota la cuestioacuten de la inicializacioacuten del puntero nulo es uno de los puntos de controversia para los teoacutericos del lenguaje En rigor la sentencia L2 anterior es erroacutenea ya que el tipo de punt1 es

puntero-a-int mientras que 0 es una constante numeacuterica (int por defecto) a pesar de lo cual es aceptada sin rechistar por el compilador [2] Lo sintaacutecticamente correcto seriacutea realizar un modelado

adecuado ( 499)

punt1 = static_castltintgt (0)

Es interesante observar que los punteros nulos de tipos distintos son distintos entre si Por ejemplo

un puntero nulo-a-int es de tipo distinto de un puntero nulo-a-char (aunque ambos coincidan en que su Rvalue es 0) por tanto no pueden ser comparados La comparacioacuten de dos punteros nulos del mismo tipo conduce a que son iguales Ejemplo

int pint = NULLchar pchar = NULLif (pint == pchar) cout ltlt Iguales Error

La uacuteltima sentencia produce un error de compilacioacuten Error Nonportable pointer comparison in

Es un error deferenciar ( 4911) un puntero nulo ademaacutes el intento de utilizar el valor obtenido puede dar lugar a un error de ejecucioacuten Por ejemplo refirieacutendonos al caso anterior

int x = pint Error

Recordar que cuando falla el operador de modelado dynamic_cast ( 499c) sobre un puntero el resultado es un puntero nulo Tambieacuten que algunas funciones de la Libreriacutea Estaacutendar devuelven punteros incluso el operador new devuelve un puntero y en algunas implementaciones antiguas el aviso de error en la operacioacuten de este operador se realizaba devolviendo un puntero nulo

sect3 Inicializar punteros

En general los punteros pueden ser inicializados como otra variable cualquiera desde luego solo tiene sentido que el valor sea la direccioacuten de inicio del almacenamiento de un objeto del tipo adecuado En otras palabras un valor que sea una direccioacuten de memoria Como existe un operador que precisamente proporciona la direccioacuten de una variable (operador de

referencia amp 4911) la forma usual de inicializar un puntero suele ser asignaacutendole el valor devuelto por dicho operador Ejemplo

int x = 100int ptr declaracioacuten de ptr como puntero-a-intptr = ampx se le asigna la direccioacuten de una variable

Tambieacuten es muy frecuente iniciarlos con el valor devuelto por el operador new ( 4920) que precisamente devuelve un puntero a objeto Ejemplo

class C definicioacuten de una clase CC cptr declara cptr como puntero-a-Ccptr = new C() new crea una instancia de la clase y devuelve un puntero al objeto cuyo valor que es asignado a cptr

Nota los enteros y los punteros no son intercambiables con excepcioacuten del cero El cero es un valor que nunca puede adoptar un puntero en condiciones normales por esta razoacuten se utiliza para significar no asignado u otra circunstancia especial Recordar que la aritmeacutetica de punteros permite comparar dos punteros para igualdad o desigualdad conNULL

sect4 Punteros como argumentos

En muchas ocasiones los punteros se utilizan como argumentos a funciones De hecho la mayoriacutea de las veces en que las matrices o las cadenas de caracteres pasan como argumentos lo que en realidad pasa es un puntero al primer elemento Por ejemplo

char str = La Tacita de Plataprintf(La ciudad es sn str)

En este caso la funcioacuten printf recibe como segundo argumento str que es un puntero a la posicioacuten de memoria donde comienza el almacenamiento de la cadena La Tacita de Plata0

En cualquier caso es necesario declarar esta circunstancia en el prototipo y en la definicioacuten de la funcioacuten para que el compilador conozca que el argumento pasado es una variable tipo puntero Ejemplo

include ltiostreamhgt void func(int ) prototipo argumento definido como puntero-a-int void main () ============= int x = 35 int ptr = ampx func (ptr) se pasa puntero-a-int como argumento cout ltlt El valor es ahora ltlt x ltlt endl void func (int p) el argumento se define como puntero-a-int p += 10 el argumento es tratado como puntero

Salida

El valor es ahora 45

  • 2 Punteros
    • sect1 Presentacioacuten
    • sect2 Sinopsis
    • sect3 Generalidades
    • 422 Aritmeacutetica de punteros
      • sect1 Sinopsis
      • sect2 Operaciones permitidas
      • sect4 Ejemplos
      • sect5 Ejemplos
      • sect6 Conversioacuten de punteros
        • 421 Puntero a objeto
          • sect1 Sinopsis
          • sect2 Puntero nulo
          • sect3 Inicializar punteros
          • sect4 Punteros como argumentos
Page 6: Punteros destinada a ingpara el bienestar de la población, o bien, que puedan ser perjudiciales para la vida vegetal o animal, o impidan el uso normal de las propiedades y lugares

N Expresioacuten Resultado

1 ip+10 Produce otro puntero Si ip es un puntero al elemento m[j] de una matriz (dicho de otro modo si ip == ampm[j] ) el nuevo puntero apunta a otro elemento m[j+10] de la misma matriz con lo que (ip+10) == ampm[j+10]

2 y = ip+10 Antildeade 10 al objeto ip (objeto referenciado por ip) y lo asigna a y

3 ip += 1

Equivale a ip = ip + 1 Incrementa en 1 el valor (Rvalue) del objeto referenciado por ip

4 ++ip Igual que el anterior incrementa en 1 el valor del objeto referenciado por ip

5 ++ip El resultado es otro puntero Equivale a ip = ip+1 es decir incrementa en 1 el valor del puntero con lo que el nuevo puntero sentildeala a otra posicioacuten (ver caso 1)

6 ip++ Igual que el caso anterior Incrementa en 1 el valor del puntero

7 (ip)++ Igual que el caso 4 Dado que el pareacutentesis tiene maacutexima precedencia y asocia de

izquierda a derecha ( 490a) incrementa en 1 el valor del objeto referenciado por ip

Observe que el pareacutentesis es necesario sin eacutel la expresioacuten modifica la posicioacuten de memoria sentildealado porip Es decir se realiza ip++ Si ip es un puntero al elemento m[j] de una matriz el resultado es un puntero al elemento m[j+1] Despueacutes se tomariacutea la indireccioacuten es decir el resultado final seriacutea el valor del elemento m[j+1]

Por tanto la expresioacuten ip++ equivale a (ip++)

8 ip+1 El valor resultante es el de incrementar en 1 el valor del objeto apuntado por ip

sect5 Ejemplos

Consideremos copiar una cadena NTBS ( 323f) definida por un puntero a su origen s en un destino definido por un punterop Considerando que el final de la cadena estaacute sentildealado por el caraacutecter nulo el proceso podriacutea ser

while (s = 0) p = s copiar caraacutecter s++ p++

Teniendo en cuenta que estamos usando el postincremento ( 491) para s y p y que cualquier ltexpresioacutengt es cierta si ltexpresioacutengt = 0 Lo anterior seriacutea equivalente a

while (s ) p = s s++

p++

El incremento se puede expresar en la misma sentencia de asignacioacuten

while (s ) p++ = s++

La razoacuten es que p++ indica el caraacutecter apuntado por p antes que sea incrementado El postincremento ++ no cambia p hasta que el caraacutecter ha sido actualizado (primero se efectuacutea la asignacioacuten y despueacutes se incrementa) El orden de ejecucioacuten de las operaciones involucradas es

1- Se asigna p s2- Se incrementa s3- Se incrementa p

La comparacioacuten puede hacerse en el mismo momento que la copia de caracteres

while ( p++ = s++) sect51

La razoacuten es que despueacutes de la uacuteltima asignacioacuten que corresponderiacutea al caraacutecter 0 de s el resultado de la asignacioacuten seriacutea justamente este valor (0 == falso) y se saldriacutea del while

Por la razoacuten inversa la expresioacuten ++p indica el caraacutecter apuntado por p despueacutes que ha sido incrementado Ambos tipos de expresiones de asignacioacuten con punteros simultaneadas con prepost incrementosdecrementos son muy frecuentes en los bucles que involucran punteros De hecho las expresiones

p++ = val cargar la pila con valval = --p sacar de la pila el uacuteltimo valor asignarlo a val

son las sentencias estaacutendar de cargardescargar valores val de una pila LIFO [1] manejada por un puntero p

Nota esta capacidad de C++ para permitir formas de coacutedigo tan extraordinariamente compactas tiene fervientes defensores y aceacuterrimos detractores En mi opinioacuten el uacutenico problema es que sin un entrenamiento previo la primera vez que se topa uno con una expresioacuten como la sect51 anterior puede quedarse bastante perplejo Aunque en realidad solo

se trate de uno maacutes de los idioms ( 413) de fondo de armario de cualquier programador C++

sect6 Conversioacuten de punteros

Un puntero de un tipo (tipoX) puede ser convertido a otro (tipoY) usando el mecanismo de conversioacuten o modelado de tipos que utiliza el operador (tipoY)

Ejemplo

char str str puntero a charint ip ip puntero a intstr = (char )ip asignacioacuten str = ip (ip puntero a char)

De forma general el operador-moldeador (tipoX ) puede convertir el operando (un puntero de cualquier tipo) a un puntero-a-tipoX

Como ejemplo de lo insidioso que pueden llegar a ser algunos rincones de los compiladores C++ considere el siguiente ejemplo

long strRchr (const Stringamp str char needle) unsigned long stLen = strlen() for (register unsigned long i = stLen - 1 igt=0 --i) if ((strcptr + i) == needle) return i return -1L

Se trata de una funcioacuten que proporciona la posicioacuten de la uacuteltima ocurrencia de un caraacutecter (needle) en un una cadena de caracteres (str) En nuestro caso los objetos de la clase String albergan cadenas alfanumeacutericas En concreto el meacutetodo len() proporciona la longitud de la cadena y el miembro cptr es un puntero al primer caraacutecter La funcioacuten devuelve -1 si el caraacutecter no se encuentre en la cadena En caso contrario devuelve la posicioacuten empezando a contar desde cero para el primer caraacutecter

Aunque compila sin dificultad la rutina anterior produce un extrantildeo resultado negativo en las pruebas realizadas con el compilador BC++ 55 mientras que con GNU G++ 342-20040916-1 para Windows produce un error fatal de runtime Despueacutes de perder un par de horas intentando diagnosticar el problema y haber sopesado todas las posibilidades (incluyendo que el compilador estuviese poseido -) resultoacute que estaba en el resultado de strcptr + i (suma del puntero con el incremento) Cuando i es un unsigned long la suma con el puntero produce un resultado negativo Ninguacuten otro tipo para i produciacutea error Por ejemplo int o long

Observe que este comportamiento anoacutemalo se produce a pesar de lo sentildealado al respecto por el Estaacutendar [4] y de que los unsigned long son tipos enteros

421 Puntero a objeto

sect1 Sinopsis

Un puntero-a-tipoX (puntero a un objeto de tipoX) almacena la direccioacuten de un objeto del tipo sentildealado es decir sentildeala a un objeto tipoX Puesto que los punteros son objetos puede haber un puntero apuntando a un puntero (asiacute sucesivamente) Los objetos a los que se apunta suelen ser matrices estructuras uniones y clases

Nota aquiacute consideramos que un objeto es una regioacuten especiacutefica de memoria que puede contener un valor (o conjunto de valores) fijo o variable Esta acepcioacuten del vocablo es diferente (maacutes amplia) que cuando designa la instancia de una clase

Las explicaciones que siguen son vaacutelidas para punteros objetos de cualquier tipo (que no sean funciones) pero cuando se trata especiacuteficamente de punteros a clases e instancias de clases existen ciertas particularidades en la notacioacuten asiacute que les hemos dedicado un epiacutegrafe especiacutefico

con algunos comentarios ( 421f)

Nota tradicionalmente se considera que punteros y matrices estaacuten estrechamente relacionados [1] hasta el punto de ser estudiados simultaacuteneamente De hecho cualquier operacioacuten que puede efectuarse entre subiacutendices de matrices puede efectuarse con punteros en general de forma maacutes raacutepida (aunque algo maacutes difiacutecil de entender por el principiante)

Ademaacutes el operador de elemento de matriz [ ] se define en teacuterminos de ser un puntero ( 4916)

Los punteros a objeto tiene su propia aritmeacutetica (rudimentaria) de forma que pueden ser incrementados disminuidos y comparados cuando se exploran matrices u otras estructuras complejas

sect2 Puntero nulo

Un puntero nulo es un puntero que apunta a una direccioacuten que no corresponde a ninguacuten objeto del programa Asignando la constante entera 0 a un puntero se le asigna el valor nulo Para mejor ligibilidad puede utilizarse la constante manifiesta NULL(definida en la libreriacutea de cabeceras estaacutendar ltstdiohgt) Ejemplo

int punt1 L1 Declara punt1punt1 = 0 L2 define punt1 como puntero nulopunt1 = NULL Equivalente a la anterior

Nota la cuestioacuten de la inicializacioacuten del puntero nulo es uno de los puntos de controversia para los teoacutericos del lenguaje En rigor la sentencia L2 anterior es erroacutenea ya que el tipo de punt1 es

puntero-a-int mientras que 0 es una constante numeacuterica (int por defecto) a pesar de lo cual es aceptada sin rechistar por el compilador [2] Lo sintaacutecticamente correcto seriacutea realizar un modelado

adecuado ( 499)

punt1 = static_castltintgt (0)

Es interesante observar que los punteros nulos de tipos distintos son distintos entre si Por ejemplo

un puntero nulo-a-int es de tipo distinto de un puntero nulo-a-char (aunque ambos coincidan en que su Rvalue es 0) por tanto no pueden ser comparados La comparacioacuten de dos punteros nulos del mismo tipo conduce a que son iguales Ejemplo

int pint = NULLchar pchar = NULLif (pint == pchar) cout ltlt Iguales Error

La uacuteltima sentencia produce un error de compilacioacuten Error Nonportable pointer comparison in

Es un error deferenciar ( 4911) un puntero nulo ademaacutes el intento de utilizar el valor obtenido puede dar lugar a un error de ejecucioacuten Por ejemplo refirieacutendonos al caso anterior

int x = pint Error

Recordar que cuando falla el operador de modelado dynamic_cast ( 499c) sobre un puntero el resultado es un puntero nulo Tambieacuten que algunas funciones de la Libreriacutea Estaacutendar devuelven punteros incluso el operador new devuelve un puntero y en algunas implementaciones antiguas el aviso de error en la operacioacuten de este operador se realizaba devolviendo un puntero nulo

sect3 Inicializar punteros

En general los punteros pueden ser inicializados como otra variable cualquiera desde luego solo tiene sentido que el valor sea la direccioacuten de inicio del almacenamiento de un objeto del tipo adecuado En otras palabras un valor que sea una direccioacuten de memoria Como existe un operador que precisamente proporciona la direccioacuten de una variable (operador de

referencia amp 4911) la forma usual de inicializar un puntero suele ser asignaacutendole el valor devuelto por dicho operador Ejemplo

int x = 100int ptr declaracioacuten de ptr como puntero-a-intptr = ampx se le asigna la direccioacuten de una variable

Tambieacuten es muy frecuente iniciarlos con el valor devuelto por el operador new ( 4920) que precisamente devuelve un puntero a objeto Ejemplo

class C definicioacuten de una clase CC cptr declara cptr como puntero-a-Ccptr = new C() new crea una instancia de la clase y devuelve un puntero al objeto cuyo valor que es asignado a cptr

Nota los enteros y los punteros no son intercambiables con excepcioacuten del cero El cero es un valor que nunca puede adoptar un puntero en condiciones normales por esta razoacuten se utiliza para significar no asignado u otra circunstancia especial Recordar que la aritmeacutetica de punteros permite comparar dos punteros para igualdad o desigualdad conNULL

sect4 Punteros como argumentos

En muchas ocasiones los punteros se utilizan como argumentos a funciones De hecho la mayoriacutea de las veces en que las matrices o las cadenas de caracteres pasan como argumentos lo que en realidad pasa es un puntero al primer elemento Por ejemplo

char str = La Tacita de Plataprintf(La ciudad es sn str)

En este caso la funcioacuten printf recibe como segundo argumento str que es un puntero a la posicioacuten de memoria donde comienza el almacenamiento de la cadena La Tacita de Plata0

En cualquier caso es necesario declarar esta circunstancia en el prototipo y en la definicioacuten de la funcioacuten para que el compilador conozca que el argumento pasado es una variable tipo puntero Ejemplo

include ltiostreamhgt void func(int ) prototipo argumento definido como puntero-a-int void main () ============= int x = 35 int ptr = ampx func (ptr) se pasa puntero-a-int como argumento cout ltlt El valor es ahora ltlt x ltlt endl void func (int p) el argumento se define como puntero-a-int p += 10 el argumento es tratado como puntero

Salida

El valor es ahora 45

  • 2 Punteros
    • sect1 Presentacioacuten
    • sect2 Sinopsis
    • sect3 Generalidades
    • 422 Aritmeacutetica de punteros
      • sect1 Sinopsis
      • sect2 Operaciones permitidas
      • sect4 Ejemplos
      • sect5 Ejemplos
      • sect6 Conversioacuten de punteros
        • 421 Puntero a objeto
          • sect1 Sinopsis
          • sect2 Puntero nulo
          • sect3 Inicializar punteros
          • sect4 Punteros como argumentos
Page 7: Punteros destinada a ingpara el bienestar de la población, o bien, que puedan ser perjudiciales para la vida vegetal o animal, o impidan el uso normal de las propiedades y lugares

p++

El incremento se puede expresar en la misma sentencia de asignacioacuten

while (s ) p++ = s++

La razoacuten es que p++ indica el caraacutecter apuntado por p antes que sea incrementado El postincremento ++ no cambia p hasta que el caraacutecter ha sido actualizado (primero se efectuacutea la asignacioacuten y despueacutes se incrementa) El orden de ejecucioacuten de las operaciones involucradas es

1- Se asigna p s2- Se incrementa s3- Se incrementa p

La comparacioacuten puede hacerse en el mismo momento que la copia de caracteres

while ( p++ = s++) sect51

La razoacuten es que despueacutes de la uacuteltima asignacioacuten que corresponderiacutea al caraacutecter 0 de s el resultado de la asignacioacuten seriacutea justamente este valor (0 == falso) y se saldriacutea del while

Por la razoacuten inversa la expresioacuten ++p indica el caraacutecter apuntado por p despueacutes que ha sido incrementado Ambos tipos de expresiones de asignacioacuten con punteros simultaneadas con prepost incrementosdecrementos son muy frecuentes en los bucles que involucran punteros De hecho las expresiones

p++ = val cargar la pila con valval = --p sacar de la pila el uacuteltimo valor asignarlo a val

son las sentencias estaacutendar de cargardescargar valores val de una pila LIFO [1] manejada por un puntero p

Nota esta capacidad de C++ para permitir formas de coacutedigo tan extraordinariamente compactas tiene fervientes defensores y aceacuterrimos detractores En mi opinioacuten el uacutenico problema es que sin un entrenamiento previo la primera vez que se topa uno con una expresioacuten como la sect51 anterior puede quedarse bastante perplejo Aunque en realidad solo

se trate de uno maacutes de los idioms ( 413) de fondo de armario de cualquier programador C++

sect6 Conversioacuten de punteros

Un puntero de un tipo (tipoX) puede ser convertido a otro (tipoY) usando el mecanismo de conversioacuten o modelado de tipos que utiliza el operador (tipoY)

Ejemplo

char str str puntero a charint ip ip puntero a intstr = (char )ip asignacioacuten str = ip (ip puntero a char)

De forma general el operador-moldeador (tipoX ) puede convertir el operando (un puntero de cualquier tipo) a un puntero-a-tipoX

Como ejemplo de lo insidioso que pueden llegar a ser algunos rincones de los compiladores C++ considere el siguiente ejemplo

long strRchr (const Stringamp str char needle) unsigned long stLen = strlen() for (register unsigned long i = stLen - 1 igt=0 --i) if ((strcptr + i) == needle) return i return -1L

Se trata de una funcioacuten que proporciona la posicioacuten de la uacuteltima ocurrencia de un caraacutecter (needle) en un una cadena de caracteres (str) En nuestro caso los objetos de la clase String albergan cadenas alfanumeacutericas En concreto el meacutetodo len() proporciona la longitud de la cadena y el miembro cptr es un puntero al primer caraacutecter La funcioacuten devuelve -1 si el caraacutecter no se encuentre en la cadena En caso contrario devuelve la posicioacuten empezando a contar desde cero para el primer caraacutecter

Aunque compila sin dificultad la rutina anterior produce un extrantildeo resultado negativo en las pruebas realizadas con el compilador BC++ 55 mientras que con GNU G++ 342-20040916-1 para Windows produce un error fatal de runtime Despueacutes de perder un par de horas intentando diagnosticar el problema y haber sopesado todas las posibilidades (incluyendo que el compilador estuviese poseido -) resultoacute que estaba en el resultado de strcptr + i (suma del puntero con el incremento) Cuando i es un unsigned long la suma con el puntero produce un resultado negativo Ninguacuten otro tipo para i produciacutea error Por ejemplo int o long

Observe que este comportamiento anoacutemalo se produce a pesar de lo sentildealado al respecto por el Estaacutendar [4] y de que los unsigned long son tipos enteros

421 Puntero a objeto

sect1 Sinopsis

Un puntero-a-tipoX (puntero a un objeto de tipoX) almacena la direccioacuten de un objeto del tipo sentildealado es decir sentildeala a un objeto tipoX Puesto que los punteros son objetos puede haber un puntero apuntando a un puntero (asiacute sucesivamente) Los objetos a los que se apunta suelen ser matrices estructuras uniones y clases

Nota aquiacute consideramos que un objeto es una regioacuten especiacutefica de memoria que puede contener un valor (o conjunto de valores) fijo o variable Esta acepcioacuten del vocablo es diferente (maacutes amplia) que cuando designa la instancia de una clase

Las explicaciones que siguen son vaacutelidas para punteros objetos de cualquier tipo (que no sean funciones) pero cuando se trata especiacuteficamente de punteros a clases e instancias de clases existen ciertas particularidades en la notacioacuten asiacute que les hemos dedicado un epiacutegrafe especiacutefico

con algunos comentarios ( 421f)

Nota tradicionalmente se considera que punteros y matrices estaacuten estrechamente relacionados [1] hasta el punto de ser estudiados simultaacuteneamente De hecho cualquier operacioacuten que puede efectuarse entre subiacutendices de matrices puede efectuarse con punteros en general de forma maacutes raacutepida (aunque algo maacutes difiacutecil de entender por el principiante)

Ademaacutes el operador de elemento de matriz [ ] se define en teacuterminos de ser un puntero ( 4916)

Los punteros a objeto tiene su propia aritmeacutetica (rudimentaria) de forma que pueden ser incrementados disminuidos y comparados cuando se exploran matrices u otras estructuras complejas

sect2 Puntero nulo

Un puntero nulo es un puntero que apunta a una direccioacuten que no corresponde a ninguacuten objeto del programa Asignando la constante entera 0 a un puntero se le asigna el valor nulo Para mejor ligibilidad puede utilizarse la constante manifiesta NULL(definida en la libreriacutea de cabeceras estaacutendar ltstdiohgt) Ejemplo

int punt1 L1 Declara punt1punt1 = 0 L2 define punt1 como puntero nulopunt1 = NULL Equivalente a la anterior

Nota la cuestioacuten de la inicializacioacuten del puntero nulo es uno de los puntos de controversia para los teoacutericos del lenguaje En rigor la sentencia L2 anterior es erroacutenea ya que el tipo de punt1 es

puntero-a-int mientras que 0 es una constante numeacuterica (int por defecto) a pesar de lo cual es aceptada sin rechistar por el compilador [2] Lo sintaacutecticamente correcto seriacutea realizar un modelado

adecuado ( 499)

punt1 = static_castltintgt (0)

Es interesante observar que los punteros nulos de tipos distintos son distintos entre si Por ejemplo

un puntero nulo-a-int es de tipo distinto de un puntero nulo-a-char (aunque ambos coincidan en que su Rvalue es 0) por tanto no pueden ser comparados La comparacioacuten de dos punteros nulos del mismo tipo conduce a que son iguales Ejemplo

int pint = NULLchar pchar = NULLif (pint == pchar) cout ltlt Iguales Error

La uacuteltima sentencia produce un error de compilacioacuten Error Nonportable pointer comparison in

Es un error deferenciar ( 4911) un puntero nulo ademaacutes el intento de utilizar el valor obtenido puede dar lugar a un error de ejecucioacuten Por ejemplo refirieacutendonos al caso anterior

int x = pint Error

Recordar que cuando falla el operador de modelado dynamic_cast ( 499c) sobre un puntero el resultado es un puntero nulo Tambieacuten que algunas funciones de la Libreriacutea Estaacutendar devuelven punteros incluso el operador new devuelve un puntero y en algunas implementaciones antiguas el aviso de error en la operacioacuten de este operador se realizaba devolviendo un puntero nulo

sect3 Inicializar punteros

En general los punteros pueden ser inicializados como otra variable cualquiera desde luego solo tiene sentido que el valor sea la direccioacuten de inicio del almacenamiento de un objeto del tipo adecuado En otras palabras un valor que sea una direccioacuten de memoria Como existe un operador que precisamente proporciona la direccioacuten de una variable (operador de

referencia amp 4911) la forma usual de inicializar un puntero suele ser asignaacutendole el valor devuelto por dicho operador Ejemplo

int x = 100int ptr declaracioacuten de ptr como puntero-a-intptr = ampx se le asigna la direccioacuten de una variable

Tambieacuten es muy frecuente iniciarlos con el valor devuelto por el operador new ( 4920) que precisamente devuelve un puntero a objeto Ejemplo

class C definicioacuten de una clase CC cptr declara cptr como puntero-a-Ccptr = new C() new crea una instancia de la clase y devuelve un puntero al objeto cuyo valor que es asignado a cptr

Nota los enteros y los punteros no son intercambiables con excepcioacuten del cero El cero es un valor que nunca puede adoptar un puntero en condiciones normales por esta razoacuten se utiliza para significar no asignado u otra circunstancia especial Recordar que la aritmeacutetica de punteros permite comparar dos punteros para igualdad o desigualdad conNULL

sect4 Punteros como argumentos

En muchas ocasiones los punteros se utilizan como argumentos a funciones De hecho la mayoriacutea de las veces en que las matrices o las cadenas de caracteres pasan como argumentos lo que en realidad pasa es un puntero al primer elemento Por ejemplo

char str = La Tacita de Plataprintf(La ciudad es sn str)

En este caso la funcioacuten printf recibe como segundo argumento str que es un puntero a la posicioacuten de memoria donde comienza el almacenamiento de la cadena La Tacita de Plata0

En cualquier caso es necesario declarar esta circunstancia en el prototipo y en la definicioacuten de la funcioacuten para que el compilador conozca que el argumento pasado es una variable tipo puntero Ejemplo

include ltiostreamhgt void func(int ) prototipo argumento definido como puntero-a-int void main () ============= int x = 35 int ptr = ampx func (ptr) se pasa puntero-a-int como argumento cout ltlt El valor es ahora ltlt x ltlt endl void func (int p) el argumento se define como puntero-a-int p += 10 el argumento es tratado como puntero

Salida

El valor es ahora 45

  • 2 Punteros
    • sect1 Presentacioacuten
    • sect2 Sinopsis
    • sect3 Generalidades
    • 422 Aritmeacutetica de punteros
      • sect1 Sinopsis
      • sect2 Operaciones permitidas
      • sect4 Ejemplos
      • sect5 Ejemplos
      • sect6 Conversioacuten de punteros
        • 421 Puntero a objeto
          • sect1 Sinopsis
          • sect2 Puntero nulo
          • sect3 Inicializar punteros
          • sect4 Punteros como argumentos
Page 8: Punteros destinada a ingpara el bienestar de la población, o bien, que puedan ser perjudiciales para la vida vegetal o animal, o impidan el uso normal de las propiedades y lugares

Ejemplo

char str str puntero a charint ip ip puntero a intstr = (char )ip asignacioacuten str = ip (ip puntero a char)

De forma general el operador-moldeador (tipoX ) puede convertir el operando (un puntero de cualquier tipo) a un puntero-a-tipoX

Como ejemplo de lo insidioso que pueden llegar a ser algunos rincones de los compiladores C++ considere el siguiente ejemplo

long strRchr (const Stringamp str char needle) unsigned long stLen = strlen() for (register unsigned long i = stLen - 1 igt=0 --i) if ((strcptr + i) == needle) return i return -1L

Se trata de una funcioacuten que proporciona la posicioacuten de la uacuteltima ocurrencia de un caraacutecter (needle) en un una cadena de caracteres (str) En nuestro caso los objetos de la clase String albergan cadenas alfanumeacutericas En concreto el meacutetodo len() proporciona la longitud de la cadena y el miembro cptr es un puntero al primer caraacutecter La funcioacuten devuelve -1 si el caraacutecter no se encuentre en la cadena En caso contrario devuelve la posicioacuten empezando a contar desde cero para el primer caraacutecter

Aunque compila sin dificultad la rutina anterior produce un extrantildeo resultado negativo en las pruebas realizadas con el compilador BC++ 55 mientras que con GNU G++ 342-20040916-1 para Windows produce un error fatal de runtime Despueacutes de perder un par de horas intentando diagnosticar el problema y haber sopesado todas las posibilidades (incluyendo que el compilador estuviese poseido -) resultoacute que estaba en el resultado de strcptr + i (suma del puntero con el incremento) Cuando i es un unsigned long la suma con el puntero produce un resultado negativo Ninguacuten otro tipo para i produciacutea error Por ejemplo int o long

Observe que este comportamiento anoacutemalo se produce a pesar de lo sentildealado al respecto por el Estaacutendar [4] y de que los unsigned long son tipos enteros

421 Puntero a objeto

sect1 Sinopsis

Un puntero-a-tipoX (puntero a un objeto de tipoX) almacena la direccioacuten de un objeto del tipo sentildealado es decir sentildeala a un objeto tipoX Puesto que los punteros son objetos puede haber un puntero apuntando a un puntero (asiacute sucesivamente) Los objetos a los que se apunta suelen ser matrices estructuras uniones y clases

Nota aquiacute consideramos que un objeto es una regioacuten especiacutefica de memoria que puede contener un valor (o conjunto de valores) fijo o variable Esta acepcioacuten del vocablo es diferente (maacutes amplia) que cuando designa la instancia de una clase

Las explicaciones que siguen son vaacutelidas para punteros objetos de cualquier tipo (que no sean funciones) pero cuando se trata especiacuteficamente de punteros a clases e instancias de clases existen ciertas particularidades en la notacioacuten asiacute que les hemos dedicado un epiacutegrafe especiacutefico

con algunos comentarios ( 421f)

Nota tradicionalmente se considera que punteros y matrices estaacuten estrechamente relacionados [1] hasta el punto de ser estudiados simultaacuteneamente De hecho cualquier operacioacuten que puede efectuarse entre subiacutendices de matrices puede efectuarse con punteros en general de forma maacutes raacutepida (aunque algo maacutes difiacutecil de entender por el principiante)

Ademaacutes el operador de elemento de matriz [ ] se define en teacuterminos de ser un puntero ( 4916)

Los punteros a objeto tiene su propia aritmeacutetica (rudimentaria) de forma que pueden ser incrementados disminuidos y comparados cuando se exploran matrices u otras estructuras complejas

sect2 Puntero nulo

Un puntero nulo es un puntero que apunta a una direccioacuten que no corresponde a ninguacuten objeto del programa Asignando la constante entera 0 a un puntero se le asigna el valor nulo Para mejor ligibilidad puede utilizarse la constante manifiesta NULL(definida en la libreriacutea de cabeceras estaacutendar ltstdiohgt) Ejemplo

int punt1 L1 Declara punt1punt1 = 0 L2 define punt1 como puntero nulopunt1 = NULL Equivalente a la anterior

Nota la cuestioacuten de la inicializacioacuten del puntero nulo es uno de los puntos de controversia para los teoacutericos del lenguaje En rigor la sentencia L2 anterior es erroacutenea ya que el tipo de punt1 es

puntero-a-int mientras que 0 es una constante numeacuterica (int por defecto) a pesar de lo cual es aceptada sin rechistar por el compilador [2] Lo sintaacutecticamente correcto seriacutea realizar un modelado

adecuado ( 499)

punt1 = static_castltintgt (0)

Es interesante observar que los punteros nulos de tipos distintos son distintos entre si Por ejemplo

un puntero nulo-a-int es de tipo distinto de un puntero nulo-a-char (aunque ambos coincidan en que su Rvalue es 0) por tanto no pueden ser comparados La comparacioacuten de dos punteros nulos del mismo tipo conduce a que son iguales Ejemplo

int pint = NULLchar pchar = NULLif (pint == pchar) cout ltlt Iguales Error

La uacuteltima sentencia produce un error de compilacioacuten Error Nonportable pointer comparison in

Es un error deferenciar ( 4911) un puntero nulo ademaacutes el intento de utilizar el valor obtenido puede dar lugar a un error de ejecucioacuten Por ejemplo refirieacutendonos al caso anterior

int x = pint Error

Recordar que cuando falla el operador de modelado dynamic_cast ( 499c) sobre un puntero el resultado es un puntero nulo Tambieacuten que algunas funciones de la Libreriacutea Estaacutendar devuelven punteros incluso el operador new devuelve un puntero y en algunas implementaciones antiguas el aviso de error en la operacioacuten de este operador se realizaba devolviendo un puntero nulo

sect3 Inicializar punteros

En general los punteros pueden ser inicializados como otra variable cualquiera desde luego solo tiene sentido que el valor sea la direccioacuten de inicio del almacenamiento de un objeto del tipo adecuado En otras palabras un valor que sea una direccioacuten de memoria Como existe un operador que precisamente proporciona la direccioacuten de una variable (operador de

referencia amp 4911) la forma usual de inicializar un puntero suele ser asignaacutendole el valor devuelto por dicho operador Ejemplo

int x = 100int ptr declaracioacuten de ptr como puntero-a-intptr = ampx se le asigna la direccioacuten de una variable

Tambieacuten es muy frecuente iniciarlos con el valor devuelto por el operador new ( 4920) que precisamente devuelve un puntero a objeto Ejemplo

class C definicioacuten de una clase CC cptr declara cptr como puntero-a-Ccptr = new C() new crea una instancia de la clase y devuelve un puntero al objeto cuyo valor que es asignado a cptr

Nota los enteros y los punteros no son intercambiables con excepcioacuten del cero El cero es un valor que nunca puede adoptar un puntero en condiciones normales por esta razoacuten se utiliza para significar no asignado u otra circunstancia especial Recordar que la aritmeacutetica de punteros permite comparar dos punteros para igualdad o desigualdad conNULL

sect4 Punteros como argumentos

En muchas ocasiones los punteros se utilizan como argumentos a funciones De hecho la mayoriacutea de las veces en que las matrices o las cadenas de caracteres pasan como argumentos lo que en realidad pasa es un puntero al primer elemento Por ejemplo

char str = La Tacita de Plataprintf(La ciudad es sn str)

En este caso la funcioacuten printf recibe como segundo argumento str que es un puntero a la posicioacuten de memoria donde comienza el almacenamiento de la cadena La Tacita de Plata0

En cualquier caso es necesario declarar esta circunstancia en el prototipo y en la definicioacuten de la funcioacuten para que el compilador conozca que el argumento pasado es una variable tipo puntero Ejemplo

include ltiostreamhgt void func(int ) prototipo argumento definido como puntero-a-int void main () ============= int x = 35 int ptr = ampx func (ptr) se pasa puntero-a-int como argumento cout ltlt El valor es ahora ltlt x ltlt endl void func (int p) el argumento se define como puntero-a-int p += 10 el argumento es tratado como puntero

Salida

El valor es ahora 45

  • 2 Punteros
    • sect1 Presentacioacuten
    • sect2 Sinopsis
    • sect3 Generalidades
    • 422 Aritmeacutetica de punteros
      • sect1 Sinopsis
      • sect2 Operaciones permitidas
      • sect4 Ejemplos
      • sect5 Ejemplos
      • sect6 Conversioacuten de punteros
        • 421 Puntero a objeto
          • sect1 Sinopsis
          • sect2 Puntero nulo
          • sect3 Inicializar punteros
          • sect4 Punteros como argumentos
Page 9: Punteros destinada a ingpara el bienestar de la población, o bien, que puedan ser perjudiciales para la vida vegetal o animal, o impidan el uso normal de las propiedades y lugares

Un puntero-a-tipoX (puntero a un objeto de tipoX) almacena la direccioacuten de un objeto del tipo sentildealado es decir sentildeala a un objeto tipoX Puesto que los punteros son objetos puede haber un puntero apuntando a un puntero (asiacute sucesivamente) Los objetos a los que se apunta suelen ser matrices estructuras uniones y clases

Nota aquiacute consideramos que un objeto es una regioacuten especiacutefica de memoria que puede contener un valor (o conjunto de valores) fijo o variable Esta acepcioacuten del vocablo es diferente (maacutes amplia) que cuando designa la instancia de una clase

Las explicaciones que siguen son vaacutelidas para punteros objetos de cualquier tipo (que no sean funciones) pero cuando se trata especiacuteficamente de punteros a clases e instancias de clases existen ciertas particularidades en la notacioacuten asiacute que les hemos dedicado un epiacutegrafe especiacutefico

con algunos comentarios ( 421f)

Nota tradicionalmente se considera que punteros y matrices estaacuten estrechamente relacionados [1] hasta el punto de ser estudiados simultaacuteneamente De hecho cualquier operacioacuten que puede efectuarse entre subiacutendices de matrices puede efectuarse con punteros en general de forma maacutes raacutepida (aunque algo maacutes difiacutecil de entender por el principiante)

Ademaacutes el operador de elemento de matriz [ ] se define en teacuterminos de ser un puntero ( 4916)

Los punteros a objeto tiene su propia aritmeacutetica (rudimentaria) de forma que pueden ser incrementados disminuidos y comparados cuando se exploran matrices u otras estructuras complejas

sect2 Puntero nulo

Un puntero nulo es un puntero que apunta a una direccioacuten que no corresponde a ninguacuten objeto del programa Asignando la constante entera 0 a un puntero se le asigna el valor nulo Para mejor ligibilidad puede utilizarse la constante manifiesta NULL(definida en la libreriacutea de cabeceras estaacutendar ltstdiohgt) Ejemplo

int punt1 L1 Declara punt1punt1 = 0 L2 define punt1 como puntero nulopunt1 = NULL Equivalente a la anterior

Nota la cuestioacuten de la inicializacioacuten del puntero nulo es uno de los puntos de controversia para los teoacutericos del lenguaje En rigor la sentencia L2 anterior es erroacutenea ya que el tipo de punt1 es

puntero-a-int mientras que 0 es una constante numeacuterica (int por defecto) a pesar de lo cual es aceptada sin rechistar por el compilador [2] Lo sintaacutecticamente correcto seriacutea realizar un modelado

adecuado ( 499)

punt1 = static_castltintgt (0)

Es interesante observar que los punteros nulos de tipos distintos son distintos entre si Por ejemplo

un puntero nulo-a-int es de tipo distinto de un puntero nulo-a-char (aunque ambos coincidan en que su Rvalue es 0) por tanto no pueden ser comparados La comparacioacuten de dos punteros nulos del mismo tipo conduce a que son iguales Ejemplo

int pint = NULLchar pchar = NULLif (pint == pchar) cout ltlt Iguales Error

La uacuteltima sentencia produce un error de compilacioacuten Error Nonportable pointer comparison in

Es un error deferenciar ( 4911) un puntero nulo ademaacutes el intento de utilizar el valor obtenido puede dar lugar a un error de ejecucioacuten Por ejemplo refirieacutendonos al caso anterior

int x = pint Error

Recordar que cuando falla el operador de modelado dynamic_cast ( 499c) sobre un puntero el resultado es un puntero nulo Tambieacuten que algunas funciones de la Libreriacutea Estaacutendar devuelven punteros incluso el operador new devuelve un puntero y en algunas implementaciones antiguas el aviso de error en la operacioacuten de este operador se realizaba devolviendo un puntero nulo

sect3 Inicializar punteros

En general los punteros pueden ser inicializados como otra variable cualquiera desde luego solo tiene sentido que el valor sea la direccioacuten de inicio del almacenamiento de un objeto del tipo adecuado En otras palabras un valor que sea una direccioacuten de memoria Como existe un operador que precisamente proporciona la direccioacuten de una variable (operador de

referencia amp 4911) la forma usual de inicializar un puntero suele ser asignaacutendole el valor devuelto por dicho operador Ejemplo

int x = 100int ptr declaracioacuten de ptr como puntero-a-intptr = ampx se le asigna la direccioacuten de una variable

Tambieacuten es muy frecuente iniciarlos con el valor devuelto por el operador new ( 4920) que precisamente devuelve un puntero a objeto Ejemplo

class C definicioacuten de una clase CC cptr declara cptr como puntero-a-Ccptr = new C() new crea una instancia de la clase y devuelve un puntero al objeto cuyo valor que es asignado a cptr

Nota los enteros y los punteros no son intercambiables con excepcioacuten del cero El cero es un valor que nunca puede adoptar un puntero en condiciones normales por esta razoacuten se utiliza para significar no asignado u otra circunstancia especial Recordar que la aritmeacutetica de punteros permite comparar dos punteros para igualdad o desigualdad conNULL

sect4 Punteros como argumentos

En muchas ocasiones los punteros se utilizan como argumentos a funciones De hecho la mayoriacutea de las veces en que las matrices o las cadenas de caracteres pasan como argumentos lo que en realidad pasa es un puntero al primer elemento Por ejemplo

char str = La Tacita de Plataprintf(La ciudad es sn str)

En este caso la funcioacuten printf recibe como segundo argumento str que es un puntero a la posicioacuten de memoria donde comienza el almacenamiento de la cadena La Tacita de Plata0

En cualquier caso es necesario declarar esta circunstancia en el prototipo y en la definicioacuten de la funcioacuten para que el compilador conozca que el argumento pasado es una variable tipo puntero Ejemplo

include ltiostreamhgt void func(int ) prototipo argumento definido como puntero-a-int void main () ============= int x = 35 int ptr = ampx func (ptr) se pasa puntero-a-int como argumento cout ltlt El valor es ahora ltlt x ltlt endl void func (int p) el argumento se define como puntero-a-int p += 10 el argumento es tratado como puntero

Salida

El valor es ahora 45

  • 2 Punteros
    • sect1 Presentacioacuten
    • sect2 Sinopsis
    • sect3 Generalidades
    • 422 Aritmeacutetica de punteros
      • sect1 Sinopsis
      • sect2 Operaciones permitidas
      • sect4 Ejemplos
      • sect5 Ejemplos
      • sect6 Conversioacuten de punteros
        • 421 Puntero a objeto
          • sect1 Sinopsis
          • sect2 Puntero nulo
          • sect3 Inicializar punteros
          • sect4 Punteros como argumentos
Page 10: Punteros destinada a ingpara el bienestar de la población, o bien, que puedan ser perjudiciales para la vida vegetal o animal, o impidan el uso normal de las propiedades y lugares

un puntero nulo-a-int es de tipo distinto de un puntero nulo-a-char (aunque ambos coincidan en que su Rvalue es 0) por tanto no pueden ser comparados La comparacioacuten de dos punteros nulos del mismo tipo conduce a que son iguales Ejemplo

int pint = NULLchar pchar = NULLif (pint == pchar) cout ltlt Iguales Error

La uacuteltima sentencia produce un error de compilacioacuten Error Nonportable pointer comparison in

Es un error deferenciar ( 4911) un puntero nulo ademaacutes el intento de utilizar el valor obtenido puede dar lugar a un error de ejecucioacuten Por ejemplo refirieacutendonos al caso anterior

int x = pint Error

Recordar que cuando falla el operador de modelado dynamic_cast ( 499c) sobre un puntero el resultado es un puntero nulo Tambieacuten que algunas funciones de la Libreriacutea Estaacutendar devuelven punteros incluso el operador new devuelve un puntero y en algunas implementaciones antiguas el aviso de error en la operacioacuten de este operador se realizaba devolviendo un puntero nulo

sect3 Inicializar punteros

En general los punteros pueden ser inicializados como otra variable cualquiera desde luego solo tiene sentido que el valor sea la direccioacuten de inicio del almacenamiento de un objeto del tipo adecuado En otras palabras un valor que sea una direccioacuten de memoria Como existe un operador que precisamente proporciona la direccioacuten de una variable (operador de

referencia amp 4911) la forma usual de inicializar un puntero suele ser asignaacutendole el valor devuelto por dicho operador Ejemplo

int x = 100int ptr declaracioacuten de ptr como puntero-a-intptr = ampx se le asigna la direccioacuten de una variable

Tambieacuten es muy frecuente iniciarlos con el valor devuelto por el operador new ( 4920) que precisamente devuelve un puntero a objeto Ejemplo

class C definicioacuten de una clase CC cptr declara cptr como puntero-a-Ccptr = new C() new crea una instancia de la clase y devuelve un puntero al objeto cuyo valor que es asignado a cptr

Nota los enteros y los punteros no son intercambiables con excepcioacuten del cero El cero es un valor que nunca puede adoptar un puntero en condiciones normales por esta razoacuten se utiliza para significar no asignado u otra circunstancia especial Recordar que la aritmeacutetica de punteros permite comparar dos punteros para igualdad o desigualdad conNULL

sect4 Punteros como argumentos

En muchas ocasiones los punteros se utilizan como argumentos a funciones De hecho la mayoriacutea de las veces en que las matrices o las cadenas de caracteres pasan como argumentos lo que en realidad pasa es un puntero al primer elemento Por ejemplo

char str = La Tacita de Plataprintf(La ciudad es sn str)

En este caso la funcioacuten printf recibe como segundo argumento str que es un puntero a la posicioacuten de memoria donde comienza el almacenamiento de la cadena La Tacita de Plata0

En cualquier caso es necesario declarar esta circunstancia en el prototipo y en la definicioacuten de la funcioacuten para que el compilador conozca que el argumento pasado es una variable tipo puntero Ejemplo

include ltiostreamhgt void func(int ) prototipo argumento definido como puntero-a-int void main () ============= int x = 35 int ptr = ampx func (ptr) se pasa puntero-a-int como argumento cout ltlt El valor es ahora ltlt x ltlt endl void func (int p) el argumento se define como puntero-a-int p += 10 el argumento es tratado como puntero

Salida

El valor es ahora 45

  • 2 Punteros
    • sect1 Presentacioacuten
    • sect2 Sinopsis
    • sect3 Generalidades
    • 422 Aritmeacutetica de punteros
      • sect1 Sinopsis
      • sect2 Operaciones permitidas
      • sect4 Ejemplos
      • sect5 Ejemplos
      • sect6 Conversioacuten de punteros
        • 421 Puntero a objeto
          • sect1 Sinopsis
          • sect2 Puntero nulo
          • sect3 Inicializar punteros
          • sect4 Punteros como argumentos
Page 11: Punteros destinada a ingpara el bienestar de la población, o bien, que puedan ser perjudiciales para la vida vegetal o animal, o impidan el uso normal de las propiedades y lugares

sect4 Punteros como argumentos

En muchas ocasiones los punteros se utilizan como argumentos a funciones De hecho la mayoriacutea de las veces en que las matrices o las cadenas de caracteres pasan como argumentos lo que en realidad pasa es un puntero al primer elemento Por ejemplo

char str = La Tacita de Plataprintf(La ciudad es sn str)

En este caso la funcioacuten printf recibe como segundo argumento str que es un puntero a la posicioacuten de memoria donde comienza el almacenamiento de la cadena La Tacita de Plata0

En cualquier caso es necesario declarar esta circunstancia en el prototipo y en la definicioacuten de la funcioacuten para que el compilador conozca que el argumento pasado es una variable tipo puntero Ejemplo

include ltiostreamhgt void func(int ) prototipo argumento definido como puntero-a-int void main () ============= int x = 35 int ptr = ampx func (ptr) se pasa puntero-a-int como argumento cout ltlt El valor es ahora ltlt x ltlt endl void func (int p) el argumento se define como puntero-a-int p += 10 el argumento es tratado como puntero

Salida

El valor es ahora 45

  • 2 Punteros
    • sect1 Presentacioacuten
    • sect2 Sinopsis
    • sect3 Generalidades
    • 422 Aritmeacutetica de punteros
      • sect1 Sinopsis
      • sect2 Operaciones permitidas
      • sect4 Ejemplos
      • sect5 Ejemplos
      • sect6 Conversioacuten de punteros
        • 421 Puntero a objeto
          • sect1 Sinopsis
          • sect2 Puntero nulo
          • sect3 Inicializar punteros
          • sect4 Punteros como argumentos