Pepa 121020120336 Phpapp02
Pepa 121020120336 Phpapp02
Pepa 121020120336 Phpapp02
TOLEDO MARTNEZ
CONTENIDO DE LA LECCIN 20
APUNTADORES Y CADENAS
1. Introduccin
2. Declaracin e iniciacin de variables de apuntador
3. Operadores de los apuntadores
3.1. Ejemplo 20.1
9. Arreglos de apuntadores
10. Caso de estudio: Simulacin de barajado y reparticin de naipes
10.1. Ejemplo 20.13
3
37
4
6
6
7
10
11
15
15
18
21
22
24
25
28
29
29
33
33
34
36
40
47
47
53
54
54
54
55
56
56
56
56
56
57
57
57
57
58
58
59
64
65
66
67
20-1
67
67
67
68
70
70
73
75
79
84
85
88
20-2
LECCIN 20
APUNTADORES Y CADENAS
INTRODUCCIN
En esta leccin se estudiar una de las caractersticas ms poderosas del lenguaje de
programacin C++: el apuntador. Los apuntadores son una de las capacidades de C++ ms
difciles de dominar. En otra leccin vimos que las referencias pueden servir para hacer llamadas
por referencia. Los apuntadores permiten a los programas simular la llamada por referencia y
crear y manipular estructuras dinmicas de datos, es decir, estructuras de datos que pueden crecer
y encogerse, como las listas vinculadas, colas, pilas y rboles. Esta leccin explica los conceptos
bsicos acerca de los apuntadores. Tambin refuerza la relacin ntima entre los arreglos, los
apuntadores y las cadenas e incluye un amplio conjunto de ejemplos de procesamiento de
cadenas.
En otro semestre se estudiarn el empleo de los apuntadores con estructuras. La
programacin orientada a objetos se efecta con apuntadores y referencias. En ese semestre se
presentan tcnicas de administracin dinmica de memoria y ejemplos de creacin y uso de
estructuras dinmicas de datos.
El enfoque de los arreglos y cadenas como apuntadores se deriva de C. En la especialidad
de computacin se estudiarn los arreglos y las cadenas como objetos en toda forma.
Los objetivos de esta leccin son:
20-3
contador
7
contadorPtr
contador
7
Los apuntadores, como cualquier otra variable, se deben declarar antes de utilizarlos. La
declaracin:
int *contadorPtr, contador;
declara la variable contadorPtr como de tipo int * (es decir, como un apuntador a un valor
entero) y se lee contadorPtr es un apuntador a int o contadorPtr apunta a un objeto de clase
entero. Adems, la variable contador se declara como entero, no como apuntador a un entero. En
esta declaracin, el * solamente se aplica a contadorPtr. Cada variable que se declara como
apuntador debe ir precedida por un asterisco (*) Por ejemplo, la declaracin:
float *xPtr, *yPtr;
indica que tanto xPtr como yPtr son apuntadores a valores float. El uso de * en una declaracin
de esta manera indica que la variable que se est declarando es un apuntador. Los apuntadores
pueden declararse para que apunten a objetos de cualquier clase de datos.
Los apuntadores se deben inicializar, ya sea al declararlos o mediante una instruccin de
asignacin. Un apuntador puede inicializarse a 0, a NULL o a una direccin. Un apuntador con
el valor 0 o NULL no apunta a nada. NULL es una constante simblica definida en el archivo de
encabezado <iostream.h> (y en varios archivos de encabezado de la biblioteca estndar) La
iniciacin a NULL de un apuntador es equivalente a inicializarlo a 0, pero en C++ se prefiere 0.
Cuando se asigna 0, se convierte en un apuntador del tipo adecuado. El valor 0 es el nico valor
entero que puede asignarse directamente a una variable de apuntador sin convertir primero
mediante cast el entero a un tipo de apuntador. En la siguiente seccin se estudia la asignacin de
la direccin de una variable a un apuntador.
OPERADORES DE LOS APUNTADORES
El &, u operador de direccin, es un aperador unario que devuelve la direccin de su
operando. Por ejemplo, suponiendo las declaraciones:
int y = 5;
int *yPtr;
la instruccin
yPtr = &y;
20-4
Figura 20.2. Representacin grfica de un apuntador que apunta a una variable entera en la memoria
600000
600000
que asignar 9 a y en la figura 20.3. El apuntador desreferenciado tambin podra usarse para
recibir un valor de entrada como en el caso de:
cin >> *yPtr;
20-5
Ejemplo 20.1
El programa siguiente: APUNTADOR1.CPP, muestra los operadores de los apuntadores. En este ejemplo,
las localidades de memoria se envan a la salida como enteros hexadecimales.
/* El siguiente programa: APUNTADOR1.CPP, muestra el empleo de los operadores & y *
*/
#include <iostream.h>
void main(void)
{
int a;
int *aPtr;
//a es un entero
//aPtr es un apuntador a un entero
a = 7;
aPtr = &a;
cout
cout
cout
}//Fin de main()
Observe que la direccin de a y el valor de aPtr son idnticos en la salida, lo que confirma que la direccin
de a efectivamente est asignada a la variable de apuntador aPtr. Los operadores & y * son inversos entre
ellos cuando se aplican ambos consecutivamente a aPtr en cualquier orden, se imprime el mismo
resultado.
20-6
int cuboValor(int);
//Prototipo
void main(void)
{
int numero = 5;
cout << "El valor original del nmero es: " << numero;
numero = cuboValor(numero);
cout << "\nEl nuevo valor del nmero es: " << numero << endl;
}//Fin de main()
int cuboValor(int n)
{
return n * n * n;
}//Fin de cuboValor()
El programa CUBO2.CPP pasa la variable numero mediante una llamada por referencia (se pasa la
direccin de numero) a la funcin cuboReferencia() Esta toma nPtr (que es un apuntador a int) como
argumento. La funcin desreferencia el apuntador y eleva al cubo el valor al que apunta nPtr. Esto cambia
el valor de numero en main()
20-7
/* El siguiente programa: CUBO2.CPP, eleva al cubo una variable mediante una llamada
por referencia, con un argumento de apuntador.
*/
#include <iostream.h>
//Prototipo
void main(void)
{
int numero = 5;
cout << "El valor original del nmero es: " << numero;
cuboReferencia(&numero);
cout << "\nEl nuevo valor del nmero es: " << numero << endl;
}//Fin de main()
void cuboReferencia(int *nPtr)
{
*nPtr = *nPtr * *nPtr * *nPtr;
}//Fin de cuboReferencia()
Una funcin que recibe como argumento una direccin debe definir un parmetro de apuntador para recibir
dicha direccin. Por ejemplo, el encabezado de la funcin cuboReferencia() es:
void cuboReferencia(int *nPtr);
El encabezado de la funcin especifica que cuboReferencia() contiene int * entre parntesis. Como sucede
con los dems tipos de variables, no es necesario incluir los nombres de los apuntadores en los prototipos
de funcin. El compilador ignorar los nombres incluidos con fines de documentacin.
En el encabezado de la funcin y en el prototipo de una funcin que espera como argumento un arreglo de
un solo ndice, puede emplearse la notacin de apuntadores en la lista de parmetros de cuboReferencia()
El compilador no hace ninguna distincin entre una funcin que recibe un apuntador y otra que recibe un
arreglo de un solo ndice. Por supuesto, esto significa que la funcin debe saber cundo est recibiendo un
arreglo y cundo se trata simplemente de una variable sencilla sobre la que debe efectuar una llamada por
referencia. Cuando el compilador encuentra un parmetro de funcin para un arreglo de un solo ndice, de
la forma int b[], lo convierte a la notacin de apuntadores int * const b (que se pronuncia como b es un
apuntador constante a un entero); const se explica en la seccin siguiente (empleo del calificador const con
apuntadores) Ambas formas de declaracin de un parmetro de funcin como arreglo de un solo ndice son
intercambiables.
Las figuras 20.3 y 20.4 son anlisis grficos de los programas CUBO1.CPP y CUBO2.CPP.
Antes de que main() llame a cuboValor():
int main()
{
int numero = 5;
numero
5
int cuboValor(int n)
{
return n * n * n;
}//Fin de cuboValor()
n
indefinido
numero = cuboValor(numero);
}//Fin de main()
20-8
numero
5
int cuboValor(int n)
{
return n * n * n;
}//Fin de cuboValor()
n
5
numero = cuboValor(numero);
}//Fin de main()
Despus de que cuboValor() eleve al cubo el parmetro n:
int main()
{
int numero = 5;
numero
5
int cuboValor(int n)
{
125
return n * n * n;
}//Fin de cuboValor()
int cuboValor(int n)
{
return n * n * n;
}//Fin de cuboValor()
indefinido
numero = cuboValor(numero);
}//Fin de main()
Despus de que cuboValor() regresa a main():
int main()
numero
{
5
int numero = 5;
125
numero = cuboValor(numero);
}//Fin de main()
indefinido
numero
125
int cuboValor(int n)
{
return n * n * n;
}//Fin de cuboValor()
n
indefinido
numero = cuboValor(numero);
}//Fin de main()
Figura 20.3. Anlisis de una llamada por valor tpica.
Antes de la llamada por referencia a cuboReferencia():
int main()
{
int numero = 5;
numero
5
cuboReferencia(&numero);
}//Fin de main()
Despus de la llamada por referencia a cuboReferencia() y antes de elevar *nPtr al cubo:
int main()
{
int numero = 5;
numero
5
cuboReferencia(&numero);
}//Fin de main()
APUNTADORES Y CADENA LECCIN 20
20-9
numero
125
cuboReferencia(&numero);
}//Fin de main()
Figura 20.4. Anlisis de una llamada por referencia tpica con argumento de apuntador.
20-10
hacia datos no constante no incluye a const. Tal apuntador puede servir para recibir una cadena
en una funcin que se vale de aritmtica de apuntadores para procesar (y tal vez modificar) uno
por uno los caracteres de la cadena. La funcin convertirMayuscula() en el programa
MAYSCULA.CPP declara el parmetro sPtr (char *sPtr) como apuntador no constante hacia
datos no constantes. La funcin procesa la cadena cadena, carcter por carcter, mediante
aritmtica de apuntadores. Los caracteres entre la a y la z son convertidos a sus letras maysculas
a travs de la funcin toupper(), los dems se conservan iguales. La funcin toupper() toma
como argumento un carcter. Si dicho carcter es una letra minscula, se devuelve la letra
mayscula correspondiente; de otro modo, se devuelve el carcter original. La funcin toupper()
es parte de la biblioteca de manejo de caracteres ctype.h.
Ejemplo 20.3
El siguiente programa: MAYSCULA.CPP, ilustra el uso de un apuntador no constante a datos no
constantes.
/* El siguiente programa: MAYUSCULA.CPP, convierte letras minsculas a maysculas, por
medio de un apuntador no constante hacia datos no constantes.
*/
#include <iostream.h>
#include <ctype.h>
//Convierte a maysculas
//Mueve sPtr al siguiente carcter
20-11
Ejemplo 20.4
La funcin imprimirCaracteres() del programa IMPRIMIR.CPP, declara que los parmetros sPtr son del
tipo const char *. La declaracin se lee de derecha a izquierda como sPtr es un apuntador hacia una
constante de caracteres. El cuerpo de la funcin utiliza una estructura for con la que enva a la salida, uno
por uno, los caracteres de la cadena, hasta que encuentra el carcter nulo. Tras la impresin de un carcter,
se incremente sPtr para apuntar al siguiente carcter de la cadena.
/* El siguiente programa: IMPRIMIR.CPP, imprime una cadena, caracter tras caracter,
mediante un apuntador no constante hacia datos constantes.
*/
#include <iostream.h>
Ejemplo 20.5
El siguiente programa: MODIFICAR.CPP, muestra los mensajes de error que se generan al intentar
compilar una funcin que recibe un apuntador hacia datos constantes y luego intenta emplear dicho
apuntador para modificar los datos.
/* El siguiente programa: MODIFICAR.CPP, intenta modificar la informacin por medio
de un apuntador no constante hacia datos constantes.
*/
#include <iostream.h>
20-12
Como sabemos, los arreglos son tipos de datos agrupados que almacenan elementos de
datos relacionados del mismo tipo bajo un mismo nombre. En otra leccin se estudiar otra
forma de tipo de datos agrupados, llamado estructura (a veces conocido como registro en otros
lenguajes) Una estructura es capaz de almacenar elementos de datos relacionados de distintos
tipos bajo un mismo nombre (por ejemplo, para almacenar informacin sobre todos los
empleados de una compaa) Al invocar una funcin con un arreglo como argumento, ste se
pasa de manera automtica a la funcin simulando una llamada por referencia. Sin embargo, las
estructuras siempre se pasan mediante llamada por valor se pasa una copia de toda la estructura.
Esto requiere la sobrecarga en tiempo de ejecucin que es causada por copiar todos los elementos
de datos de la estructura y almacenarlos en la pila de llamadas de funcin de la computadora
(que es el lugar donde se almacenan las variables locales empleadas en la funcin mientras sta
se ejecuta) Cuando hay que pasar una estructura a una funcin, puede utilizarse un apuntador
hacia datos constantes (o una referencia hacia datos constantes), logrando el desempeo de una
llamada por referencia y la proteccin de una llamada por valor. Cuando el apuntador se pasa
hacia una estructura, slo hay que copiar la direccin en la que se almacena tal estructura. En una
mquina con direcciones de 4 bytes, se hace una copia de 4 bytes de memoria, en lugar de los, tal
vez, cientos o miles de bytes de la estructura.
Un apuntador constante hacia datos no constantes es un apuntador que siempre apunta a
la misma localidad de memoria; los datos de dicha localidad se pueden modificar a travs del
apuntador. Esto es lo predeterminada para un nombre de arreglo, el cual es un apuntador
constante hacia el inicio del arreglo. Es posible acceder y cambiar toda la informacin del arreglo
por medio de su nombre y sus ndices. Un apuntador constante hacia datos no constantes puede
servir para recibir como argumento un arreglo en una funcin que accede a elementos del mismo,
empleado slo notacin de ndices. Los apuntadores que se declaran como const deben ser
inicializados cuando se declaran (si el apuntador es un parmetro de funcin, se inicializa con un
apuntador que se pasa a la funcin)
Ejemplo 20.6
El programa MODIFICAR2.CPP, intenta modificar un apuntador constante. El apuntador ptr se declara como de
tipo int * const. Esta declaracin se lee de derecha a izquierda como ptr es un apuntador constante hacia un
entero. El apuntador se inicializa con la direccin de la variable entera x. El programa intenta asignarle a ptr la
direccin de y, lo cual genera un mensaje de error. Observe que al asignarle el valor 7 a *ptr no se produce un error
el valor al que apunta ptr sigue siendo modificable.
20-13
void main(void)
{
int x, y;
/* ptr es un apuntador constante hacia un entero. Se puede modificar un entero
a travs de ptr, pero ptr siempre apunta a la misma localidad de memoria.
*/
int *const ptr = &x;
*ptr = 7;
ptr = &y;
}//Fin de main()
Los mensajes que enva el compilador son los siguientes:
Cannot modify a const object
y is declared but never used
void main(void)
{
int x = 5, y;
/
/* ptr es un apuntador constante hacia un entero constante. ptr siempre apunta
a la misma localidad y el entero de dicha localidad no puede ser modificado.
*/
const int *const ptr = &x;
cout << *ptr << endl;
*ptr = 7;
ptr = &y;
}//Fin de main()
APUNTADORES Y CADENA LECCIN 20
20-14
20-15
Ejemplo 20.9
C++ ofrece el operador unario sizeof, el cual determina el tamao en bytes de un arreglo (o de cualquier
otro tipo de datos) durante la compilacin del programa. Cuando al nombre de un arreglo se le aplica el
operador sizeof, como en el programa SIZEOF.CPP, ste devuelve la cantidad total de bytes que hay en el
APUNTADORES Y CADENA LECCIN 20
20-16
arreglo como un valor de tipo size_t, que generalmente es un unsigned int. La computadora empleada aqu
almacena las variables de tipo float en 4 bytes de memoria, y arreglo se ha declarado como de 20
elementos, por lo que arreglo ocupa 80 bytes de memoria. Al aplicarle el operador sizeof a un parmetro de
apuntador de una funcin que recibe un arreglo como argumento, dicho operador devuelve el tamao en
bytes (4) del apuntador, no el tamao del arreglo.
/* El siguiente programa: SIZEOF.CPP, utiliza el operador sizeof() aplicado a un nombre
de arreglo, devuelve la cantidad de bytes del arreglo.
*/
#include <iostream.h>
}//Fin de main()
size_t obtenerTamano(float *ptr)
{
return sizeof(ptr);
}//fin de obtenerTamano()
El nmero de elementos de un arreglo tambin puede determinarse por medio de los resultados de dos
operaciones de sizeof. Por ejemplo, considere la siguiente declaracin de arreglo:
double arregloReal[22];
Si las variables del tipo de datos double se almacenan en 8 bytes de memoria, el arreglo arregloReal
contiene un total de 176 bytes. Para determinar el nmero de elementos del arreglo, puede utilizarse la
siguiente expresin:
sizeof (arregloReal) / sizeof(double);
La expresin determina el nmero de bytes en el arreglo arregloReal y divide este valor entre el nmero de
bytes que se utiliza en memoria para almacenar un valor double.
Ejemplo 20.10
El programa SIZEOF2.CPP se vale del operador sizeof para calcular el nmero de bytes utilizados para
almacenar cada uno de los tipos de datos estndar de la computadora particular que se est empleado.
/* El siguiente programa: SIZEOF2.CPP, muestra el uso del operador sizeof */
#include <iostream.h>
#include <iomanip.h>
20-17
void main(void)
{
char c;
short s;
int i;
long l;
float f;
double d;
long double ld;
int arreglo[20], *ptr = arreglo;
cout
}//Fin de main()
El operador sizeof se puede aplicar a cualquier nombre de variable, nombre de tipo o valor constante.
Cuando se aplica a un nombre de variable (que no sea un nombre de arreglo) o valor constante, se devuelve
el nmero de bytes que se emplean para almacenar el tipo de variable o constante especficos. Observe que
los parntesis que se utilizan con sizeof son obligatorios si se indica como operando un nombre de tipo; no
se requieren si se indica como operando un nombre de variable. Es importante recordar que sizeof es un
operador, no una funcin.
20-18
situacin en una mquina con enteros de 4 bytes. Observe que vPtr puede inicializarse para que
apunte al arreglo v mediante cualquiera de las siguientes instrucciones:
vPtr = v;
vPtr = &v[0];
Localidad
3000
3004
v[0]
3008
v[1]
3012
v[2]
3016
v[3]
v[4]
producir 3008 (3000 + 2 * 4), suponiendo que los enteros se almacenan en 4 bytes de memoria.
En el arreglo v, vPtr ahora apuntar a v[2] (vea la figura 20.6)
Localidad
3000
3004
v[0]
v[1]
3008
v[2]
3012
v[3]
3016
v[4]
20-19
arreglo de caracteres, los resultados sern consistentes con la aritmtica comn, pues cada
carcter tiene un byte de longitud.
Si vPtr se hubiera incrementado a 3016, que apunta a v[4], la instruccin
vPtr -= 4;
incrementan el apuntador para que apunte a la siguiente localidad del arreglo. Las instrucciones
--vPtr;
vPtr--;
le asignar a x el nmero de elementos del arreglo de vPtr a v2Ptr, que es 2 en este caso. La
aritmtica de apuntadores carece de significado a menos que se lleve a cabo sobre un arreglo. No
podemos suponer que dos variables del mismo tipo estn almacenadas de manera contigua en la
memoria, a menos que sean elementos adyacentes de un arreglo.
Es posible asignar un apuntador a otro, si ambos son del mismo tipo. De otro modo, es
necesario emplear un operador de conversin mediante cast para convertir el valor del apuntador
del lado derecho de la asignacin al tipo de apuntador a la izquierda de la asignacin. La
excepcin a esta regla es el apuntador a void (es decir, void *), que es un apuntador genrico
capaz de representar cualquier tipo de apuntador. Todos los tipos de apuntadores pueden ser
asignados a void sin necesidad de una conversin mediante cast. Sin embargo, un apuntador a
void no puede asignarse directamente a un apuntador de otro tipo; primero hay que convertir el
apuntador void al tipo de apuntador adecuado.
No es posible desreferenciar un apuntador void *. Por ejemplo, el compilador sabe que un
apuntador a int hace referencia a cuatro bytes de memoria en una mquina con enteros de 4
bytes, pero los apuntadores a void simplemente contienen localidades de memoria para un tipo
de datos desconocido; por lo tanto, el compilador no sabe el nmero preciso de bytes a los que
hace referencia el apuntador. El compilador debe saber el tipo de datos para determinar el
nmero de bytes a desreferenciar para un apuntador en particular. En el caso de un apuntador a
void, esta cantidad de bytes no puede determinarse a partir del tipo.
20-20
Esto es equivalente a tomar la direccin del primer elemento del arreglo, como sigue
bPtr = &b[0];
El elemento b[3] del arreglo se puede referencia de manera alterna con la expresin de
apuntador
*(bPtr + 3)
El arreglo mismo puede ser tratado como apuntador y utilizado con aritmtica de
apuntadores. Por ejemplo, la expresin
*(b + 3)
20-21
tambin se refiere al elemento del arreglo b[3]. En general, todas las expresiones de arreglos con
ndices se pueden escribir con un apuntador y un desplazamiento. En este caso, se utiliz
notacin de apuntador y desplazamiento con el nombre del arreglo como apuntador. Observe que
la instruccin previa no modifica de ninguna manera el nombre del arreglo; b an apunta al
primer elemento de la misma.
Los puntadores se pueden indexar de la misma manera que los arreglos. Por ejemplo, la
expresin
bPtr[1]
hace referencia al elemento b[1] del arreglo; esta expresin se conoce como notacin de
apuntador e ndice.
Recuerde que, en esencia, los nombres de arreglos son apuntadores constantes; siempre
apuntan al inicio del arreglo. Por lo tanto, la expresin
b += 3
es invlida debido a que intenta modificar el valor del nombre del arreglo por medio de
aritmtica de apuntadores.
Ejemplo 20.11
El programa APUNTADORES.CPP, utiliza los cuatro mtodos que hemos explicado para hacer referencia
a los elementos de un arreglo (indizacin de arreglos, apuntador y desplazamiento con el nombre del
arreglo como apuntador, indizacin de apuntadores y apuntador y desplazamiento con un apuntador)
para imprimir los cuatro elementos del arreglo de enteros b.
/* El siguiente programa: APUNTADORES.CPP, utiliza las notaciones de ndices y por apuntadores
con arreglos.
*/
#include <iostream.h>
void main(void)
{
int b[] = {10, 20, 30, 40};
int *bPtr = b;
//Establece bPtr para que apunte al arreglo b
cout
20-22
Ejemplo 20.12
Para ilustrar an ms que los arreglos y los apuntadores son intercambiables, vea las dos funciones de copia
de cadenas (copia1() y copia2()) del programa APUNTADORES2.CPP. Ambas funciones copian una
cadena a un arreglo de caracteres. Tras una comparacin de los prototipos de funcin de copia1() y
copia2(), ambas funciones parecen idnticas (gracias a que los arreglos y los apuntadores son
intercambiables) Estas funciones llevan a cabo la misma tarea, pero se implementan de manera diferente.
/* El siguiente programa: APUNTADORES2.CPP, copia una cadena por medio de notacin de
arreglos y notacin de apuntadores.
*/
#include <iostream.h>
20-23
La funcin copia1() utiliza notacin de ndices de arreglo para copiar la cadena s2 al arreglo de caracteres
s1. Adems, declara una variable entera i, que funciona como contador, la cual ser el ndice del arreglo. El
encabezado de la estructura for realiza la operacin completa de copia su cuerpo es la instruccin vaca. El
encabezado especifica que i se inicializa a cero y se incrementa en uno con cada iteracin del ciclo. La
condicin for, (s1[i] = s2[i]) != \0, realiza la operacin de copia, carcter por carcter, de s2 a s1. Al llegar
al carcter nulo en s2, ste es asignado a s1 y termina el ciclo, pues el carcter nulo es igual a \0. Recuerde
que el valor de una instruccin de asignacin el valor asignado al argumento de la izquierda.
La funcin copia2() se vale de apuntadores y aritmtica de apuntadores para copiar la cadena de s2 al
arreglo de caracteres s1. Otra vez, el encabezado de la estructura for efecta toda la operacin de copia.
Dicho encabezado no incluye ninguna iniciacin de variables. Como en la funcin copia1(), la condicin
(*s1 = *s2) != \0 realiza la operacin de copia. El apuntador s2 es desreferenciado y el carcter resultante
es asignado al apuntador desreferenciado s1. Tras la asignacin que sucede en la condicin, se incrementan
los apuntadores para que apunten al siguiente elemento del arreglo s1 y al siguiente carcter de la cadena
s2, respectivamente. Al encontrar el carcter nulo en s2, se le asigna al apuntador desreferenciado s1 y
termina el ciclo.
Observe que el primer argumento, tanto de copia1() como de copia2(), debe ser un arreglo lo bastante
grande para contener la cadena del segundo argumento. De otra manera, puede suceder un error cuando se
intente escribir en una localidad de memoria fuera de los lmites del arreglo. Adems observe que el
segundo parmetro de cada funcin se declara como const char * (cadena constante) En ambas funciones
se copia el segundo argumento al primero los caracteres se copian del segundo argumento, uno a la vez,
pero nunca se modifican. Por lo tanto, se declara el segundo parmetro de modo que apunte a un valor
constante, aplicando as el principio de menor privilegio. Ninguna de las dos funciones necesita modificar
el segundo argumento, por lo tanto no tienen la capacidad de hacerlo.
ARREGLOS DE APUNTADORES
Los arreglos pueden contener apuntadores. Un uso comn de tal estructura de datos es
para formar arreglos de cadenas. Cada entrada del arreglo es una cadena, pero en C++ una
cadena es, en esencia, un apuntador a su primer carcter. Por lo tanto, cada entrada de un arreglo
de cadenas es, de hecho, un apuntador al primer carcter de una cadena. Considere la declaracin
del arreglo de cadena palos, que podra ser til para representar una baraja de naipes.
char *palos[4] = {Corazones, Diamantes, Trboles, Espadas};
20-24
que la cadena ms larga. Para ayudar a representar una baraja, en la siguiente seccin se emplean
arreglos de cadenas.
palos[0]
\0
palos[0]
\0
palos[0]
\0
palos[0]
\0
10
11
12
Corazones 0
Diamantes 1
Trboles 2
Espadas 3
Figura 20.8. Arreglo (paquete) de doble ndice que representa una baraja.
20-25
En la figura 20.8 cada columna (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12) representan: As,
Dos, Tres, Cuatro, Cinco, Seis, Siete, Ocho, Nueve, Diez, Sota, Reina y Rey respectivamente.
As paquete[2][12] (parte sombreada de la figura 20.8) representa al rey de trboles.
Trboles
Rey
Esta baraja simulada puede barajarse como sigue. Primero, el arreglo paquete se pone
en ceros. Luego se seleccionan al azar una fila (rengln, 0 a 3) y una columna (columna, 0 a 12)
El nmero 1 se inserta en el elemento del arreglo paquete[rengln][columna], indicando que
este naipe va a ser el primero de la baraja en ser repartido. Este proceso continua con la insercin
aleatoria de los nmeros 2, 3, ..., 52 en el arreglo paquete, con lo que se indica el segundo,
tercero, ... y quincuagsimo segundo naipe a repartir. A medida que se va llenando el arreglo
paquete con nmeros de naipe, es posible que una carta se seleccione dos veces, es decir, que
paquete[rengln][columna] sea distinto de cero cuando sea seleccionado. Esta seleccin
simplemente se ignora y se seleccionan al azar otro rengln y otra columna hasta dar con un
naipe no seleccionado. Tarde o temprano los nmeros del 1 al 52 ocuparn los 52 espacios del
arreglo paquete. En este momento se termina el barajado de los naipes.
Este algoritmo de barajado podra ejecutarse durante un tiempo indefinidamente grande
si se seleccionan repetidamente al azar naipes que ya han sido barajados. Este fenmeno se
conoce como aplazamiento indefinido. En los ejercicios se estudiar un mejor algoritmo de
barajado que elimina la posibilidad de dicho fenmeno.
Para repartir el primer naipe se busca en el arreglo la posicin
paquete[rengln][columna] que sea igual a 1. Esto se logra mediante una estructura for anidada
que vara rengln de 0 a 3 y columna de 0 a 12. A qu naipe corresponde dicho espacio del
arreglo? El arreglo palos ha sido precargado con los cuatro palos, por lo que, para obtener el
palo, se imprime la cadena de caracteres palos[rengln] De igual manera, para obtener el valor
del naipe, se imprime la cadena de caracteres cara[columna] Tambin se imprime la cadena de
. La impresin de esta informacin en el orden correcto permite imprimir cada naipe en la
forma Rey de Trboles, As de Diamantes, etctera.
Procedamos mediante la refinacin descendente paso a paso. La parte superior
simplemente es:
Baraja y reparte 52 naipes.
20-26
Con esto se termina el proceso de refinacin. Observe que este programa es ms eficiente
si las partes de barajado y reparticin del algoritmo se combinan, de modo que cada naipe se
reparta a medida que se pone en la baraja. Decidimos programar estas operaciones por separado
debido a que los naipes normalmente se reparten despus de haber sido barajados (no a medida
que se barajan)
APUNTADORES Y CADENA LECCIN 20
20-27
Ejemplo 20.13
En el programa BARAJAS.CPP, se muestra el barajado y reparticin de naipes. Observe el formato de
salida que se utiliza en la funcin repartir():
cout
La instruccin de salida anterior provoca que el valor del naipe se enve a la salida justificado a la derecha
en un campo de 5 caracteres, y que el palo se enve a la salida justificado a la izquierda en un campo de 8
caracteres. La salida se imprime en formado de dos columnas. Si el naipe que se enva a la salida est en la
primera columna, se enva una tabulacin a la salida tras l para saltar a la segunda columna: de otra
manera, se enva un salto de lnea.
/* El siguiente programa: BARAJAS.CPP, baraja y reparte naipes. */
#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
#include <time.h>
void barajar(int[][13]);
void repartir(const int [][13], const char *[], const char *[]);
void main(void)
{
const char *palos[4] = {"Corazones", "Diamantes", "Trboles",
"Espadas"};
const char *cara[13] = {"As", "Dos", "Tres", "Cuatro", "Cinco", "Seis",
"Siete", "Ocho", "Nueve", "Diez", "Sota", "Reina",
"Rey"};
int paquete[4][13] = {0};
srand(time(0));
barajar(paquete);
repartir(paquete, cara, palos);
}//Fin de main()
void barajar(int wPaquete[][13])
{
int renglon, columna;
for(int baraja = 1; baraja <= 52; baraja++)
{
do
{
renglon = rand() % 4;
columna = rand() % 13;
} while(wPaquete[renglon][columna] != 0);
wPaquete[renglon][columna] = baraja;
}//Fin del for
}//Fin de barajar()
20-28
APUNTADORES Y FUNCIONES
Un apuntador a una funcin contiene la direccin que tiene la funcin en la memoria.
Segn hemos visto el nombre de un arreglo es, en realidad, la direccin inicial en memoria del
primer elemento del mismo. Del mismo modo, un nombre de funcin en realidad es la direccin
inicial en memoria del cdigo que lleva a cabo la tarea de la funcin. Los apuntadores a
funciones pueden ser pasados a las funciones, devueltos de ellas, almacenados en arreglos y
asignados a otros apuntadores a funciones.
Ejemplo 20.14
Para ilustrar el uso de los apuntadores a funciones, hemos modificado el programa de ordenamiento de
burbuja de esta leccin al cual llamamos BURBUJA.CPP, dando lugar al siguiente programa,
BURBUJA2.CPP. Este nuevo programa consiste en main() y en las funciones burbuja(), intercambiar(),
ascendente() y descendente() La funcin burbuja() recibe como argumento un apuntador a una funcin
sea ascendente() o descendente()- adems de un arreglo de enteros y su tamao. El programa le pide al
usuario que seleccione si el arreglo debe ordenarse de manera ascendente o descendente. Si el usuario
indica 1, a burbuja() se le pasa un apuntador a la funcin ascendente(), lo que causa que el arreglo se
ordena de menor a mayor. Si el usuario indica 2, a burbuja() se le pasa un apuntador a la funcin
descendente(), lo que causa que el arreglo se ordene de mayor a menor.
/* El siguiente programa: BURBUJA2.CPP, de ordenamiento de usos mltiples que utiliza
apuntadores a funciones.
*/
#include <iostream.h>
#include <iomanip.h>
20-29
cout
= *elemento1Ptr;
= *elemento2Ptr;
= temporal;
20-30
20-31
( *f[opcion]) (opcion);
En la llamada, f[opcion] selecciona el apuntador que se encuentra en la localidad opcion del arreglo. El
apuntador se desreferencia para que llame a la funcin, y opcion se pasa como argumento de la funcin.
Cada funcin imprime el valor de su argumento y su nombre, indicando que se llam de manera correcta.
En los ejercicios se desarrollar un sistema operador por mens.
/* El siguiente programa: APUNTADORES3.CPP, muestra un arreglo de apuntadores a funciones. */
#include <iostream.h>
void funcion1(int);
void funcion2(int);
void funcion3(int);
void main(void)
{
void(*f[3])(int) = {funcion1, funcion2, funcion3};
int opcion;
cout << "Introduzca un nmero entre 0 y 2, 3 para terminar: ";
cin >> opcion;
while(opcion >= 0 && opcion < 3)
{
(*f[opcion])(opcion);
cout << "Introduzca un nmero entre 0 y 2, 3 para terminar: ";
cin >> opcion;
}//Fin de while
cout << "Ejecucin del programa finalizada." << endl;
}//Fin de main()
void funcion1(int a)
{
cout
void funcion2(int b)
{
cout
void funcion3(int c)
{
cout
20-32
En C++, los caracteres son los bloques de construccin fundamentales de los programas
fuente. Todos los programas se componen de una secuencia de caracteres que, agrupados de
manera significativa, son interpretados por la computadora como una serie de instrucciones que
sirven para llevar a cabo una tarea. Un programa puede contener constantes de caracteres. Una
constante de carcter es un valor entero representado corno un carcter entre apstrofos. El valor
de dicha constante es el valor entero del carcter en el conjunto de caracteres de la mquina. Por
ejemplo, z representa el valor entero de z (122 en el conjunto de caracteres ASCII) y \n
representa el valor entero del salto de lnea (10 en el conjunto de caracteres ASCII)
Una cadena es una serie de caracteres que se trata como unidad. Una cadena puede
incluir letras, dgitos y diversos caracteres especiales, como +, -, *, /, $ y otros. En C++ las
literales de cadena o constantes de cadena se escriben entre comillas, como sigue:
Miguel ngel Toledo Martnez
Ave. I.P.N. 36
Mxico, D. F.
(201) 555-12121
(un nombre)
(una direccin)
(una ciudad y un estado)
(un nmero telefnico)
Una cadena en C++ es un arreglo de caracteres que termina con el carcter nulo ( \0)
Una cadena se accede por medio de un apuntador al primer carcter de dicha cadena. El valor de
una cadena es la direccin (constante) de su primer carcter. Por lo tanto, en C++ es apropiado
decir que una cadena es un apuntador constante; de hecho, se trata de un apuntador al primer
carcter de la cadena. En este sentido, las cadenas son como los arreglos, pues un nombre de
arreglo tambin es un apuntador (constante) a su primer elemento.
En una declaracin, se puede asignar una cadena a un arreglo de caracteres o a una
variable de tipo char *. Las declaraciones
char color[]
char *colorPtr
= azul;
= azul;
inicializan una variable con la cadena azul. La primera declaracin crea un arreglo de 5
elementos llamado color que contiene los caracteres a, z, u, l y \. La segunda crea una
variable de apuntador colorPtr que apunta a la cadena, azul, que est en alguna parte de la
memoria.
La declaracin char color [] = {azul}; tambin podra escribirse como
char color[] = {a, z, u, l, \0' );
20-33
Al declarar un arreglo de caracteres para contener una cadena, se debe asegurar que es
lo bastante grande para almacenar dicha cadena y su carcter nulo de terminacin. La
declaracin anterior determina automticamente el tamao del arreglo basndose en el nmero
de inicializadores indicados en la lista de iniciacin.
Es posible asignar una cadena a un arreglo por medio de extraccin de flujo utilizando
cin. Por ejemplo, la siguiente instruccin sirve para asignarle una cadena al arreglo de caracteres
palabra[20]
cin >> palabra;
especifica que cin debe leer un mximo de 19 caracteres y ponerlos en el arreglo palabra,
reservando la 20 localidad del arreglo para el carcter nulo de terminacin de la cadena. El
manipulador de flujo setw() slo se aplica al siguiente valor que se introduzca.
En algunos casos es deseable introducir una lnea de texto completa a un arreglo. Con
este fin, C++ ofrece la funcin cin.getline. sta toma tres argumentos -un arreglo de caracteres
en el que se almacenar la lnea de texto, una longitud y un carcter delimitador.
Por ejemplo, el segmento de programa
char sentencia[80];
cin.getline( sentencia, 80, \n);
declara el arreglo sentencia de 80 caracteres, luego lee del teclado una lnea de texto y la carga
en el arreglo. La funcin termina la lectura de los caracteres cuando encuentra el carcter \n,
cuando se introduce un indicador de fin de archivo o cuando el nmero de caracteres ledos hasta
el momento es de uno menos que la longitud indicada en el segundo argumento (el ltimo
carcter del arreglo se reserva para el carcter nulo de terminacin) Si aparece el carcter
delimitador, se lee y se descarta. El tercer argumento de cin.getline tiene \n como valor
predeterminado, por lo que la llamada de funcin anterior podra haberse escrito as:
cin.getline( sentencia, 80 );
FUNCIONES DE MANIPULACIN DE CADENAS DE LA BIBLIOTECA DE MANEJO DE CADENAS
20-34
Descripcin de la funcin
Prototipo de funcin
Descripcin de la funcin
La funcin a strcpy() copia el segundo argumento (una cadena) al primer argumento (un
arreglo de caracteres que debe ser lo bastante grande para almacenar la cadena y su carcter nulo
de terminacin, el cual tambin se copia) La funcin strncpy() es equivalente a strcpy(), excepto
que strncpy() especifica el nmero de caracteres a copiar de la cadena al arreglo. Observe que la
APUNTADORES Y CADENA LECCIN 20
20-35
La funcin a strcat() aade el segundo argumento (una cadena) al primero (un arreglo
de caracteres que contiene una cadena) El primer carcter del segundo argumento reemplaza el
carcter nulo (\ 0) que termina la cadena del primer argumento. El programador debe
asegurarse de que el arreglo en el que se encuentra la primera cadena sea lo bastante grande para
guardar la combinacin de la primera y segunda cadenas, as como el carcter nulo de
terminacin (copiado de la segunda cadena) La funcin a strncat() agrega una cantidad
especfica de caracteres de la segunda cadena a la primera. Se agrega un carcter nulo de
terminacin al resultado.
Ejemplo 20.17
El programa siguiente: COPIAR2.CPP, muestra las funciones strcat() y strncat()
/* El siguiente programa: COPIAR2.CPP, muestra el uso de las funciones strcat()
y strncat().
*/
#include <iostream.h>
#include <string.h>
20-36
void main(void)
{
char s1[20]
char s2[]
char s3[40]
= "Feliz ";
= "Ao Nuevo ";
= "";
cout << "s1 = " << s1 << "\ns2 = " << s2;
cout << "\nstrcat(s1, s2)
= " << strcat(s1, s2);
cout << "\nstrncat(s3, s1, 6) = " << strncat(s3, s1, 6);
cout << "\nstrcat(s3, s1)
= " << strcat(s3, s1) << endl;
}//Fin de main()
Ejemplo 20.18
El siguiente programa, COMPARAR.CPP, compara tres cadenas por medio de strcmp() y strncmp() La
funcin strcmp() compara el primer argumento con el segundo, carcter por carcter. La funcin devuelve 0
si las cadenas son iguales, un valor negativo si la primera cadena es menor que la segunda y un valor
positivo si la primera cadena es mayor que la segunda. La funcin strncmp() es equivalente a strcmp(),
excepto porque strncmp() compara hasta un nmero especfico de caracteres. La funcin strncmp() no
compara los caracteres que hay despus de un carcter nulo. El programa imprime los valores enteros que
las llamadas de la funcin devuelven.
/* El siguiente programa: COMPARAR.CPP, muestra el uso de las funciones strcmp() y
strncmp().
*/
#include <iostream.h>
#include <iomanip.h>
#include <string.h>
void main(void)
{
char *s1 = "Feliz Ao Nuevo";
char *s2 = "Feliz Ao Nuevo";
char *s3 = "Feliz Vacacin";
cout
cout
}//Fin de main()
Para entender lo que significa que una cadena sea mayor que o menor que otra cadena, considere el
proceso de alfabetizacin de una serie de apellidos. El lector, sin duda, pondra Gonzlez antes que Prez,
pues en el abecedario la primera letra de Gonzlez est antes que la primera letra de Prez. Pero el
abecedario es algo ms que una lista de 30 letras; es una lista ordenada de caracteres. Cada letra aparece en
una posicin especfica de la lista. La Z es algo ms que una letra del abecedario; Z es, especficamente el
carcter 30 del alfabeto.
20-37
Cmo sabe la computadora que una letra viene antes que otra? Todos los caracteres se representan
dentro de la computadora como cdigos numricos; cuando la computadora compara dos cadenas, de hecho
est comparando los cdigos numricos de los caracteres que hay en dichas cadenas.
Con el fin de estandarizar las representaciones de los caracteres, la mayora de los fabricantes de
computadoras han diseado sus mquinas para que operen con alguno de dos esquemas de codificacin: el
ASCII (Cdigo Estndar Americano para el Intercambio de Informacin) o el EBCDIC (Cdigo de
Intercambio Decimal Codificado en Binario Extendido) Hay otros esquemas de codificacin, pero estos
dos son los ms difundidos.
ASCII y EBCDIC se llaman cdigos de caracteres o conjuntos de caracteres. Las manipulaciones de
cadenas y caracteres de hecho comprenden la manipulacin de los cdigos numricos correspondientes, y
no de los caracteres mismos. Esto explica por qu los caracteres y los enteros pequeos son intercambiables
en C++. Debido a que tiene sentido decir que un cdigo numrico es mayor que, menor que o igual a otro
cdigo numrico, es posible relacionar varios caracteres o cadenas entre ellos haciendo referencia a los
cdigos de caracteres.
La funcin strtok() sirve para dividir una cadena en una serie de tokens. Un token es una
secuencia de caracteres separada por caracteres delimitadores (por lo general espacios o marcas
de puntuacin) Por ejemplo, en una lnea de texto, cada palabra puede considerarse como un
token y los espacios que las separan pueden verse como delimitadores.
Se necesitan varias llamadas a strtok() para dividir en tokens una cadena (suponiendo
que la cadena contenga ms de un token) La primera llamada a strtok() contiene dos argumentos:
una cadena a dividir en tokens y una cadena que contiene los caracteres que separan los tokens
(es decir, delimitadores) En el siguiente programa, TOKENS.CPP, la instruccin
tokenPtr = strtok( cadena, l);
asigna tokenPtr como apuntador al primer token de cadena. El segundo argumento de strtok(),
, indica que los tokens en cadena estn separados por espacios. La funcin strtok() busca el
primer carcter de cadena que no sea un carcter delimitador (espacio) ste es el inicio del
primer token. Luego encuentra el siguiente carcter delimitador de la cadena y lo reemplaza con
un carcter nulo ( \ 0 ) Esto termina el token actual. La funcin a strtok() guarda un apuntador
al carcter que sigue al token y devuelve un apuntador al token actual.
Las siguientes llamadas a strtok() que continan dividiendo en tokens a cadena
contienen NULL como primer argumento. El argumento NULL indica que la llamada a strtok()
deber continuar dividiendo en tokens a partir de la localidad de cadena guardada por la ltima
llamada a strtok() Si no quedan tokens cuando se llame a strtok(), ste devuelve NULL.
Ejemplo 20.19
El programa TOKENS.CPP, utiliza strtok() para dividir en tokens la cadena Esta es una oracin con 7
tokens. Cada token se imprime por separado. Observe que strtok() modifica la cadena de entrada, por lo
tanto, debe hacer una copia de la cadena si desea volver a utilizarla en el programa tras las llamadas a
strtok()
/* El siguiente programa: TOKENS.CPP, muestra el uso de la funcin strtok(). */
#include <iostream.h>
#include <string.h>
20-38
void main(void)
{
char cadena[] = "Esta es una oracin con 7 tokens";
char *tokenPtr;
cout
La funcin strlen() toma como argumento una cadena y devuelve el nmero de caracteres que
sta contiene en la longitud no se incluye el carcter nulo de terminacin.
Ejemplo 20.20
El programa siguiente, LONGITUD.CPP, muestra el uso de la funcin strlen()
/* El siguiente programa: LONGITUD.CPP, muestra el empleo de la funcin strlen(). */
#include <iostream.h>
#include <string.h>
void main(void)
{
char *cadena1 = "abcdefghijklmnopqrstuvwxyz";
char *cadena2 = "cinco";
char *cadena3 = "Mxico";
cout
}//Fin de main()
20-39
EJERCICIOS RESUELTOS
20-40
void main(void)
{
char cadena[] = "\"!Alto!\", dijo l.";
cout << cadena;
}//Fin de main()
20-41
void main(void)
{
char tituloLibro[] = "\"El Coronel no tiene quien le escriba\"";
cout
}//Fin de main()
/* ************************************************************************
Una posible implementacin de la funcin strlen(), es la siguiente:
size_t strlen(const char *cadena)
{
int i = 0;
while (cadena[i])
i++;
return (i)
}//Fin de strlen()
**************************************************************************** */
void main(void)
{
char titulo[] = "\"El Coronel no tiene quien le escriba\"";
char libro[128];
strcpy(libro, titulo);
cout << "El nombre del libro es: " << libro << endl;
}//Fin de main()
/* ***********************************************************************
Una implementacin de la funcin strcpy() podra ser la siguiente:
char *strcpy(char *destino, const char *fuente)
{
while (*destino++ = *fuente++)
;
return (destino - 1);
}//Fin de *strcpy()
**************************************************************************/
/* El siguiente programa: ANEXAR.CPP, ilustra el uso de la funcin strcat().
La funcin aade el contenido de la cadena fuente a la cadena de destino
y regresa el apuntador a la cadena de destino. La funcin asume que la cadena
de destino puede acomodar los caracteres de la cadena de origen.
*/
APUNTADORES Y CADENA LECCIN 20
20-42
#include <iostream.h>
#include <string.h>
void main(void)
{
char nombre[64] = "Miguel Angel es tan";
strcat(nombre, " feliz");
cout << nombre;
}//Fin de main()
/* ***********************************************************************
Una posible implementacin de la funcin strcat es la siguiente:
char *strcat(char *destino, const char *fuente)
{
char *original = destino;
while (*destino)
destino**;
void main(void)
{
char nombre[64] = "Miguel Angel";
strncat(nombre, " Martnez", 4);
cout << "Votaste por?: " << nombre << endl;
}//Fin de main()
/* ***********************************************************************
Una posible implementacin de la funcin strncat() es la siguiente:
char *strncat(char *destino, const char *fuente, int n)
{
char *original = destino;
int i = 0;
while (*destino)
destino++;
while ((i++ < n) && (*destino++ = *fuente++))
;
20-43
if (i > n)
*destino = NULL;
return (original);
}//Fin de strncat()
************************************************************************** */
/* El siguiente programa: STRXFRM.CPP, ilustra el uso de la funcin strxfrm() */
#include <iostream.h>
#include <string.h>
void main(void)
{
char fuente[64] = "\El Coronel no tiene quien le escriba\"";
char destino[64];
int longitud;
longitud = strxfrm(destino, fuente, sizeof(fuente));
cout << "Longitud de la cadena: " << longitud << endl;
cout << "Contenido del destino: " << destino << endl;
cout << "Contenido de la fuente: " << fuente << endl;
}//Fin de main()
20-44
void main(void)
{
cout << strlwr("\"El Coronel no tiene quien le escriba\"") << endl;
cout << strupr("\"El Coronel no tiene quien le escriba\"") << endl;
}//Fin de main()
/* *********************************************************************
Una posible implementacin de la funcin strlwr() es la siguiente:
#include <ctype.h>
char *strlwr(char *cadena)
{
char *original = cadena;
while (*cadena)
{
*cadena = tolower(*cadena);
cadena++;
}//Fin de while
return(original)
}//Fin de *strlwr()
************************************************************************** */
20-45
void main(void)
{
char titulo[64] = "\"El Coronel no tiene quien le escriba\"";
char *ptr;
if (ptr = strchr(titulo, 'C'))
cout
<< "La primera ocurrencia de C es en el desplazamiento: "
<< (ptr - titulo) << endl;
else
cout << "NO SE ENCONTR EL CARCTER BUSCADO!" << endl;
}//Fin de main()
/* ***********************************************************************
Una posible implementacin de la funcin strchr() es la siguiente:
char *strchr(const char *cadena, int letra)
{
while ((*cadena != letra) && (*cadena)
cadena++;
return(cadena);
}//Fin de *strchr()
************************************************************************** */
/* El siguiente programa: STRRCHR.CPP, ilustra el uso de la funcin strrchr */
#include <iostream.h>
#include <string.h>
20-46
/* ***********************************************************************
Una posible implementacin de la funcin strrchr() es la siguiente:
char *strrchr(const char *cadena, int letra)
{
char *ptr = NULL;
while (*cadena)
{
if (*cadena == letra)
ptr = cadena;
cadena++;
}//Fin de while
return(ptr);
}//Fin de *strrch()
************************************************************************** */
FUNCIONES DE CADENA QUE UTILIZAN CADENAS UBICADAS FUERA DE LOS 64KB (far string)
Algunos compiladores poseen funciones que aceptan apuntadores ubicados fuera de los
64 kbyes. Por ejemplo, para determinar la longitud de una cadena referenciada por un apuntador
far, puede utilizar la funcin _fstrlen(), como se muestra a continuacin:
#include <string.h>
size_t _fstrlen(const char *string)
En el caso de que no exista en el compilador y usted tenga una funcin que maneje
apuntadores ubicados en los 64 kbytes, puede modificar los mismos como se muestra en el
siguiente ejemplo, para la funcin fstreql():
int fstreql (char far *str1, char far *str2)
{
while ((*str1 == *str2) && (*str1))
{
str1++;
str2++;
}//Fin de while
return ((*str1 == NULL) && (*str2 ==NULL));
}//Fin de fstreql()
20-47
void main(void)
{
cout << "Comparando Abc y Abc : " << strcmp("Abc", "Abc") << endl;
cout << "Comparando abc y Abc : " << strcmp("abc", "Abc") << endl;
cout << "Comparando abcd y abc: " << strcmp("abcd", "abc") << endl;
cout << "Comparando Abc y Abcd: " << strcmp("Abc", "Abcd") << endl;
}//Fin de main()
20-48
/* ***********************************************************************
Una posible implementacin de la funcin strcmp() es la siguiente:
int strcmp(const char *s1, const char *s2)
{
while ((*s1 == *s2) && (*s1))
{
s1++;
s2++;
}//Fin de while
if ((*s1 == *s2) && (! *s1) // Las cadenas son iguales
return(o);
else if ((*s1) && (! *s2)) // cadena s1 > cadena s2
return(-1);
else if ((*s2) && (! *s1)) // cadena s2 > cadena s1
return(1);
else
return ((*s1 > *s2) ? -1; 1);
}//Fin de strcmp()
************************************************************************** */
void main(void)
{
cout << "Comparando tres letras de Abc con Abc: " <<
strncmp("Abc", "Abc", 3) << endl;
cout << "Comparando tres letras de abc con Abc: " <<
strncmp("abc", "Abc", 3) << endl;
cout << "Comparando tres letras de abcd con abc: " <<
strncmp("abcd", "abc", 3) << endl;
cout << "Comparando cinco letras de Abc con Abcd: " <<
strncmp("Abc", "Abcd", 5) << endl;
}//Fin de main()
20-49
/* ***********************************************************************
Una posible implementacin de la funcin strncmp() es la siguiente:
int strncmp(const char *s1, const char *s2, int n)
{
int i = o;
while ((*s1 == *s2) && (*s1) && i < n)
{
s1++;
s2++;
i++
}//Fin de while
if (i == n)
// Las cadenas son iguales
return (0);
else if ((*s1 == *s2) && (! *s1) // Las cadenas son iguales
return(o);
else if ((*s1) && (! *s2))
// cadena s1 > cadena s2
return(-1);
else if ((*s2) && (! *s1))
// cadena s2 > cadena s1
return(1);
else
return ((*s1 > *s2) ? -1; 1);
}//Fin de strncmp()
************************************************************************** */
/* El siguiente programa: CMPCASE.CPP, ilustra el uso de las funciones stricmp()
y strncmpi(), las cuales hacen comparaciones sin diferenciar maysculas de
minsculas.
*/
#include <iostream.h>
#include <string.h>
void main(void)
{
cout
cout
cout
cout
<< "Comparando Abc con Abc: " << stricmp("Abc", "Abc") << endl;
<< "Comparando abc con Abc: " << stricmp("abc", "Abc") << endl;
<< "Comparando tres letras de abcd con ABC: "
<< strncmpi("abcd", "ABC", 3) << endl;
<< "Comparando 5 letras de abc con Abcd: "
<<
strncmpi("abc", "Abcd", 5);
}//Fin de main()
20-50
propsito
Convierte de ascii a punto flotante.
Convierte de ascii a entero.
Convierte de ascii a entero largo.
Convierte de ascii a doble precisin.
Convierte de ascii a entero largo.
void main(void)
{
int intResultado;
float floatResultado;
long longResultado;
intResultado = atoi("1234");
floatResultado = atof("12345.678");
longResultado = atol("1234567L");
cout
}//Fin de main()
void main(void)
{
char *titulo;
if ((titulo = strdup("\"El Coronel no tiene quien le escriba\"")))
cout << "Ttulo: " << titulo << endl;
else
cout << "Error al duplicar la cadena" << endl;
}//Fin de main()
20-51
/* ***********************************************************************
Una posible implementacin de la funcin strdup() es la siguiente:
#include <string.h>
#include <malloc.h>
return(ptr);
}//Fin de *strdup()
************************************************************************** */
void main(void)
{
cout
cout
cout
}//Fin de main()
/* **********************************************************************
Una posible implementacin de la funcin strspn es la siguiente:
size_t strspn(const char *s1, const char *s2)
{
int i, j;
for (i = 0; *s1; i++, s1++)
{
for (j = 0; s2[j]; j++)
if (*s1 == s2[j])
break;
if (s2[j] == NULL);
break;
}//Fin del for
return (i);
}//Fin de sstrspn()
************************************************************************** */
APUNTADORES Y CADENA LECCIN 20
20-52
void main(void)
{
cout
cout
cout
}//Fin de main()
/* ***********************************************************************
Una posible implementacin de la funcin strstr() es la siguiente:
char *strstr(const char *s1, const char *s2)
{
int i, j, k;
for (i = 0; s1[i]; i++)
for (j = i, k = 0; s1[j] == s2[k]; j++, k++)
if (! s2[k + 1])
return (s1 + i);
return (NULL);
}//Fin de *strstr()
************************************************************************** */
20-53
20-54
20-55
20-56
El archivo de cabecera ctype.h contiene las macros islower y isupper que le ayudan a
determinar si un carcter es minscula o mayscula respectivamente:
if (islower(carcter))
if(isupper(carcter))
Desde el punto de vista gramatical los smbolos de puntuacin incluyen a la coma, punto
y coma, punto, interrogacin y as sucesivamente. Desde punto de vista del lenguaje C un
smbolo es de puntuacin si es un carcter grfico que no sea alfanumrico. El archivo de
cabecera ctype.h contiene la macro ispunct que le ayuda a determinar si un carcter es o no
smbolo de puntuacin:
if (ispunct(carcter))
20-57
El carcter espacio incluye el espacio, tabulador, retorno de carro, nueva lnea, tabulador
vertical y alimentacin de hoja. El archivo de cabecera ctype.h contiene la macro isspace que le
ayuda a determinar si un carcter es o no carcter espacio:
if (isspace(carcter))
//Para putchar
//Para _toupper() y toupper()
20-58
//Para putchar()
//Para tolower() y _tolower()
Para asegurar que un carcter es un carcter ASCII vlido, su valor se encuentra entre 0 y
127 utilice la macro toascii contenida en archivo de cabecera ctype.h:
Una implementacin de dicha macro es la siguiente:
#define toascii(character) ((character) & 0x7F)
Lo que se logra con el valor hexadecimal 0x7F es hacer que el valor ASCII sea siempre
positivo (0 a 127)
/* La funcin printf, le permite escribir salida formateada a la pantalla.
Dependiendo de los requerimientos de su programa, existen ocasiones en que
necesita trabajar con una cadena de caracteres que contiene salida formatea
da. Por ejemplo, suponga que sus empleados tienen 5 dgitos como nmero de
empleado y tres caracteres que identifican la regin (tal como OAX para Oaxaca).
Suponga que almacena informacin acerca de cada empleado en un archivo cuyo
nombre es una combinacin de estos dos valores (tal como OAX12345). La
funcin sprintf le permite escribir salida formateada en una cadena de
caracteres.
El siguiente programa: SPRINTF.CPP, utiliza la funcin sprintf para crear
un nombre de archivo de 8 caracteres.
*/
#include <stdio.h>
20-59
void main(void)
{
int numeroEmpleado
= 12345;
char region[]
= "OAX";
char nombreArchivo[64];
sprintf(nombreArchivo, "%s%d", region, numeroEmpleado);
printf("Nombre del empleado: %s\n", nombreArchivo);
}//Fin de main()
void main(void)
{
int edad;
float salario;
char cadena[] = "33 25000.00";
sscanf(cadena, "%d %f\n", &edad, &salario);
printf("Edad: %d salario %f\n", edad, salario);
}//Fin de main()
/* El siguiente programa: CADENA1.CPP, utiliza las funciones strlen(), strcat()
busca un caracter en una cadena y lo remplaza por otro caracter.
*/
#include <iostream.h>
#include <string.h>
20-60
cout
cout
<< "Las cadenas encadenadas son: " << cadenaGrande << endl;
<< "La nueva cadena tiene " << strlen(cadenaGrande)
<< " caracteres" << endl << endl;
20-61
{
char temp[TAMANO_CADENA];
strcpy(temp, cadena[i]);
strcpy(cadena[i], cadena[j]);
strcpy(cadena[j], temp);
}//Fin de if
cout << "El arreglo ordenado es:" << endl;
for (int i = 0; i < TAMANO_ARREGLO; i++)
cout << cadena[i] << endl;
}//Fin de main()
20-62
/* El siguiente programa: CADENA4.CPP, busca una subcadena dentro de una cadena e indica
en donde comienza. Busca tambin un caracter indicando en que posicin se encuentra.
*/
#include <iostream.h>
#include <string.h>
20-63
contador = 0;
while (p)
{
contador++;
indice = p - cadenaPrincipal;
cout << "Localizado en el ndice " << indice << endl;
p = strchr(++p, caracterBuscar);
}//Fin de while
if (contador == 0)
cout << "No localizado el caracter en la cadena principal" << endl;
}//Fin de main()
Bajo cada clase, aada la seccin Mensajes enviados a los objetos de otras clases (a tales mensajes se les
llama colaboraciones; a partir de ahora emplearemos este trmino) y liste las interacciones entre las clases que
quedan, es decir, bajo la clase persona, incluya la entrada :
APUNTADORES Y CADENA LECCIN 20
20-64
2.
3.
4.
5.
6.
Suponer que el * con el que se declara un apuntador se extiende a todos los nombres de variables de una lista de
variables de apuntador separada por comas puede causar que tales apuntadores se declaren como no
apuntadores. Cada apuntador debe declararse con un * como prefijo del nombre.
Desreferenciar un apuntador que no ha sido inicializado de manera apropiada o al que no se le ha indica- do
que apunte a una localidad especfica de memoria, puede producir un error fatal de tiempo de ejecucin o
modificar accidentalmente informacin importante, permitiendo que el programa se ejecute hasta el final, lo que
arrojar resultados incorrectos.
El intento por desreferenciar un no apuntador es un error de sintaxis.
Desreferenciar un apuntador 0 por lo general causa un error fatal en tiempo de ejecucin.
Es un error no desreferenciar un apuntador cuando es necesario hacerlo con el fin de obtener el valor al que
apunta el apuntador.
No inicializar un apuntador que se ha declarado corno const es un error de sintaxis.
20-65
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
El empleo del operador sizeof en una funcin con el fin de determinar el tamao en bytes de un parmetro de
arreglo da como resultado el tamao en bytes del apuntador, no el tamao en bytes del arreglo.
La omisin de los parntesis en una operacin sizeof cuando el operando es un nombre de tipo es un error de
sintaxis.
La utilizacin de aritmtica de apuntadores sobre un apuntador que no hace referencia a un arreglo de valores
normalmente es un error de lgica.
La resta o comparacin de dos apuntadores que no hacen referencia a elementos del mismo arreglo por lo
general es un error de lgica.
Salirse de cualquiera de los extremos de un arreglo al aplicar aritmtica de apuntadores normalmente es un
error de lgica.
La asignacin de un apuntador de un tipo a otro apuntador de un tipo distinto (que no sea void *) sin convertir el
primer apuntador al tipo del segundo es un error de sintaxis.
Desreferenciar un apuntador void * es un error de sintaxis.
Aunque los nombre de arreglos son apuntadores al inicio de stos y aunque los apuntadores se pueden modificar
con expresiones aritmticas, los nombres de los arreglos no pueden modificarse mediante expresiones
aritmticas, dado que son apuntadores constantes.
Es un error no asignar suficiente espacio en un arreglo de caracteres para almacenar el carcter nulo de
terminacin de la cadena.
Es un error crear o utilizar una cadena que no contenga un carcter nulo de terminacin.
El procesamiento de un solo carcter como cadena puede generar un error fatal en tiempo de ejecucin. Una
cadena es un apuntador -probablemente sea un entero de tamao respetablemente grande. Sin embargo, un
carcter es un entero pequeo (los valores ASCII van de 0 a 255) En muchos sistemas, esto provoca un error,
pues las direcciones de memoria bajas se reservan para fines especiales, como controladores de interrupciones
del sistema operativo -por lo tanto, suceden violaciones de acceso.
Si pasa un carcter como argumento a una funcin cuando se espera una cadena, puede causar un error fatal
en tiempo de ejecucin.
Pasar una cadena como argumento de una funcin cuando se espera un carcter es un error de sintaxis.
Es un error olvidar incluir el archivo de encabezado <string.h> cuando se emplean funciones de la biblioteca
de manejo de cadenas.
No agregar un carcter nulo de terminacin al primer argumento de strncpy cuando el tercer argumento es
menor o igual que la longitud de la cadena del segundo argumento puede ser causa de errores fatales en tiempo
de ejecucin.
La suposicin de que strcmp y strncmp devuelven 1 cuando sus argumentos son iguales es un error de lgica.
Ambas funciones devuelven 0 (que es el valor de falso de C++) cuando hay una igualdad. Por lo tanto, al probar
la igualdad de dos cadenas, el resultado de la funcin strcmp o strncmp debe compararse con 0 para determinar
si son iguales.
Es un error no notar que strtok modifica la cadena que se est dividiendo en tokens y luego intentar utilizarla
como si fuera la cadena original, sin modificaciones.
3.
4.
5.
Aunque no se requiere, la inclusin de las letras Ptr en los nombres de variables de apuntador deja claro que
dichas variables son apuntadores y que necesitan manipularse como tales.
Utilice una llamada por valor para pasar argumentos a una funcin, a menos que el invocador requiera
explcitamente que la funcin llamada modifique el valor de la variable argumento en el entorno del invocador.
ste es otro ejemplo del principio de menor privilegio.
Antes de utilizar una funcin, revise su prototipo de funcin a fin de determinar los parmetros que puede
modificar.
Utilice la notacin de arreglos en lugar de la notacin de apuntadores cuando manipule arreglos. Aunque la
compilacin del programa tal vez tarde un poco ms, con seguridad ser ms claro.
Al almacenar una cadena de caracteres en un arreglo de caracteres, debe asegurarse de que el arreglo es lo
bastante grande para contener la cadena ms grande que almacenar. C++ permite el almacenamiento de
cadenas de cualquier longitud. Si una cadena es ms grande que el arreglo en el que la almacenar, los
caracteres que estn despus del final del arreglo sobrescribirn la informacin en memoria que se encuentre a
continuacin de dicho arreglo.
20-66
PROPUESTAS DE DESEMPEO
1.
2.
3.
Los objetos grandes, como las estructuras, se deben pasar mediante apuntadores hacia datos constantes o con
referencias hacia datos constantes, con el fin de lograr los beneficios en desempeo de la llamada por referencia
y la seguridad de la llamada por valor.
sizeof es un operador unario de tiempo de compilacin, no una funcin de tiempo de ejecucin. Por lo tanto,
la utilizacin de sizeof no afecta negativamente el desempeo en tiempo de ejecucin.
A veces los algoritmos que emergen de manera natural pueden tener sutiles problemas de desempeo, como el
aplazamiento indefinido. Es importante buscar algoritmos que eviten el aplazamiento indefinido.
PROPUESTAS DE PORTABILIDAD
1.
2.
3.
4.
5.
6.
7.
El formato en el que se enva a la salida un apuntador depende de la mquina. Algunos sistemas envan a la
salida los valores de apuntador corno enteros hexadecimales, mientras que otros lo hacen como enteros
decimales.
Aunque const est bien definido en el ANSI C y C++, algunos compiladores no lo aplican adecuadamente.
El nmero de bytes que se utilizan para almacenar un tipo de datos particular puede variar segn el sistema. Al
escribir programas que dependan de los tamaos de los tipos de datos y que se ejecutarn en varios sistemas de
cmputo, hay que utilizar sizeof para determinar el nmero de bytes en que se almacenan los distintos tipos de
datos.
La mayora de las computadoras actuales tienen enteros de 2 o 4 bytes. Algunas de las ms nuevas utilizan
enteros de 8 bytes. Debido a que los resultados de la aritmtica de apuntadores dependen del tamao de los
objetos a los que apunta un apuntador, la aritmtica de apuntadores depende de la mquina.
Cuando se inicializa una variable de tipo char * con una literal de cadena, algunos compiladores pueden poner
dicha cadena en alguna localidad de memoria en la que no puede ser modificado. Si necesitara modificar una
literal de cadena, deber almacenarla en un arreglo de caracteres, a fin de asegurar la posibilidad de modificarla
en todos los sistemas.
Los cdigos numricos empleados para la representacin de caracteres pueden cambiar segn la computadora.
No use los cdigos ASCII especficos, como en el caso de if ( ch == 65 ) ms bien, emplee la constante del
carcter, como en if ( ch = = A ).
2.
3.
4.
5.
El calificador const puede servir para aplicar el principio de menor privilegio. La utilizacin del principio de
menor privilegio para disear software de la manera correcta puede reducir en gran medida el tiempo de
depuracin y los efectos secundarios, as como simplificar la modificacin y el mantenimiento de los
programas.
Si un valor no cambia (o no debe cambiar) en el cuerpo de una funcin a la cual se pasa, el parmetro debe ser
declarado como const con el fin de asegurar que no sea modificado por accidente.
Slo es posible alterar un valor en un invocador cuando se efecta una llamada por valor. Este valor debe
asignarse a partir del valor de devolucin de la funcin. Si hay que modificar varios valores en un invocador, es
necesario pasar varios argumentos mediante llamada por referencia.
La colocacin de prototipos de funcin en las definiciones de otras funciones aplica el principio de menor
privilegio, restringiendo las llamadas de funcin a las funciones en las que aparecen los prototipos.
Al pasar un arreglo a una funcin, tambin hay que pasar su tamao (en lugar de integrarlo en la funcin)
Esto contribuye a hacer ms general la funcin. Las funciones generales con frecuencia son reutilizables en
otros programas.
Los apuntadores se deben inicializar con el fin de evitar que apunten a reas desconocidas o no inicializadas de
la memoria.
20-67
20-68
!"Al llevar a cabo aritmtica de apuntadores sobre un arreglo de caracteres, el resultado es como el de la
aritmtica normal, pues cada carcter se almacena en un byte de memoria.
!"Se puede asignar un apuntador a otro si ambos son del mismo tipo. De otra manera, debe aplicarse una
conversin mediante cast. La excepcin a esto es un apuntador a void, que es un tipo de apuntador general
que puede contener apuntadores de cualquier tipo. A los apuntadores a void se les puede asignar
apuntadores de otros tipos. Es posible asignar un apuntador void a un apuntador de otro tipo slo a travs
de una conversin mediante cast explcita.
!"No se puede desreferenciar un apuntador a void.
!"Los apuntadores se pueden comparar por medio de los operadores de igualdad y relacionales. Las
comparaciones de apuntadores por lo general slo tienen sentido si los apuntadores apuntan a miembros del
mismo arreglo.
!"Los apuntadores se pueden indexar de la misma manera que los nombres de arreglos.
!"Un nombre de arreglo es equivalente a un apuntador al primer elemento del mismo.
!"En la notacin de apuntador/desplazamiento, el desplazamiento es igual a un ndice de arreglo.
!"Todas las expresiones de arreglos indexadas se pueden escribir con un apuntador y un desplazamiento,
utilizando corno apuntador el nombre del arreglo o un apuntador separado que apunte a dicho arreglo.
!"Un nombre de arreglo es un apuntador constante que siempre apunta a la misma localidad de memoria.
!"Es posible tener arreglos de apuntadores.
!"Un apuntador a una funcin es la direccin donde reside el cdigo de la funcin.
!"Los apuntadores a funciones pueden ser pasados a otras funciones, devueltos de otras funciones,
almacenados en arreglos y asignados a otros apuntadores.
!"Un uso comn de los apuntadores de funcin es en los llamados sistemas operados por men. Los
apuntadores de funcin sirven para seleccionar la funcin a llamar segn un elemento particular del men.
!"La funcin strcpy copia su segundo argumento (una cadena) a su primer argumento (un arreglo de
caracteres) El programador debe asegurarse de que el arreglo es lo bastante grande para almacenar la
cadena y su carcter nulo de terminacin.
!"La funcin strncpy es equivalente a strcpy, excepto que una llamada a strncpy especifica el nmero de
caracteres a copiar de la cadena al arreglo. El carcter nulo de terminacin slo se copiar si el nmero de
caracteres a copiar es de uno ms que la longitud de la cadena.
!"La funcin strcat aade la cadena de su segundo argumento (incluyendo el carcter nulo de terminacin) a
la cadena de su primer argumento. El primer carcter de la segunda cadena reemplaza el carcter nulo ( \0
) de la primera cadena. El programador debe asegurarse de que el arreglo en el que est la primera cadena
es lo bastante grande para almacenar tanto la primera cadena como la segunda.
!"La funcin strncat agrega un nmero de caracteres especificado de la segunda cadena a la primera. Se
aade un carcter nulo de terminacin al resultado.
!"La funcin strcmp compara la cadena de su primer argumento con la cadena de su segundo argumento,
carcter por carcter. La funcin devuelve 0 si ambas son iguales, un resultado negativo si la primera es
menor que la segunda y un valor positivo si la primera es mayor que la segunda.
!"La funcin strncmp es equivalente a strcmp, excepto que strncmp compara un nmero especificado de
caracteres. Si el nmero de caracteres de una cadena es menor que el nmero especificado, strncmp
compara los caracteres hasta que se encuentra el carcter nulo en la cadena ms corta.
!"Una secuencia de llamadas a strtok divide una cadena en tokens separados por los caracteres contenidos en
el segundo argumento. La primera llamada contiene como primer argumento la cadena a dividir en tokens,
y las llamadas siguientes que continan dividiendo la misma cadena en tokens contienen NULL como
primer argumento. Cada llamada devuelve un apuntador al token actual. Si no hay ms tokens al llamar a
strtok, se devuelve NULL.
!"La funcin strlen toma como argumento una cadena y devuelve el nmero de caracteres que hay en ella; en
la longitud de la cadena no se incluye el carcter nulo de terminacin.
!"Una cadena de caracteres es un arreglo de caracteres que terminan por los caracteres ASCII 0 o NULL.
!"Puede crear una cadena de caracteres dentro de su programa mediante la declaracin de un arreglo de tipo
char.
!"Su programa es responsable de agregar el carcter NULL despus del ltimo carcter de la cadena.
APUNTADORES Y CADENA LECCIN 20
20-69
!"Cuando su programa utiliza cadenas constantes entre comillas, el compilador C++ automticamente
agrega el carcter NULL.
!"C++ le permite inicializar las cadenas al declararlas, especificando los caracteres deseados entre comillas.
!"La mayora de los compiladores C++ proporcionan un conjunto de funciones para el manejo de cadenas en
las libreras en tiempo de ejecucin.
PREGUNTAS Y PROBLEMAS
PREGUNTAS
1.
2.
Indique si las siguientes oraciones son verdaderas o falsas. Si la respuesta es falsa, explique por qu.
a) El operador de direccin & slo puede aplicarse a constantes, a expresiones y a variables declaradas
con la clase de almacenamiento register.
b) Se puede desreferenciar un operador declarado como void.
c) No es posible asignar un apuntador de un tipo a otro de otro tipo sin una operacin de conversin
mediante cast.
3.
Responda las siguientes preguntas. Suponga que los nmeros de punto flotante de precisin sencilla se
almacenan en 4 bytes y que la direccin de inicio del arreglo est en la localidad 1002500 de la memoria. Cada
parte del ejercicio debera utilizar el resultado de las partes previas, donde aplique.
a) Declare un arreglo de tipo float llamado numeros que tenga 10 elementos, los cuales deber inicializar a
los valores 0.0, 1.1, 2.2, ..., 9.9. Suponga que la constante simblica TAMANO se ha definido como10.
b) Declare el apuntador nPtr que apunta a un objeto de tipo float.
c) Imprima los elementos del arreglo numeros utilizando la notacin de ndices de arreglos. Emplee una
estructura for y suponga que se ha declarado la variable de control entera i. Imprima cada nmero con
una posicin de precisin a la derecha del punto decimal.
d) D dos instrucciones independientes que asignen la direccin de inicio del arreglo numeros a la variable
de apuntador nPtr.
e) Imprima los elementos del arreglo numeros por medio de notacin de apuntador/desplazamiento con el
apuntador nPtr.
f) Imprima los elementos del arreglo numeros utilizando notacin de apuntador/desplazamiento con el
nombre del arreglo como apuntador.
g) Imprima los elementos del arreglo numeros indexando el apuntador nPtr.
h) Haga referencia al elemento 4 del arreglo numeros empleando notacin de ndices de arreglos, notacin
de apuntador/desplazamiento con el nombre del arreglo como apuntador, notacin de ndice de apuntador
con nPtr y notacin de apuntador/desplazamiento con nPtr.
i) Suponiendo que nPtr apuntara al inicio del arreglo numeros, a qu direccin hace referencia nPtr + 8?
Qu valor se almacena en dicha localidad?
j) Suponiendo que nPtr apunte a numeros[5], qu direccin referencia nPtr despus de que se ejecuta nPtr
-= 4?. Qu valor se almacena en esa localidad?
4.
Escriba una sola instruccin que lleve a cabo la tarea indicada para cada uno de los siguientes casos. Suponga
que ya se han declarado las variables de punto flotante numero1 y numero2, y que numero1 se ha inicializado a
7.3. Tambin suponga que la variable ptr es de tipo char * y que los arreglos s1[100] s2[100] son de tipo char.
a)
b)
c)
d)
20-70
e)
f)
g)
h)
i)
j)
k)
l)
5.
Haga lo siguiente:
a) Escriba el encabezado de una funcin llamada intercambio(), que toma como parmetros los apuntadores
a los nmeros de punto flotante x e y y que no devuelve nada.
b) Escriba el prototipo de la funcin de la parte (a).
c) Escriba el encabezado de una funcin llamada evaluar(), que devuelve un entero y toma como parmetros
el entero x y un apuntador a la funcin poly. sta toma un parmetro entero y devuelve un entero.
d) Escriba el prototipo de funcin de la parte (c)
e) Muestre dos mtodos diferentes para inicializar el arreglo de caracteres vocal con la cadena de vocales
AEIOU.
6.
7.
Qu imprimen las siguientes instrucciones cuando se ejecutan (si es que imprimen algo)? Si alguna de estas
contiene un error, descrbalo e indique la manera de corregirlo. Suponga las siguientes declaraciones de
variables:
char s1[50] = jack, s2[50] = jill, s3[50], *sptr;
a)
b)
c)
d)
20-71
8.
Indique si las siguientes oraciones son verdaderas o falsas. Si la respuesta es falsa, explique por qu.
a) La comparacin de dos apuntadores que apuntan a arreglos diferentes no tiene sentido.
b) Debido a que el nombre de un arreglo es un apuntador al primer elemento de dicho arreglo, los nombres
de arreglo deben manipularse de la misma manera que los apuntadores.
9.
Conteste a lo siguiente. Suponga que los enteros sin signo se almacenan en 2 bytes y que la direccin inicial del
arreglo es la localidad 1002500 de la memoria.
a) Declare un arreglo de tipo unsigned int llamado valores que cuente con 5 elementos, los cuales deber
inicializar a los enteros pares del 2 al 10. Suponga que la constante simblica se ha definido como 5.
b) Declare el apuntador vPtr que apunta a un objeto de tipo unsigned int.
c) Imprima los elementos del arreglo valores utilizando notacin de ndices de arreglo. Emplee una
estructura for y suponga que se ha declarado la variable de control entera i.
d) Escriba dos instrucciones separadas que asignen la direccin inicial del arreglo valores a la variable de
apuntador vPtr.
e) Imprima los elementos del arreglo valores utilizando notacin de apuntador/desplazamiento.
f) Imprima los elementos del arreglo valores utilizando notacin de apuntador/desplazamiento con el
nombre del arreglo como apuntador.
g) Imprima los elementos del arreglo valores indexando el apuntador al arreglo.
h) Haga referencia al elemento 5 de valores utilizando notacin de ndices de arreglo, notacin de
apuntador/desplazamiento con el nombre del arreglo como apuntador, notacin de ndices de apuntador y
notacin de apuntador/desplazamiento.
i) A qu direccin hace referencia vPtr + 3? Qu valor se almacena en dicha localidad?
j) Suponiendo que vPtr apunte a valores[4], a qu direccin hace referencia vPtr -= 4? Qu valor se
almacena en dicha localidad?
10. Para cada uno de los siguientes puntos, escriba una instruccin que lleve a cabo la tarea indicada. Suponga que
se han declarado las variables enteras largas valor1 y valor2, y que valor1 se ha inicializado a 200000.
a)
b)
c)
d)
e)
f)
g)
20-72
PROBLEMAS
Nota: Los problemas 1 a 4 son algo complejos. Una vez que los haya hecho, debera poder implementar con
facilidad los juegos de naipes ms comunes.
1.
Modifique el programa BARAJAS.CPP, para que la funcin de barajado de los naipes reparta una mano de
pquer de cinco naipes. Despus escriba las funciones que realicen lo siguiente:
a)
b)
c)
d)
e)
f)
2.
Utilice las funciones desarrolladas en el problema 1 para escribir un programa que reparta dos manos de
pquer de cinco naipes, las evale y determine cul es la mejor.
3.
Modifique el problema desarrollado en el problema 2 de modo que simule al repartidor. La mano del repartidor
se baraja cerrada, para que el jugador no la pueda ver. El programa deber evaluar dicha mano y, con base en
su calidad, cambiar las inservibles de la mano original por uno, dos o tres naipes. El programa deber reevaluar
la mano del repartidor. (Precaucin: ste es un problema complicado)
4.
Modifique el programa desarrollado en el problema 3 para que pueda manejar automticamente la mano del
repartidor, pero que le permita al jugador decidir cules de los naipes de su propia mano cambiar. El programa
deber evaluar ambas manos y decidir quin gana. Ahora utilice este nuevo programa para jugar 20 juegos
contra la computadora. Quin gana ms juegos, usted o la computadora? Haga que uno de sus amigos
juegue 20 juegos contra la computadora. Quin gana ms juegos? Con base en estos resultados, haga las
modificaciones necesarias para refinar el programa de pquer (ste tambin es un problema difcil) Juegue 20
juegos ms. El programa modificado juega mejor?
5.
0
1
14
27
40
1
2
15
28
41
2
3
16
29
42
3
4
17
30
43
4
5
18
31
44
5
6
19
32
45
6
7
20
33
46
7
8
21
34
47
8
9
22
35
48
9
10
23
36
49
10
11
24
37
50
11
12
25
38
51
12
13
26
39
52
20-73
0
19
13
12
50
1
40
28
33
38
2
27
14
15
52
3
25
16
42
39
4
36
21
43
48
5
46
30
23
51
6
10
8
45
9
7
34
11
3
5
8
35
31
29
37
9
41
17
32
49
10
18
24
4
22
11
2
7
47
6
12
44
1
26
20
(Simulacin: la tortuga y la liebre) En este problema, recrear la carrera clsica de la tortuga y la liebre. Se
valdr de la generacin de nmeros aleatorios para desarrollar la simulacin de este memorable evento.
Nuestros contendientes comienzan la carrera en el cuadro 1 de una serie de 70 cuadros. Cada cuadro representa
una posicin posible en la ruta de la carrera. La lnea de meta est en el cuadro 70. El primer contendiente que
llegue o pase el cuadro 70 obtiene como recompensa un cubo de zanahorias y lechuga fresca. La ruta sube
serpenteando por la ladera de una montaa resbalosa, por lo que ocasionalmente los contendientes pierden
terreno.
Hay un reloj que pulsa una vez por segundo. Con cada pulso del reloj, el programa deber ajustar la posicin de
los animales, de acuerdo con las siguientes reglas:
Animal
Tipo de movimiento
Movimiento real
3 cuadros a la derecha
6 cuadros a la izquierda
1 cuadro a la derecha
No se mueve
9 cuadros a la derecha
12 cuadros a la izquierda
1 cuadro a la derecha
2 cuadros a la izquierda
Utilice variables para llevar el registro de las posiciones de los animales (las posiciones son de la 1 a la 70)
Cada animal debe comenzar en la posicin 1 (es decir, la puerta de salida) Si un animal resbala hacia la
izquierda, quedando antes del cuadro 1, devulvalo al cuadro 1.
Genere los porcentajes de la tabla previa produciendo un entero aleatorio, i, que est en el rango 1 i 10.
Para la tortuga, efecte un paso veloz cuando 1 i 5, un resbaln cuando 6 i 7 y un paso lento
cuando 8 i 10. Utilice una tcnica similar para mover a la liebre.
Comience la carrera imprimiendo
BANG!
Y ARRANCAN!
Por cada pulso del reloj (es decir, cada repeticin del ciclo), imprima una lnea de 70 posiciones que
muestre la posicin de la tortuga mediante la letra T y la de la liebre mediante la letra L. Ocasionalmente
los contendientes caern en el mismo cuadro. En este caso, la tortuga morder a la liebre y el programa
deber imprimir OUCH! en tal posicin. Todas las posiciones de impresin que no sean T, L ni OUCH!
(en caso de empate), deben estar en blanco.
Despus de la impresin de cada lnea, pruebe si alguno de los animales ha llegado o pasado el cuadro 70.
De ser as, imprima el ganador y termine la simulacin. Si la tortuga gana, imprima LA TORTUGA
GANA! BRAVO! Si la liebre gana, imprima La liebre gana. Ni hablar. Si ambos animales llegan a la
meta con el mismo pulso de reloj, tal vez usted quiera favorecer a la tortuga (el desvalido) o imprimir Es un
empate. Si ninguno de los animales gana, vuelva a efectuar el ciclo, simulando el siguiente pulso del reloj.
APUNTADORES Y CADENA LECCIN 20
20-74
(Programacin en lenguaje de mquina) Crearemos una computadora a la que llamaremos Simpletron. Como
su nombre implica, es una mquina sencilla, pero como pronto veremos, tambin es poderosa. La Simpletron
ejecuta programas escritos en el nico lenguaje que entiende directamente; es decir, el lenguaje de mquina
Simpletron, o SML.
La Simpletron contiene un acumulador -es decir, un registro especial en el que se coloca la informacin antes
de que la Simpletron la tome para efectuar clculos o examinarla de varias maneras. Toda la informa de la
Simpletron se maneja en trminos de palabras. Una palabra es un nmero decimal de cuatro dgitos con
signo, como +3364, -1293, +0007, -0001, etc. La Simpletron viene equipada con una memoria de 100
palabras, las cuales se referencian por su nmero de localidad: 00, 01, ..., 99.
Antes de ejecutar un programa SML, debemos cargar el programa en memoria. La primera instruccin de cada
programa SML siempre queda en la localidad 00. El simulador comenzar la ejecucin a partir de localidad.
Cada instruccin en SML, ocupa una palabra de la memoria de la Simpletron (por lo tanto, las instrucciones
son nmeros decimales de cuatro dgitos con un signo) Supondremos que el signo de una instruccin SML
siempre es positivo, pero el signo de una palabra de datos puede ser positivo o negativo. Cada localidad de la
memoria de la Simpletron puede contener una instruccin, un valor de datos utilizado por el programa o un
rea no utilizada (y, por lo tanto, indefinida) de la memoria. Los primeros dos dgitos de cada instruccin SML
son el cdigo de operacin, que especifica que se llevar a cabo. Los cdigos de operacin de SML aparecen en
la figura 20.12.
Cdigo de operacin
Significado
Operaciones de entrada/salida:
const int READ = 10;
Operaciones de carga/almacenamiento:
const int LOAD = 20;
20-75
Cdigo de operacin
Significado
Nmero
+1007
+1008
+2007
+3008
+2109
+1109
+4300
+0000
+0000
+0000
Instruccin
(Lee A)
(Lee B)
(Carga A)
(Suma B)
(Almacena C)
(Escribe C)
(Terminacin)
(Variable A)
(Variable B)
(Resultado C)
El programa SML del ejemplo 2 lee del teclado dos nmeros y determina e imprime el valor ms alto. Note
que la instruccin +4107 se utiliza como transferencia de control condicional, a semejanza de la instruccin
if de C++.
Ejemplo 2
Localidad
00
01
02
03
04
05
06
07
08
09
10
Nmero
+1009
+1010
+2009
+3110
+4107
+1109
+4300
+1110
+4300
+0000
+0000
Instruccin
(Lee A)
(Lee B)
(Carga A)
(Resta B)
(Bifurca con negativo a 07)
(Escribe A)
(Terminacin)
(Escribe B)
(Terminacin)
(Variable A)
(Variable B)
20-76
Ahora escriba programas en SML que lleven a cabo las siguientes actividades.
a) Mediante un ciclo controlado por centinela lea 10 nmeros positivos y calcule e imprima su suma.
b) Mediante un ciclo controlado por contador, lea siete nmeros, algunos positivos y otros negativos, y
calcule e imprima su promedio.
c) Lea una serie de nmeros y determine e imprima el mayor. El primer nmero indicar la cantidad de
nmeros a procesar.
8.
(Simulador de computadora) Al principio parecer un tanto pretencioso, pero en este problema va a construir
su propia computadora. No, no se encargar de soldar sus componentes. En cambio, se valdr de la poderosa
tcnica de la simulacin basada en software para crear un modelo en software de la Simpletron. No s
decepcionar. Su simulador convertir en una Simpletron a la computadora en la que est trabajando y usted de
hecho podr ejecutar, probar y depurar los programas SML que escribi en el problema 18.
Cuando ejecute su simulador Simpletron, deber comenzar por imprimir:
*** Bienvenidos a Simpletron! ***
*** Por favor introduzca su programa una instruccin ***
*** (o dato) a la vez. Presentar ***
*** la localidad y un signo de interrogacin (?) . ***
*** Despus usted teclear la palabra para esa localidad. ***
*** Para detener la introduccin de su programa, ***
*** teclee el centinela -99999. ***
Simule la memoria de la Simpletron con el arreglo memoria de un solo ndice, que tiene 100 elementos.
Supongamos ahora que est ejecutndose el simulador y examinemos el dilogo a medida que ingresamos el
programa del ejemplo 2 del ejercicio 18:
00 ? +1009
01 ? +1010
02 ? +2009
03 ? +3110
04 ? +4107
05 ? +1109
06 ? +4300
07 ? +1110
08 ? +4300
09 ? +0000
10 ? +0000
11 ? -99999
12
*** Se ha completado la carga del programa ***
*** Inicia la ejecucin del programa
***
El programa SML ha sido colocado (o cargado) en el arreglo memoria. Ahora la Simpletron ejecuta su
programa SML. La ejecucin inicia con la instruccin de la localidad 00 y, como C++, contina
secuencialmente, a menos que se le dirija a otra parte del programa mediante una transferencia de control.
Mediante la variable acumulador represente el registro del acumulador. Emplee la variable contador para
llevar el registro de la localidad de memoria que contiene la instruccin en ejecucin. En la variable
codigoOperacion indique la operacin actual, es decir, los dos dgitos de la izquierda de la palabra de
instruccin. Mediante la variable operando indique la localidad de memoria sobre la que opera la
instruccin actual. As, operando est formado por los dos dgitos ms a la derecha de la instruccin que se
est ejecutando en el momento. No ejecute las instrucciones directamente en la memoria. En cambio,
transfiera la siguiente instruccin a ejecutar de la memoria a una variable llamada registroInstruccion.
Luego tome los dos dgitos de la izquierda, ponindolos en codigoOperacion, y tome los dos de la derecha
y colquelos en operando. Cuando comienza la operacin de la Simpletron, los registros especiales se
inicializan a 0.
20-77
Ahora hagamos el recorrido por la ejecucin de la primera instruccin SML, +1009. que est en la
localidad de memoria 00. A esto se le llama ciclo de ejecucin de instruccin.
contador nos dice la localidad de la siguiente instruccin a ejecutar. Obtenemos de la memoria el contenido
de dicha localidad mediante la instruccin de C++.
registroInstruccion = memoria[contador];
El cdigo de operacin y el operando se extraen del registro de instrucciones por medio de las
instrucciones:
codigoOperacion = registroInstruccion / 100;
operando = registroInstruccion %100;
Ahora la Simpletron deber determinar que el cdigo de operacin es en realidad una read, o lectura, (en
lugar de write, load, etc.) Una switch se encarga de diferenciar las doce operaciones de SML.
En la estructura switch se simula el comportamiento de varias instrucciones SML como sigue (dejaremos
las dems para que las resuelva el lector):
read:
load:
add:
branch:
halt:
y luego imprime el nombre y contenido de los registros, as como el contenido completo de la memoria. Tal
impresin con frecuencia es conocida como vaciado de computadora. Para ayudarle a programar su
funcin de vaciado, la figura 20.13 muestra un ejemplo de formato de vaciado. Observe que el vaciado tras
la ejecucin del programa Simpletron mostrara los valores reales de las instrucciones y de los datos al
momento de terminacin de la ejecucin.
Prosigamos con la ejecucin de la primera instruccin de nuestro programa: +1009 en la localidad 00.
Como hemos indicado, la instruccin switch simula esto ejecutando la instruccin C++:
cin >> memoria[ operando ];
Antes de la ejecucin de cin, se deber presentar un signo de interrogacin (?) en la pantalla, para pedirle al
usuario una entrada. La Simpletron espera a que el usuario introduzca un valor y oprima la tecla Retorno.
El valor queda en la localidad 09.
En este punto se ha completado la simulacin de la primera instruccin. Lo que queda es preparar a
Simpletron para que ejecute la siguiente instruccin. Dado que la instruccin que se acaba de ejecutar no
fue una transferencia de control, simplemente necesitamos incrementar el registro del contador de
instrucciones como sigue:
++contador;
Con esto se completa la ejecucin simulada de la primera instruccin. El proceso completo (es decir, el
ciclo de ejecucin de instruccin) inicia nuevamente con la obtencin de la siguiente instruccin a ejecutar.
Ahora consideremos la manera como se simulan las instrucciones de bifurcacin (las transferencias de
control) Todo lo que necesitamos hacer es ajustar el valor de contador de instrucciones. Por lo tanto, se
simula la instruccin de bifurcacin incondicional (40) dentro de switch con:
contador = operando;
La instruccin condicional bifurca si el acumulador es igual a cero se simula con:
APUNTADORES Y CADENA LECCIN 20
20-78
if ( acumulador == 0)
contador = operando;
En este punto, usted deber implementar el simulador Simpletron y ejecutar los programo SML que
escribi en el problema 18. Puede embellecer el SML con caractersticas adicionales e incluirlas en su
simulador.
El simulador deber buscar varios tipos de errores. Durante la fase de carga del programa, por ejemplo,
cada nmero tecleado por el usuario para memoria deber estar en el rango de -9999 a +9999. El simulador
deber comprobar mediante un ciclo while que cada nmero digitado est en este rango y, si no, solicitar al
usuario que lo vuelva a teclear hasta que est correcto.
REGISTROS
acumulador
contador
registroInstruccin
codigoOperacion
operando
+0000
00
+0000
00
00
MEMORIA
0
10
20
30
40
50
60
70
80
90
0
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
1
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
2
3
4
5
6
+0000 +0000 +0000 +0000 +0000
+0000 +0000 +0000 +0000 +0000
+0000 +0000 +0000 +0000 +0000
+0000 +0000 +0000 +0000 +0000
+0000 +0000 +0000 +0000 +0000
+0000 +0000 +0000 +0000 +0000
+0000 +0000 +0000 +0000 +0000
+0000 +0000 +0000 +0000 +0000
+0000 +0000 +0000 +0000 +0000
+0000 +0000 +0000 +0000 +0000
Figura 20.13. Ejemplo de vaciado
7
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
8
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
9
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
+0000
Durante la fase de ejecucin, el simulador deber buscar varios errores serios, como divisin entre cero,
cdigos de ejecucin invlidos, sobrecargas del acumulador (es decir, operaciones aritmticas que den
valores mayores que +9999 o menores que -9999) y otros. Tales errores serios se llaman errores fatales. Al
detectar un error fatal, el simulador deber imprimir un mensaje de error como:
*** Intento de dividir entre cero ***
*** Terminacin anormal de Simpletron ***
as como un vaciado completo con el formato que indicamos previamente. Con l se ayudar al usuario a
localizar el error en el programa.
MS PROBLEMAS DE APUNTADORES
9.
Modifique el programa de barajado y reparticin de naipes del programa BARAJAS.CPP, para que las
operaciones de barajado y reparticin se lleven a cabo mediante la misma funcin (barajarRepartir()) La
funcin deber contener una estructura de ciclo anidada semejante a la funcin barajar() del programa
BARAJAS.CPP.
20-79
int * numero;
cout << numero << endl;
float *realPtr;
long *enteroPtr;
enteroPtr = realPtr;
int *x, y;
x = y;
20-80
89
10
12
68
45
Comenzando por el elemento ms a la derecha del arreglo, compare cada elemento contra 37 hasta que
encuentre uno menor que 37, luego intercambie 37 y dicho elemento. El primer elemento menor que 37 es
12, por lo que 37 y 12 se intercambian. El nuevo arreglo queda as:
12
89
10
37
68
45
37
10
89
68
45
Comenzando por la derecha, pero iniciando con el elemento anterior a 89, compare los dems elementos
con 37 hasta encontrar uno menor que 37, luego intercambie 37 y dicho elemento. El primer elemento
menor que 37 es 10, por lo que 37 y 10 se intercambian. El nuevo arreglo queda como:
12
f)
10
37
89
68
45
Comenzando por la izquierda, pero iniciando con el elemento que sigue a 10, compare los elementos
contra 37 hasta encontrar uno mayor que 37, luego intercambie 37 y dicho elemento. No hay ms
elementos mayores que 37, as que, cuando comparamos 37 contra l mismo, sabemos que est en su
destino final en el arreglo ordenado.
Una vez aplicada la particin al arreglo anterior, quedan dos arreglos desordenados, El subarreglo con valores
menores que 37 contiene 12, 2, 6, 4, 10 y 8. El subarreglo con valores mayores que 37 contiene 89, 68 y 45. El
ordenamiento contina con el particionamiento de ambos arreglos de la misma manera que el arreglo original.
20-81
Basndose en el anlisis anterior, escriba la funcin recursiva quicksort() que ordena un arreglo de enteros con un
solo ndice. La funcin deber recibir como argumentos un arreglo de enteros, un ndice inicial y un ndice final.
quicksort() deber llamar a la funcin particin() para que lleve a cabo el paso de particionamiento.
14. (Recorrido por un laberinto) El siguiente tramado de # y puntos ( . ) es un arreglo de doble ndice que
representa un laberinto.
#
#
.
#
#
#
#
#
#
#
#
#
#
.
.
#
.
#
.
#
.
#
.
#
#
.
#
#
.
#
.
.
.
#
.
#
#
.
.
.
.
#
#
#
.
#
.
#
#
#
#
#
.
.
.
.
.
#
.
#
#
.
.
.
#
#
#
#
.
#
.
#
#
.
#
.
#
.
.
.
.
.
.
#
#
.
#
.
#
#
#
#
.
#
#
#
#
.
#
.
.
.
.
.
.
#
.
#
#
.
#
#
#
#
#
#
#
#
.
#
#
.
.
.
.
.
.
.
.
.
.
#
#
#
#
#
.
#
#
#
#
#
#
#
En este arreglo de doble ndice, los # representan las paredes del laberinto y los puntos los cuadros de las
rutas posibles a travs del laberinto. Slo se pueden hacer movimientos a una localidad del arreglo que
contenga un punto.
Hay un algoritmo sencillo de recorrido del laberinto que garantiza encontrar la salida (suponiendo que la
hay) Si no la hay, usted llegar nuevamente al punto de inicio. Ponga su mano derecha sobre la pared que
est a su derecha y avance. Nunca quite su mano de la pared. Si el laberinto da la vuelta a la derecha, siga
por la pared de la derecha. Siempre y cuando no quite su mano de la pared, tarde o temprano llegar a la
salida del laberinto. Podra haber una ruta ms corta que la que ha tomado, pero est garantizado que saldr
del laberinto si sigue este algoritmo.
Escriba la funcin recursiva travesia() que lo guiar por el laberinto. La funcin deber recibir como
argumentos un arreglo de caracteres de 12 por 12 que represente el laberinto, as como el punto de inicio de
dicho laberinto. A medida que travesia() intente localizar la salida del laberinto, deber poner una x en cada
cuadro de la ruta. La funcin deber desplegar el laberinto despus de cada movida, de modo que el usuario
pueda ver cmo se resuelve el problema.
15. (Generacin aleatoria de laberintos) Escriba la funcin generadorLaberinto(), que toma como argumento un
arreglo de caracteres de 12 por 12 y genera aleatoriamente un laberinto. Dicha funcin deber proporcionar el
punto de inicio y el de terminacin del laberinto. Pruebe la funcin travesa() del problema 25 sobre varios
laberintos generados al azar.
16. (Laberintos de cualquier tamao) Generalice las funciones travesia() y generadorLaberinto() de los
problemas 14 y 15 para que procesen laberintos de cualquier anchura y altura.
17. (Arreglos de apuntadores a funciones) Rescriba el programa FUNARRE3.CPP, (de la leccin 19, pgina 50)
para que opere mediante una interfaz operada por men. El programa deber ofrecer las siguientes 5 opciones al
usuario, como sigue (deben aparecer en la pantalla):
20-82
del mismo tipo. Por esta razn, las funciones del programa FUNARRE3.CPP se deben modificar para que
todas devuelvan el mismo tipo y tomen los mismos parmetros. Modifique las funciones minimo() y
mximo() de modo que impriman el valor mnimo o mximo y no devuelvan nada. En la opcin 3,
modifique la funcin promedio() del programa FUNARRE3.CPP para que enve a la salida el promedio de
cada estudiante (no de uno especfico) La funcin promedio() no deber devolver nada y deber tomar los
mismos parmetros que mostrarArreglo(), minimo() y mximo(). Almacene los apuntadores a las cuatro
funciones en el arreglo procesarOpcion() y tome la seleccin del usuario como el ndice del arreglo para
llamar a cada funcin.
18. (Modificaciones al simulador Simpletron) En el problema 7 se escribi un simulador en software de una
computadora que ejecuta programas escritos en el SML (lenguaje de mquina Simpletron) En este problema
proponemos vanas modificaciones y mejoras al simulador Simpletron. Algunas de las siguientes
modificaciones y mejoras podran ser necesarias para ejecutar los programas generados por el compilador.
a) Aumente la memoria del simulador Simpletron de modo que contenga 1000 localidades de memoria,
permitiendo el manejo de programas ms extensos.
b) Haga que el simulador pueda efectuar clculos de mdulo. Esto requiere una nueva instruccin en el
lenguaje de mquina Simpletron.
c) Permita que el simulador realice clculos de exponenciacin. Esto requiere una nueva instruccin en el
lenguaje de mquina Simpletron.
d) Modifique el simulador para que emplee valores hexadecimales, en lugar de valores enteros, para
representar instrucciones en lenguaje de mquina Simpletron.
e) Modifique el simulador de modo que permita enviar a la salida un salto de lnea. Esto requiere una nueva
instruccin en el lenguaje de mquina Simpletron.
f) Modifique el simulador para que procese valores de punto flotante, adems de valores enteros.
g) Modifique el simulador a fin de que maneje entrada de cadenas. Sugerencia: es posible dividir cada
palabra Simpletron en dos grupos, conteniendo cada una un entero de dos dgitos. Cada entero de dos
dgitos representa el equivalente decimal ASCII de un carcter. Agregue una instruccin en lenguaje de
mquina que acepte la entrada de una cadena y la almacene a partir de cierta localidad de memoria de la
Simpletron. La primera mitad de la palabra en dicha localidad ser la cuenta del nmero de caracteres de
la cadena (es decir, la longitud de la cadena) Cada media palabra subsiguiente contiene un carcter
ASCII, expresado como dos dgitos decimales. La instruccin en lenguaje de mquina convierte cada
carcter en su equivalente ASCII y lo asigna a media palabra.
h) Modifique el simulador para que maneje salida de cadenas almacenadas en el formato de la parte (g)
Sugerencia: agregue una instruccin de lenguaje de mquina que imprima una cadena a partir de cierta
localidad de memoria de la Simpletron. La primera mitad de la palabra de dicha localidad es la cuenta del
nmero de caracteres de la cadena (es decir, la longitud de la cadena) Cada media palabra subsiguiente
contiene un carcter ASCII expresado como dos dgitos decimales. La instruccin de lenguaje de mquina
comprueba la longitud e imprime la cadena, traduciendo cada nmero de dos dgitos a su carcter
equivalente.
19. Qu hace este programa?
//Programa19.cpp
#include <iostream.h>
20-83
{
for(; *s1 != \0 && *s2 != \0; s1++, s2++)
if(*s1 != *s2)
return 0;
return 1;
}//Fin de misterio3()
PROBLEMAS DE MANIPULACIN DE CADENAS
20. Escriba un programa que, mediante la funcin strcmp, compare dos cadenas introducidas por el usuario. El
programa deber indicar si la primera cadena es menor, igual o mayor que la segunda.
21. Escriba un programa que compare, mediante la funcin strncmp, dos cadenas introducidas por el usuario. El
programa deber aceptar como entrada el nmero de caracteres a comparar, adems de indicar si la primera
cadena es menor, igual o mayor que la segunda.
22. Escriba un programa que se valga de la generacin de nmeros aleatorios para crear oraciones. El programa
utilizar cuatro arreglos de apuntadores a char, llamados articulo, sustantivo, verbo y preposicion. Deber
crear una oracin seleccionando una palabra al azar de cada arreglo en el siguiente orden articulo, sustantivo,
verbo, preposicion, articulo y sustantivo. A medida que se selecciona cada palabra, se le concatenar con las
palabras previas en un arreglo lo bastante grande para guardar la oracin completa. Las palabras se separarn
por espacios. La impresin de la oracin generada comenzar con una letra mayscula y terminar con un
punto. El programa generar 20 oraciones.
Los arreglos se llenarn como sigue: el arreglo articulo deber contener los artculos e, un, y, algn
y, cualquier; el arreglo sustantivo deber contener los sustantivos nio, seor, perro, pueblo y
auto; el arreglo verbo deber contener los verbos manejo, salt, corri, camin y evit; el
arreglo preposicion deber contener las preposiciones a, de, sobre, bajo y en.
Una vez que el programa haya sido escrito y est operando, modifquelo para que genere una historia corta que
consista de varias oraciones. (Qu tal la posibilidad de un escritor de cuentos para la clase de literatura?)
23. (Quintillas) Una quintilla es una oracin en verso, a veces jocoso, de cinco lneas, en el que el primero y
segundo versos riman con el quinto y el tercero con el cuarto. Mediante tcnicas parecidas a las desarrolladas en
el problema 22, escriba un programa en C++ que produzca quintillas al azar. Refinar este programa para que
genere buenas quintillas es un problema complejo, pero el resultado vale el esfuerzo.
24. Escriba un programa que codifique frases en pig Latin. (En ingls, pig Latin es un tipo de lenguaje que se
utiliza con propsitos de juego.) Hay muchas variaciones en los mtodos con los que se forman frases en pig
Latin. Por simplicidad, utilice el siguiente algoritmo:
Para formar una frase en pin Latin, divida en palabras dicha frase mediante la funcin strtok. Para convertir
cada palabra a pig Latin, ponga la primera letra de la palabra al final de ella y agregue las letras ay. As, la
palabra salta se convierte en altasay, las se vuelve aslay y computadora queda corno
omputadoracay. Los espacios entre las palabras quedan igual. Suponga lo siguiente: la frase consiste en
palabras separadas por espacios, no hay signos de puntuacin y todas las palabras tienen dos o ms letras. La
funcin mostrarLatinPalabra() deber desplegar cada palabra. Sugerencia: cada vez que se encuentre un token
durante una llamada a strtok, pase el apuntador del token a la funcin mostrarLatinPalabra() e imprima la
palabra en pig Latin.
25. Escriba un programa que acepte como entrada una cadena con un nmero telefnico, en la forma (555)5555555. El programa deber utilizar la funcin strtok para obtener como token el cdigo de rea, los primeros tres
dgitos del nmero telefnico y los ltimos cuatro dgitos. Los siete dgitos del nmero telefnico deben
concatenarse para formar una sola cadena. El programa deber convertir la cadena con el cdigo de rea a int y
la cadena con el nmero telefnico a long. Se deben imprimir el cdigo de rea y el nmero telefnico.
26. Escriba un programa que acepte como entrada una lnea de texto, la divida en tokens por medio de la funcin
strtok y enve los tokens a la salida en orden inverso.
27. Utilice las funciones de comparacin de cadenas estudiadas y las tcnicas de ordenamiento de arreglos
desarrollados para escribir un programa que alfabetice una lista de cadenas. Ordene los nombres de 10 o 15
pueblos de su zona.
20-84
28. Escriba dos versiones de la funcin de copia de cadenas y de la funcin de concatenacin de cadenas de la
figura 20.9. La primera versin deber utilizar indizacin de arreglos, y la segunda apuntadores y aritmtica de
apuntadores.
29. Escriba dos versiones de cada funcin de comparacin de cadenas de la figura 20.9. La primera versin debe
emplear indizacin de arreglos, y la segunda apuntadores y aritmtica de apuntadores.
30. Escriba dos versiones de la funcin strlen de la figura 20.9. La primera versin debe valerse de indizacin de
arreglos, y la segunda de apuntadores y aritmtica de apuntadores.
SECCIN ESPECIAL: Manipulacin avanzado de cadenas
Los problemas anteriores estn ligados a las lecciones y se disearon para poner a prueba los conocimientos del
lector sobre los conceptos fundamentales de manipulacin de cadenas. Esta seccin incluye un conjunto de
problemas de manipulacin de cadenas intermedios y avanzados. El lector deber encontrar interesantes y amenos
estos problemas. La dificultad de los problemas vara considerablemente. Algunos requieren de una hora o dos para
su escritura e implementacin. Otros son tiles corno tareas de laboratorio que podran tardar dos o tres semanas de
estudio e implementacin. Varios son proyectos vastos que se extendern durante todo el curso.
31. (Anlisis de texto) La disponibilidad de computadoras con capacidad de manipulacin de cadenas ha dado
como resultado algunos enfoques bastante interesantes para el anlisis de las obras de los grandes autores. Se ha
puesto mucha atencin en si William Shakespeare en realidad existi. Algunos estudiosos creen que hay
bastante evidencia que indica que las obras maestras atribuidas a Shakespeare en realidad fueron escritas por
Christopher Marlowe u otros autores. Los investigadores se han valido de las computadoras para encontrar las
similitudes en los escritos de ambos autores. Este ejercicio examina tres mtodos de anlisis de texto mediante
computadoras.
a) Escriba un programa que lea del teclado varias lneas de texto e imprima una tabla que indique el nmero
de veces que sucede cada letra del abecedario en el texto. Por ejemplo, la frase:
Ser o no ser: sa es la cuestin
contiene dos a, ninguna b, una c, etctera.
b) Escriba un programa que lea varias lneas de texto e imprima una tabla que indique el nmero de palabras
de una letra, de dos letras, de tres letras, etc., que hay en el texto. Por ejemplo, la frase
Si es ms noble para la mente sufrir
Contiene
c)
Longitud de la palabra
Veces
1
2
3
4
5
6
7
0
3
1
1
2
1
0
Escriba un programa que lea varias lneas de texto e imprima una tabla que indique el nmero veces que
sucede cada palabra del texto. La primera versin del programa deber incluir las palabras de la tabla en el
mismo orden en que aparecen en el texto. Por ejemplo, las lneas:
Ser o no ser: sa es la cuestin
Si es ms noble para la mente sufrir
contienen la palabra ser dos veces, la palabra ms una vez, no una vez, etc. Despus deber
intentar una impresin ms interesante (y til) en la que las palabras aparezcan ordenadas alfabticamente.
32. (Procesamiento de texto) Una importante funcin de los sistemas de procesamiento de texto es la justificacin
tipogrfica, es decir, la alineacin de las palabras tanto con el margen izquierdo como con el derecho. Esto
APUNTADORES Y CADENA LECCIN 20
20-85
genera un documento de aspecto profesional que da la apariencia de haber sido formado tipogrficamente, en
lugar de escrito en una mquina de escribir. La justificacin tipogrfica puede lograrse en los sistemas de
cmputo insertando caracteres en blanco entre las palabras, de modo que la palabra ms a la derecha quede
alineada con el margen derecho.
Escriba un programa que lea varias lneas de texto y lo imprima en formato justificado. Suponga que texto se
debe imprimir en papel de 8 pulgadas de ancho y que se dejan mrgenes de una pulgada tanto al lado
izquierdo como al derecho. Suponga que la computadora imprime 10 caracteres por pulgada horizontal. Por lo
tanto, dicho programa deber imprimir 6 pulgadas de texto o 65 caracteres por lnea.
33. (Impresin de fechas con varios formatos) En la correspondencia comercial, las fechas por lo general se
imprimen en varios formatos. Dos de los ms comunes son:
21/07/55 y julio 21, 1955
Escriba un programa que lea una fecha con el primer formato y la imprima con el segundo.
34. (Proteccin de cheques) Con frecuencia las computadoras se utilizan para ejecutar sistemas de impresin de
cheques, como sucede con las aplicaciones de nmina y cuentas por pagar. Circulan por all muchas historias
extraas sobre cheques de nmina emitidos (accidentalmente) que amparan cifras de ms de un milln. Los
sistemas de cheques imprimen cifras extraas debido a errores humanos y/o a fallas de la mquina. Los
diseadores de sistemas integran controles en sus sistemas para evitar la emisin de tales cheques.
Otro problema serio es que alguien altere intencionalmente la cifra de un cheque para cobrarlo
fraudulentamente. Para evitar la alteracin de una cifra, la mayora de los sistemas de impresin de cheques
utiliza una tcnica llamada proteccin de cheques.
Los cheques diseados para impresin en una computadora contienen una cantidad fija de espacios en los que se
puede imprimir una cifra. Suponga que un cheque contiene ocho espacios en blanco, donde la computadora
debe imprimir el importe de un cheque de nmina. Si la cifra es grande, entonces se llenarn los ocho espacios.
Por ejemplo:
1,230.60
----------12345678
Por otra parte, si la cifra es menor que $100.00, entonces quedaran en blanco varios de los espacios. Por
ejemplo,
99.87
-----------12345678
contiene tres espacios en blanco. Si un cheque se imprime con espacios en blanco, es fcil de alterar. Para evitar
esto, muchos sistemas de impresin de cheques protegen la cifra insertando asteriscos iniciales como sigue:
***99.87
----------12345678
Escriba un programa que acepte una cifra y luego la imprima en formato de proteccin de cheques, con
asteriscos iniciales, de ser necesario. Suponga que se dispone de nueve espacios para imprimir la cifra.
35. (Escritura del importe de un cheque con palabras) Prosiguiendo el estudio del ejemplo previo, reiteramos la
importancia de disear sistemas de impresin de cheques que eviten la alteracin de sus importes. Un mtodo
de seguridad comn requiere que la cifra sea escrita tanto con nmeros como con palabras. Inclusive si alguien
es capaz de alterar la cifra numrica, es muy difcil modificar la cifra en palabras.
20-86
Muchos sistemas computarizados de impresin de cheques no imprimen la cifra del cheque con palabras. Tal
vez la razn principal de esta omisin es que la mayora de los lenguajes de alto nivel empleados para las
aplicaciones comerciales no cuentan con caractersticas adecuadas de manipulacin de cadenas. Otra razn es
que la lgica de la escritura de las cifras con palabras es un tanto complicada.
Escriba un programa en C++ que acepte una cifra numrica y la imprima con palabras. Por ejemplo, la cifra
112.43 deber escribirse como:
CIENTO DOCE con 43/100
36. (Cdigo Morse) Tal vez el esquema de codificacin ms famoso de todos es el cdigo Morse, desarrollador por
Samuel Morse en 1832 para el sistema telegrfico. El cdigo Morse asigna una serie de puntos y rayas a cada
letra del abecedario, a cada dgito y a algunos caracteres especiales (punto, coma, dos puntos y punto y coma)
En los sistemas audibles, el punto representa un sonido corto y la raya un sonido largo., Otras representaciones
de puntos y rayas son las empleadas en los sistemas de orientacin por luz y los de sealizacin con
indicadores.
La separacin entre palabras se indica mediante un espacio o, sencillamente, por la ausencia de un punto o raya.
En los sistemas sonoros, se indica un espacio mediante un periodo corto en el que no se transmite ningn
sonido. En la figura 20.14 aparece la versin internacional del cdigo Morse.
Escriba un programa que lea una frase en espaol y la codifique en cdigo Morse. Tambin escriba un
programa que lea una frase en cdigo Morse y la convierta en su equivalente en ingls. Ponga un espacio entre
cada letra codificada en Morse y tres espacios entre cada palabra.
Carcter
Cdigo
Carcter
Cdigo
A
.T
B
-...
U
..C
-.-.
V
...D
-..
W
.-E
.
X
-..F
..-.
Y
-.-G
--.
Z
--..
H
....
I
..
Dgitos
J
.--1
.---K
-.2
..--L
.-..
3
...-M
-4
....N
-.
5
.....
O
--6
-....
P
.--.
7
--...
Q
--.8
---..
R
.-.
9
----.
S
...
0
----Figura 20.14. Las letras del abecedario como se expresan con el cdigo Morse internacional
37. (Programa de conversin entre Sistema mtrico y sistema ingls) Escriba un programa que apoye al usuario
en las conversiones entre el sistema mtrico y el ingls. El programa deber permitirle al usuario especificar
como cadenas los nombres de las unidades (es decir, centmetros, litros, gramos, etc., en el sistema mtrico y
pulgadas, cuartillos, libras, etc., en el sistema ingls) y deber responder a preguntas sencillas como:
Cuntas pulgadas hay en 2 metros?
Cuntos litros hay en 10 cuartillos?
El programa deber reconocer las conversiones invlidas. Por ejemplo, la pregunta:
Cuntos pies hay en 5 kilogramos
APUNTADORES Y CADENA LECCIN 20
20-87
no tiene sentido, pues los pies, son unidades de longitud, mientras que los kilogramos, son unidades de peso.
INTERESANTE PROYECTO DE MANIPULACIN DE CADENAS
38. (Generador de crucigramas) Mucha gente ha resuelto crucigramas, pero pocos han intentado generar uno. La
generacin de crucigramas es difcil. Aqu se sugiere como un proyecto de manipulacin de cadenas de alta
complejidad y esfuerzo. Hay muchos asuntos que el programador debe resolver para lograr que funcione incluso
el programa generador de crucigramas ms sencillo. Por ejemplo, cmo se representa el tramado de un
crucigrama en la computadora? Deber utilizarse una serie de cadenas o arreglos de doble ndice? El
programador necesita una fuente de palabras (es decir, un diccionario computarizado) al que pueda hacer
referencia directa el programa. De qu forma deben almacenarse estas palabras para simplificar las
complejas manipulaciones requeridas por el programa? El lector realmente ambicioso desear generar la
parte de claves del crucigrama, donde se imprimen las pistas para determinar las palabras horizontales y
verticales. La simple impresin de una versin en blanco del crucigrama es un problema complejo.
20-88