Documentos de Académico
Documentos de Profesional
Documentos de Cultura
- Paso de parámetros
Se realiza un paso de parámetros por valor cuando se envía una copia de los
valores de los parámetros actuales.
En este caso, la función invocada no podrá modificar los valores de las variables
utilizadas como parámetros actuales, sino que trabajará con las copias que se le
envían. Estas copias son recibidas en los parámetros formales, los cuales se
comportan como variables locales pertenecientes a la función invocada.
Al igual que las variables locales, una vez que termina la ejecución de la función
invocada, las variables pertenecientes a los parámetros formales se destruyen; y
por lo tanto, se pierden los valores que envió el módulo invocador.
#include <iostream.h>
#define NL cout << "\n" void precio(double); void main(void) { double
costo; cout << "COSTO : $ "; cin>> costo;
precio(costo); // SE INVOCA A precio() Y SE LE ENVIA UNA
// COPIA DEL VALOR DE costo
NL;
cout << costo; // EL VALOR DE costo SE CONSERVA DESPUES // DE LA
INVOCACION A precio() } void precio(double recibido) {
recibido="recibido" * 1.5; // SE MODIFICA EL VALOR DE LA // COPIA
GURDADA EN recibido NL; cout << recibido; }
A diferencia del paso por valor, el paso por referencia permite que la función
invocada modifique el valor original de las variables usadas como argumentos.
#include <iostream.h>
#include <conio.h>
void main(void)
{
float precio;
clrscr();
gotoxy(20,12);
cout << "¿ CUAL ES EL PRECIO ?. N$ " ; cin>> precio;
oferta(precio);
gotoxy(20,14);
cout << "¿ DIJO USTED N$ " << precio << " ?"; gotoxy(20,16); cout
<< " ESO ES CON EL 20 % DE DESCUENTO"; gotoxy(1,25); } void
oferta(float & bajo) { bajo *="0.8" ; gotoxy(20,24); cout << "PRECIO
REBAJADO: N$ " << bajo; }
Según lo anterior, podemos decir que es preferible utilizar una variable existente
en lugar crear una nueva, y eliminar el paso de parámetros por valor.
El paso de parámetros por valor puede sustituirse por un paso de parámetros por
referencia donde se utilice el modificador const, como se muestra en el listado 4.5.
#include <iostream.h>
#include <conio.h>
void main(void)
{
float precio;
clrscr();
gotoxy(20,12);
cout << "¿ CUAL ES EL PRECIO ?. N$ " ; cin>> precio;
seudoferta(precio);
gotoxy(20,14);
cout << "¿ DIJO USTED N$ " << precio << " ?"; gotoxy(20,16); cout
<< " ESO DIJE.... NO HAY DESCUENTO"; gotoxy(1,25); } void
seudoferta(const float & bajo) { float rebajado; rebajado="bajo" * 0.8
; gotoxy(20,24); cout << "PRECIO REBAJADO: N$ " << rebajado; }
El valor del precio cambia para cada artículo, pero el valor del descuento puede
considerarse como un pocentaje fijo del precio para la mayoría de los artículos
(por ejemplo en época de ofertas).
//////////////////////////////////////////////////////
// ARGPRED.CPP : EJEMPLO DEL MANEJO DE ARGUMENTOS //
// CON VALORES PREDETERMINADOS //
//////////////////////////////////////////////////////
#include <iostream.h>
#include <conio.h>
Se dice que una función es recursiva cuando puede invocarse a sí misma. En cada
invocación se crean las variables locales, por lo que es indispensable incluir una
condición de salida, ya que de no hacerlo se agotará la memoria disponible en la
pila.
#include <iostream.h>
#include <conio.h>
#define NL cout << "\n" #define PULSE cout << "PULSE CUALQUIER TECLA
PARA CONTINUAR." void recursiva(void); void main(void) { clrscr();
recursiva(); NL; PULSE; getch(); NL; } void recursiva(void) { int x;
cout << "TECLEE UN NUMERO ENTERO... ( 0="SALIR)" "; cin>> x ;
if(x)
recursiva();
}
En el listado 4.7 podemos observar que, para que la función recursiva se invoque a
si misma, es necesario que el valor almacenado en x sea diferente de 0.
#include <iostream.h>
#include <conio.h>
void main()
{
unsigned short int num;
long result;
clrscr();
do {
gotoxy(20,11);
cout << "El FACTORIAL del número: " ; clreol(); cin>> num
;
} while((num <0) || (num> 19 ));
result = factorial(num);
gotoxy(20,13);
cout << " es : " << result; } long factorial(unsigned short int n)
{ if(n="=0)" return 1; else return n*(factorial(n-1)) ; }
Numero de
Valor de n Resultado
invocación
1 4 4*(factorial(3))
2 3 3*(factorial(2))
3 2 2*(factorial(1))
4 1 1*(factorial(0))
5 0 1
1 * (factorial(0)) = 1 * 1 = 1
2 * (factorial(1)) = 2 * 1 = 2
3 * (factorial(2)) = 3 * 2 = 6
4 * (factorial(3)) = 4 * 6 = 24
Finalmente, la invocación 1 retorna el valor 24 a la función invocadora main(), la
cual asigna a la variable result el valor recibido ( 24 ).
5.- Arreglos.
Los elementos de los arreglos son variables de algún tipo dado, que al compartir el
mismo nombre pueden ser tratadas como una sola entidad.
donde:
DECLARACION RESULTADO
Al declarar un arreglo dentro de una función, los valores almacenados en cada uno
de los elementos son desconocidos (se dice que el arreglo "tiene basura"), lo cual
causa que el programa correspondiente arroje resultados inesperados. Para evitar
los valores desconocidos, se recomienda asignar valores iniciales a cada uno de los
elementos de los arreglos, como se muestra a continuación:
Como puede observarse en la figura 5.1, el primer subíndice tiene valor cero y el
último tiene valor cuatro.
Una vez declarado el arreglo, se pueden asignar valores a cada uno de sus
elementos, como se muestra enseguida:
vector[0] = 100 ;
vector[1] = 101 ;
vector[2] = 102 ;
vector[3] = 103 ;
vector[4] = 104 ;
En este caso particular, pudimos haber asignado los valores por medio de un
estatuto for de la siguiente forma:
for( int x = 0 ; x < 5 ; x++) vector[x] = x + 100 ;
Todo lo escrito en este ejemplo es válido para arreglos con elementos de cualquier
tipo.
Por ejemplo, si queremos desplegar en pantalla los caracteres del código ASCII lo
haríamos por medio del siguiente grupo de instrucciones:
#include <iostream.h>
#include <conio.h>
void main(void)
{
int matriz[3][4];
clrscr();
for(int x=0 ; x < 3 x++)
{
for(int y=0 y< 4 ; y++)
{
matriz[x][y]=x+y+1 ;
gotoxy(y+1,x+1);
cout matriz[x][y];
}
}
}
1234
2345
3456
int digitos[10];
digitos[0] = 0 ;
digitos[1] = 1 ;
digitos[2] = 2 ;
digitos[3] = 3 ;
digitos[4] = 4 ;
digitos[5] = 5 ;
digitos[6] = 6 ;
digitos[7] = 7 ;
digitos[8] = 8 ;
digitos[9] = 9 ;
Como puede verse, la primera forma es mucho más compacta, aunque , como en
muchas de las instrucciones de C++, la brevedad del código sacrifica la claridad.
char cadena[8];
cadena[0] = 'A' ;
cadena[1] = 'R' ;
cadena[2] = 'R' ;
cadena[3] = 'E' ;
cadena[4] = 'G' ;
cadena[5] = 'L' ;
cadena[6] = 'O' ;
cadena[7] = '\0';
Al contener el carácter nulo, el arreglo cadena será reconocido por las funciones y
objetos diseñados para manipular cadenas de caracteres. Para manejar un arreglo
de cadenas de caracteres se debe declarar como un arreglo bidimensional de
elementos de tipo char, como puede observarse en el listado 5.2.
#include <iostream.h>
#include <conio.h>
void main()
{
unsigned short int calif[10];
char nombre[10][21]; // Se declara un arreglo bidimensional
// para 10 nombres de 20 caracteres por
// nombre mas un caracter para el nulo.
clrscr();
for( int x=0 ; x < 10 ; x++)
{
gotoxy(10,x+1);
cout << "NOMBRE [" << x << "] = " ;
cin >> nombre[x];
gotoxy(45,x+1);
cout << "CALIFICACION [" << x << "] = " ;
cin >> calif[x];
}
}
Por Ejemplo:
es equivalente a:
char nombres[3][5];
nombres[0] = "HUGO" ;
nombres[1] = "PACO" ;
nombres[2] = "LUIS" ;
o así:
char nombres[3][5];
nombres[0][0] = 'H' ;
nombres[0][1] = 'U' ;
nombres[0][2] = 'G' ;
nombres[0][3] = 'O' ;
nombres[0][4] = '\0' ;
nombres[1][0] = 'P' ;
nombres[1][1] = 'A' ;
nombres[1][2] = 'C' ;
nombres[1][3] = 'O' ;
nombres[1][4] = '\0' ;
nombres[2][0] = 'L' ;
nombres[2][1] = 'U' ;
nombres[2][2] = 'I' ;
nombres[2][3] = 'S' ;
nombres[2][4] = '\0' ;
En los listados 5.3 y 5.4 se muestran las dos primeras formas, observándose que se
obtiene el mismo resultado.
#include <iostream.h>
#include <conio.h>
void main()
{
char nombres[][5] = { "HUGO","PACO","LUIS" };
int calif[] = { 100, 90, 100 };
clrscr();
for( int x=0 ; x < 3;x++)
{
gotoxy(35,x+10);
cout nombres[x];
gotoxy(40,x+10);
cout << calif[x];
}
}
#include <iostream.h>
#include <conio.h>
void main()
{
char nombres[][5] = { 'H','U','G','O','\0',
'P','A','C','O','\0',
'L','U','I','S','\0' };
int calif[] = { 100, 90, 100 };
clrscr();
for( int x=0 ; x< 3;x++)
{
gotoxy(35,x+10);
cout nombres[x];
gotoxy(40,x+10);
cout << calif[x];
}
}
La ventaja que tiene la forma mostrada en 5.3 y 5.4 es que, al no especificar una de
las dimensiones, la cantidad de cadenas a manejar puede variarse con sólo
agregarlas a la lista o eliminarlas de ella.
5.5.- Funciones para el manejo de cadenas
Para leer una cadena de caracteres desde el teclado existe la función gets(), y para
desplegar una cadena en pantalla se usa la función puts(). Los prototipos de ambas
funciones se encuentran declarados en el archivo STDIO.H.
Por ejemplo, el listado 5.5 muestra un programa que sirve para leer y desplegar
cadenas de caracteres utilizando las funciones gets() y puts().
void main()
{
char nombre[31]; // Declara un arreglo de 31 caracteres
char saludo1[] = "?? HOLA,"; //Constante de caracteres
char saludo2[] = " !!";
clrscr();
gotoxy(20,10);
puts("¿ Cuál es tu nombre ? "); //Despliega cadena de car.
gotoxy(45,10);
gets(nombre); // Lee cadena de caracteres
strupr(nombre); // Convierte a mayúsculas
gotoxy(20,12);
puts(saludo1);
gotoxy(30,12);
puts(nombre);
gotoxy(30+strlen(nombre),12); // Longitud de la cadena
puts(saludo2);
}
Además de las funciones gets() y puts(), existe otro grupo de funciones para el
manejo de cadenas de caracteres, como strlen() y strupr() utilizadas en el
programa del listado 5.5. Los prototipos de estas funciones se encuentran
declarados en el archivo STRING.H En la tabla 5.1 se describen brevemente
algunas de las funciones para el manejo de cadenas de caracteres en el C++ de
Borland, cuyos prototipos se encuentran declarados en el archivo STRING.H .
FUNCION DESCRIPCION
Copia una cadena de caracteres en otra.Se detiene cuando encuentra el
stpcpy
terminador nulo.
strcat Añade una cadena de caracteres a otra.
strchr Busca, en una cadena, un caracter dado.
strcmp Compara dos cadenas.
Macro que compara dos cadenas sin distinguir entre mayúsculas y
strcmpi
minúsculas.
strcpy Copia una cadena.
Busca segmentos que no contienen un subconjunto de un conjunto
strcspn
especificado de caracteres.
strdup Copia una cadena a una nueva localidad.
_strerror Genera un mensaje de error definido por el programador.
strerror Retorna el apuntador al mensaje asociado con el valor del error.
stricmp Compara dos cadenas sin diferenciar entre mayúsculas y minúsculas
strlen Determina la longitud de una cadena.
strlwr Convierte las mayúsculas de una cadena en minúsculas.
strncat Añade el contenido de una cadena al final de otra.
strncmp Compara parte de una cadena con parte de otra.
Compara parte de una cadena con parte de otra, sin distinguir entre
strncmpi
mayúsculas y minúsculas.
strncpy Copia un un número de bytes dados, desde una cadena hacia otra.
Compara parte de una cadena con parte de otra, sin distinguir entre
strnicmp
mayúsculas y minúsculas.
strnset Hace que un grupo de elementos de una cadena tengan un valor dado.
Busca la primera aparición, en una cadena, de cualquier caracter de un
strpbrk
conjunto dado.
strrchr Busca la última aparición de un caracter en una cadena.
strrev Invierte el orden de los caracteres de una cadena.
strset Hace que los elementos de una cadena tengan un valor dado.
Busca en una cadena el primer segmento que es un subconjunto de un
strspn
conjunto de caracteres dado.
strstr Busca en una cadena la aparición de una subcadena dada.
_strtime Convierte la hora actual a una cadena.
strtod Convierte una cadena a un valor double ó long double.
strtol Convierte una cadena a un valor long.
strtoul Convierte una cadena a un valor unsigned long.
strupr Convierte las minúsculas de una cadena a mayúsculas.
void main()
{
char nombre[31];
clrscr();
gotoxy(10,1);
puts("¿ Cuál es tu nombre ? ");
gotoxy(35,1);
gets(nombre);
clrscr();
gotoxy (10,1);
puts("ELEMENTO CARACTER DIRECCION");
for( int x=0 ; (x <strlen(nombre)+5) && (x<23); x++)
{
gotoxy(10,x+2);
printf("nombre[%2d] %c= %4d %9u",
x,nombre[x],nombre[x],&nombre[x]);
}
}
Los apuntadores son una de las herramientas más poderosas con que cuenta el
Lenguaje C++ . Desafortunadamente, muchos programadores han creado el mito
de que el estudio de los apuntadores es muy complicado, lo cual ha desarrollado
una fobia entre quienes se inician en el estudio del lenguaje.
En las figuras 6.1, 6.2 y 6.3 se muestra el manejo de la pila y el montículo en los seis
modelos de memoria disponibles en el C++ de Borland.
Para cada programa, dependiendo del espacio requerido para el código y para los
datos, se puede utilizar un modelo de memoria específico. El modelo
predeterminado en el C++ de Borland es el modelo SMALL.
Con el modelo de memoria TINY se utiliza un solo segmento (64 KB) para el
código, los datos y la pila. La utilización del modelo TINY es aconsejable
únicamente cuando se quiere crear un archivo .COM
Cuando se usa el modelo MEDIUM, los datos están limitados a un segmento pero
el código puede utilizar varios (hasta 16 MB). El uso de este modelo se recomienda
cuando se tiene un programa grande con pocos datos.
En los modelos LARGE y HUGE, el código y los datos pueden ocupar varios
segmentos (hasta 16 MB). La diferencia entre estos modelos es que el HUGE puede
manejar variables automáticas que, en total, excedan los 64 KB.
De manera similar, en el caso del modelo HUGE no debe haber datos automáticos
de más de 64 KB en cada módulo.
tipo * identificador ;
#include <iostream.h>
#include <conio.h>
void main()
{
int automatica ; // Se declara la variable automatica.
int *apunt ; // Se declara el apuntador apunt, que apun-
// tará a objetos de tipo int.
cout << "VALOR=" << automatica << " \n"; // 100 *apunt="200" ; //
Se asigna el valor 200 al objeto apunta- // do por apunt. cout <<
"VALOR=" << automatica << " \n"; // 200 getch(); }
Las instrucciones del listado 6.1 se traducen en la siguiente secuencia, donde los
apuntadores se representan con una flecha (para simular que "apuntan hacia" ó
"señalan" un objeto) y los objetos apuntados se representan por un cuadro (para
simular un recipiente).
Un apuntador es una variable que solo puede contener un valor a la vez, por lo que
solo puede apuntar a un objeto al mismo tiempo.
Por otro lado, una variable cualquiera puede ser apuntada por varios apuntadores,
ya que su dirección de memoria puede ser almacenada en distintas variables a la
vez.
void *multiusos ;
#include <iostream.h>
#include <conio.h>
#define NL cout << "\n" void main() { int varent="0" ; float
varflot="0.0" ; void *apmulti="&varent;" // apmulti APUNTA A varent
*(int *)apmulti="2" ; // ASIGNA 2 AL OBJETO NL; // APUNTADO POR
apmulti cout << varent ; apmulti="&varflot" ; // apmulti APUNTA A
varflot *(float *)apmulti="1.1" ; // ASIGNA 1.1 AL OBJETO APUNTADO //
POR apvoid NL; cout << varflot ; NL; getch(); }
*(int *)apmulti = 2 ;
en donde:
El hecho de que sean near significa que solo disponen de dos bytes para almacenar
una dirección de memoria. Al disponer de dos bytes, el número entero sin signo
más grande que pueden almacenar es 65535, el cual corresponde a la dirección
más alta de un segmento de memoria.
#include <iostream.h>
#include <conio.h>
void main()
{
int far *aplej ; // Declara un apuntador far a enteros
char c ;
int ren, col ;
clrscr();
cout << "Teclee caracteres ( < Enter >="Salida" ) : " ;
aplej="(int" far *) 0xB8000000 ; while(( c="getche())" !="\r" ) for(
ren="0" ; ren < 25 ; ren ++ ) for( col="0" ; col < 80 ; col++ )
*(aplej + ren*80 + col )="c" | 0x0700 ; clrscr(); }
En:
En la linea:
la parte
la parte:
mientras que:
c | 0x0700
es una operación OR a nivel de bits para asegurar que el caracter c tendrá los
atributos de caracter normal.
Tanto en C como en C++ existen funciones tales como malloc() y free() para la
asignación y liberación de memoria del montículo.
#include <iostream.h>
void main()
{
int *apent; // Declara un apuntador a entero
En el programa del listado 6.4, se supone que la reservación será exitosa porque
existe espacio suficiente en el montículo.
Pero ¿quién asegura que el espacio requerido por new está disponible?. Para
controlar esta situación y evitar un mensaje de error por parte del sistema en
tiempo de ejecución, en 6.5 se propone una nueva versión del programa.
#include <iostream.h>
#include <stdlib.h> // Para exit().
void main()
{
int *apent; // Declara un apuntador a entero
Los operadores new y delete pertenecen al Lenguaje C++ , de tal manera que no se
requiere incluir ningún archivo de cabecera para utilizarlos.
double* dap ;
dap = new double[25];
ó su forma equivalente:
double* dap = new double[25];
#include <iostream.h>
#include <conio.h>
#include <stdlib.h>
void main()
{
unsigned int n;
clrscr();
gotoxy(20,1);
cout << "NUMERO DE ELEMENTOS DEL ARREGLO: "; cin>> n;
float* apf;
if((apf=new float[n])==NULL)
{
cout << "NO HAY ESPACIO SUFICIENTE EN EL MONTICULO\N";
exit(1); } for(int x="0" ; x < n ; x++) { gotoxy(20,x+3);
*(apf+x)="x+100.25;" cout << *(apf+x) << "\n"; } delete apf; getch();
}
Por ejemplo :
#include <iostream.h>
void main()
{
int calif[] = { 100,90,95,80,90};
#include <iostream.h>
void main()
{
int calif[] = { 100,90,95,80,90};
Como puede observarse, la única diferencia entre los listados 6.7 y 6.8 es que el
primero utiliza calif[i] y el segundo *(calif+i).
Debido a que la ejecución de los programas de ambos listados producen resultados
iguales, se deduce que:
calif[i] == *(calif+i)
Para entender esto que a simple vista no es obvio, revisaremos algunos conceptos:
1.- El nombre del arreglo corresponde al de un apuntador que apunta al primer
elemento del arreglo, por lo que:
Visto gráficamente :
2.- Para hacer referencia a un elemento específico del arreglo, se toma como base
la dirección del primer elemento y, con el subíndice del elemento específico, se
calcula su dirección. Por ejemplo, para referirse al segundo elemento del arreglo
puede procederse así :
*(calif+2)
Lo que significa: "El objeto que se encuentra dos posiciones después del objeto
apuntado por calif". En este caso, una posición es el espacio requerido por cada
uno de los elementos, de tal manera que, si calif apunta a la dirección 65494,
entonces calif+2 es la expresión que calcula la dirección 65498. La figura 6.7
muestra los elementos del arreglo calif[] con sus nombres en notación de arreglos y
en notación de apuntadores.
Figura 6.7.- El arreglo calif[] en la pila. Notación en arreglos y en apuntadores.
&sueldo[5] es igual a :
#include <iostream.h>
#include <conio.h>
#include <stdio.h>
void main()
{
char *nombre = "PACO" ;
clrscr();
gotoxy(30,12);
cout<< "!! HOLA, " ; puts(nombre); gotoxy(43,12); cout << " !!";
getch(); }
#include <iostream.h>
#include <conio.h>
#include <string.h>
void main()
{
char *nombres[ ] = { "HUGO", "PACO", "LUIS" } ;
char invitado[11];
int bandera;
clrscr();
gotoxy(30,10);
cout << "CUAL ES SU NOMBRE ? " ; gotoxy(50,10); cin>> invitado ;
gotoxy(30,12);
for( int x = 0 ; x <3 ; x++ ) if(strcmp(invitado, nombres[x])="="
0) bandera="0;" if(bandera="=" 0) cout << "!! PASE, ESTIMADO " <<
invitado << " !!"; else cout << "!! FUERA DE AQUI, " << invitado << "
!!"; getch(); }
Un arreglo puede pasarse como parámetro a una función. Si tuviera que pasarse
por valor un arreglo muy grande, sería un desperdicio de memoria. En el Lenguaje
C++ el paso de arreglos se hace por referencia, ya que el nombre del arreglo
corresponde a un apuntador al primer elemento del arreglo.
El listado 6.11 contiene un programa que maneja una función llamada nputs() , la
cual recibe como parámetro un arreglo de caracteres.
#include <iostream.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
void nputs(char *);
void main()
{
char cadena[81];
clrscr();
gotoxy(10,10);
cout << "ESCRIBA UNA CADENA: "; gets(cadena); gotoxy(10,12);
nputs(cadena); getch(); } void nputs(char cad[ ]) { int x="0;"
while(cad[x]) { cout << cad[x] ; x++; } }
#include <iostream.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
void main()
{
char cadena[81];
clrscr();
gotoxy(10,10);
cout << "ESCRIBA UNA CADENA: "; gets(cadena); gotoxy(10,12);
nputs(cadena); getch(); } void nputs(char *cad) { while(*cad) cout <<
*cad++ ; }
Toda función tiene asociada una dirección de inicio de código, la cual puede
pasarse como parámetro en la invocación a otra función, como se muestra en el
listado 6.13.
#include <iostream.h>
#include <string.h>
#include <conio.h>
void main()
{
char cadx[80], cady[80];
clrscr();
gotoxy(10,5);
cout << "ESCRIBA UNA CADENA : " ; cin>> cadx;
gotoxy(10,7);
cout << "ESCRIBA OTRA CADENA : " ; cin>> cady;
gotoxy(10,9);
compara(cadx, cady, cmpcad);
gotoxy(1,24);
}
void compara(char *cad1, char *cad2,
int (*cmpcad)(char*, char*))
{
if(!(*cmpcad)(cad1,cad2))
cout << "LAS CADENAS SON IGUALES"; else cout << "LAS CADENAS
SON DISTINTAS"; } int cmpcad(char *x, char *y) { return(strcmp(x,y));
}
int(*cmpcad)(char*, char*)
Esto puede extrapolarse para dos o más variables, como se observa en el listado
6.14.
#include <iostream.h>
#include <conio.h>
void main()
{
int x, *a, **b, ***c ; // 1
clrscr();
a = &x ; // 2
*a = 100 ; // 3
b = &a ; // 4
**b += *a ; // 5
c = &b ; // 6
***c += **b + *a ; // 7
cout << " *a=" << *a << " \n" ; cout << " **b=" << **b << " \n" ;
cout << "***c=" << ***c << " \n" ; getch(); }
Se declaran:
x como una variable de tipo entero. a como un apuntador a objetos de tipo entero. b como
un apuntador a un apuntador, el cual a su vez apuntará a objetos de tipo entero. Se dice que
b es "el apuntador del apuntador". c como un apuntador a un apuntador que apunta a otro
apuntador, el cual a su vez apunta a objetos de tipo entero. Se dice que c es "el apuntador
del apuntador del apuntador".
a = &x ; // 2
b = &a ; // 4
**b += *a ; // 5
Al objeto apuntado por el apuntador apuntado por b se le suma el valor del objeto
apuntado por a. La pila luciría así:
c = &b ; // 6
_ Gif animado
_ Applet animado
#include <iostream.h>
en la pantalla aparecerá:
En este caso:
*cadena == cadena[]
**cadena == *cadena[]
***cadena == **cadena[]
El uso de corchetes vacíos sólo es válido cuando se realiza una asignación ó cuando
se escriben los argumentos en la línea de cabecera de la definición de una función.
Sólo el par de corchetes de la extrema derecha puede escribirse vacío, los demás
deberán contener un valor constante.
donde: