Manual C++
Manual C++
Manual C++
Mayo 2018
ESTRUCTURA BÁSICA DE UN PROGRAMA
#include <iostream> }declaración de librerías
using namespace std; }declaración del espacio de
nombres
int main(void){
Todo programa en C++ comienza con una función main(), y sólo puede haber una.
En C++ el main() siempre regresa un entero, es por eso se antepone “int” a la
palabra “main”. Los paréntesis que le siguen contienen lo que se le va a mandar a la
función. En este caso se puso la palabra “void” que significa vacío, es decir que a la
función main no se le está mandando nada, podría omitirse el void dentro de los
paréntesis, el compilador asume que no se enviará nada. La llave que se abre
significa que se iniciará un bloque de instrucciones.
cout<<”hola mundo”<<endl;
Esta es una instrucción. La instrucción cout está definida dentro de la biblioteca
iostream.h, que previamente declaramos que íbamos a utilizar. Una función, en este
caso main() siempre comienza su ejecución con una instrucción (la que se encuentra
en la parte superior), y continúa así hasta que se llegue a la última instrucción (de la
parte inferior). Para terminar una instrucción siempre se coloca “;”. Pero además de
instrucciones se pueden invocar funciones definidas por el usuario (por supuesto
diferentes de main) como se verá mas adelante.
return 0;
Esta es otra instrucción, en este caso la instrucción return determina que es lo que se
devolverá de la función main(). Habíamos declarado que main devolvería un
entero, así que la instrucción return devuelve 0. Lo cual a su vez significa que no han
ocurrido errores durante su ejecución.
}
La llave de cierre de la función main() indica el termino del bloque de instrucciones.
#include <iostream.h>
using namespace std;
int main( ){
int variable;
variable=5;
cout<<variable;
return 0;
}
Notemos en esta ocasión sólo la parte: int variable; . A esta sección se le denomina
declaración. Se trata de la declaración de una variable de nombre “variable”.
Una variable es una posición de memoria con nombre que se usa para mantener un
valor que puede ser modificado por el programa3. Las variables son declaradas,
usadas y liberadas. Una declaración se encuentra ligada a un tipo, a un nombre y a
un valor.
18
Los corchetes significan que esa parte es opcional. Por ejemplo, la declaración:
int mi_variable=5;
declara una variable tipo entero de nombre “mi_variable” y le asigna el valor “5”.
Además de las restricciones anteriores, existe otra, y esta tiene que ver con las
palabras reservadas del lenguaje, que no son muchas a comparación de otros
lenguajes como Basic. Las palabras que se presentan en la siguiente lista, no
pueden ocuparse como nombres de variables, funciones, u otras instrucciones
definidas por el programador.
19
union unsigned using virtual
void volatile wchar_t while
xor xor_eq
Tabla 2 Palabras reservadas de C++
Las variables se pueden declarar en tres sitios básicos: dentro de las funciones (ya
sea la función main u otras creadas por el programador), estas variables son
llamadas locales; en la definición de parámetros de una función, como se verá más
adelante; y fuera de todas las funciones, variables globales.
Ejemplo:
#include <iostream.h>
int variable_global=10;
int main(){
int variable_local=20;
Una variable global puede ser modificada en cualquier parte del programa, mientras
que una variable local sólo puede ser modificada y utilizada dentro de la función en la
que se ha declarado. Por supuesto, antes de utilizar una variable y hacer
operaciones con ella, hay que declararla.
20
Por lo general, siempre se trata de utilizar lo menos posible la declaración de
variables globales. El siguiente ejemplo muestra que se pueden declarar variables en
cualquier parte del programa, siempre y cuando se declaren antes de usarlas.
#include <iostream.h>
int main( ){
int variable1=10;
int variable2=variable1+30;
#include <iostream.h>
int main( ){
const float pi=3.141592;
int radio=5;
float area;
area=pi*radio*radio;
cout<<"el area del circulo es:
"<<area<<endl; return 0;
}
21
Declaramos una constante del tipo de datos float , le damos el nombre “pi” y le
asignamos el valor 3.141592. Este valor jamás podrá ser modificado en ninguna
parte del programa
TIPOS DE DATOS
Los tipos de datos atómicos son los tipos de datos más sencillos a partir de los
cuales se pueden construir otros más complejos. La siguiente tabla ilustra estos tipos
con sus intervalos de valores posibles y el número de bytes que ocupan.
22
long 10
double
char 1 -128 a 127
unsigned 1 0 a 255
char
bool 1 Valor lógico o booleano que puede ser trae
(cierto) o false (falso).
Tabla 3 Tipos de datos en C++
definidas.
#include <limits.h>
#include <iostream.h>
int main( ){
cout<<"PROGRAMA QUE MUESTRA LOS VALORES MAXIMOS Y
"\ "MINIMOS \n DE ALGUNOS DE LOS TIPOS DE DATOS
"\ "ATOMICOS"<<endl;
cout<<"\n int maximo: "<<INT_MAX<<" int minimo: "\
<<INT_MIN<<endl;
cout<<"\n char maximo: "<<CHAR_MAX<<" char minimo: "\
<<CHAR_MIN<<" tamaño en bits: "<<CHAR_BIT<<endl;
cout<<"\n long maximo: "<<LONG_MAX<<" long minimo: "\
<<LONG_MIN<<endl;
cout<<"\n short maximo: "<<SHRT_MAX<<" short minimo: "\
<<SHRT_MIN<<endl;
return 0;
}
Por medio de los ejemplos dados hasta el momento nos podemos dar una idea de la
forma en que se asignan valores a los tipos de datos numéricos. Tan sólo falta
mostrar como se pueden asignar valores en formato octal y hexadecimal. Las
siguientes instrucciones lo aclararán.
int variable1=022;
int variable2=0x12;
23
Ambas variables están almacenando el número 18, la primera en octal y la otra en
hexadecimal. También se pueden asignar números exponenciales.
float variable3=2e-6;
Caracteres de Significado
control
\n salto de línea
\t tabulador horizontal
\v tabulador vertical
\a alerta sonora
\0 carácter nulo
\b mueve el cursor hacia
atrás
Tabla 4 Secuencias de escape
24
Cualquier carácter se puede representar con la “\” seguida del propio carácter o del
código octal o hexadecimal. Por ejemplo las comillas dobles será ‘\”’ o ‘\042’ o ‘\x22’.
OPERACIONES BÁSICAS
Operado Significado
r
+ adición
- sustracción
* multiplicación
/ división
% resto de la división
entera
Tabla 5 Operaciones básicas
#include <iostream.h>
int main( ){
int a=5, b=10, c=20, r;
r=a+b; a=c%r; //aquí “a” valdrá 5(resto de 20/15)
c=b-a; a=a*2;
cout<<"a="<<a<<" b="<<b<<" c="<<c<<"
r="<<r<<endl; cout<<"la suma de a y b es:
"<<a+b<<endl; return 0;
}
Estos operadores no son exclusivos de los tipos de datos numéricos. Un dato tipo
char también es modificable mediante operadores. Recuerde que lo que se guarda
es el código ASCII.
25
#include <iostream.h>
int main( ){
char car1='a', car2;
car2=car1+15;
cout<<"car2="<<car2<<endl;
car1=car2-10;
cout<<"car1="<<car1<<endl;
cout<<"la suma de los dos es:"<<car1+car2<<endl;
car1=car1-car2;
cout<<"car1="<<car1<<endl;
return 0;
}
a=a*2;
car1=car1-car2;
a*=2;
car1-=car2;
Ahora conozcamos a otros operadores muy útiles. “++” y “--“. Éstos tienen la función
de aumentar y disminuir en uno al dato que opera. Pero su comportamiento depende
de si sea en prefijo (antes del operando) o sufijo (después de).
#include <iostream.h>
int main( ){
int a,b,c;
a=17*5+2; //primero resuelve la multiplicación
26
cout<<"a="<<a<<endl;
b=a++ -7; //a-7=80, luego se incrementa a
cout<<"b="<<b<<endl;
c=++b * --a; //se incremente b a 81,
//luego disminuye a a 87, luego evalúa b*a
cout<<"c="<<c<<endl;
return 0;
}
También puede utilizar los paréntesis (como propiedad asociativa) para guiar al
programa hacia qué operaciones debe de hacer primero. Hasta aquí, podría
considerarse que se han visto las operaciones básicas (suma, resta, multiplicación y
división). Pero no son las únicas. Aunque los siguientes operadores no le parezcan
importantes o no los comprenda por completo, más adelante se dará cuenta de sus
usos.
Operadores de desplazamiento
Desplazar los bits de un número entero hacia la derecha equivale a dividirlo por 2.
Veamos por qué.
… … 256 128 64 32 16 8 4 2 1
1 0 0 0 0 0 0 0 1
27
… … 256 128 64 32 16 8 4 2 1
0 1 0 0 0 0 0 0 0
Desplaza un bit a la derecha y el campo vacío lo llena con un cero. Vea el siguiente
ejemplo de aplicación.
int var=16;
var >>= 1; //ahora var tiene asignado un 8
Son operadores binarios que permiten comparar los valores de dos variables o
expresiones.
Operado Significado
r
< menor que
<= menor o
igual
> mayor que
>= mayor o
igual
== igual
!= desigual
Tabla 7 operadores relacionales y de igualdad
28
Operadores de bits y lógicos
Operado Significado
r
& conjunción (Y) de
bits
^ O exclusivo de bits
| O inclusivo de bits
Tabla 8 Operadores de bits
Precedencia de operadores
Símbolo Significado
:: resolución de alcance
++ incremento sufijo
-- decremento sufijo
() llamada a función
[] elemento de tabla
-> acceso a miembro desde un puntero
. acceso a miembro
++ incremento prefijo
-- decremento prefijo
! negación lógica
~ complemento a uno
- cambio de signo (operador unario)
+ identidad (operador unario)
& dirección
* seguir un puntero
sizeof tamaño en bytes
new reserva de memoria
delete liberación de memoria
(tipo) conversión explícita de tipos
29
.* acceso a miembros de clase
->* acceso a miembros de clase desde
puntero
* multiplicación
/ división
% resto de la división entera
+ suma
- resta
<< desplazamiento de bits a la izquierda
>> desplazamiento de bits a la derecha
< menor que
<= menor o igual
> mayor que
>= mayor o igual
== igual
!= desigual
& conjunción (Y) de bits
^ O exclusivo de bits
| O inclusivo de bits
&& conjunción (Y) lógica
|| disyunción (O) lógica
= asignación simple
*=, /=, %=, +=, - =, asignaciones compuestas
<<=, >>=,&=, ^=, |
=
?: expresión condicional
trhow lanzamiento de excepción
, separador de expresiones
Tabla 10 Precedencia de operadores en C++
30
CAPITULO 3 ENTRADA Y SALIDA BÁSICA
ENTRADA Y SALIDA
cout<<”Mensaje a la pantalla”<<endl;
#include <iostream.h>
int main(){
cout<<"cadena de caracteres"<<endl;
cout<<2+2<<endl; //imprime un entero
cout<<9/2<<endl; //imprime un flotante
cout<<(int)(3.141592+2)<<endl; //imprime un entero
31
return 0;
}
La instrucción cout<< puede imprimir tanto números enteros como flotantes sin
necesidad de decirle específicamente el tipo de datos del que se trata, pero, por
supuesto notemos que al enviarle una cadena de caracteres esta debe de estar entre
comillas. Ya en ejemplos anteriores vimos como se mandaba a la pantalla el valor de
una variable, así que no hace falta más ilustración al respecto.
La principal función para leer desde el teclado es cin>>, pero es mejor ver un
ejemplo para tener la idea clara.
#include <iostream.h>
int main(){
int numero;
char car;
float otroNum;
cout<<"escribe un
numero:"<<endl; cin>>numero;
cout<<"\nel numero que tecleaste es:
"<<numero<<endl; cout<<"dame una letra"<<endl;
cin>>car;
cout<<"\ntecleaste: "<<car<<endl;
cout<<"escribe un numero
flotante"<<endl; cin>>otroNum;
cout<<"\neste es: "<<otroNum;
32
return 0;
}
MODIFICADORES DE FORMATO
En el primer ejemplo del presente capítulo quizá no entendió del todo lo qué hacía la
instrucción:
cout<<(int)(3.141592+2)<<endl;
33
A esto se le llama hacer un cast, y es muy común hacerlo cuando no queremos que
se pierdan determinadas propiedades en los resultados de las operaciones. Por
ejemplo, las siguientes líneas de código, que son equivalentes tienen por efecto
convertir el tipo de la variable de origen al de la variable destino:
int B; int B;
double A= (double) B; double A = double(B);
#include <iostream.h>
int main(){
int numero=25;
int leido;
cout<<"numero es en octal: "<<oct<<numero<<endl;
cout<<"en hexadecimal: "<<hex<<numero<<endl;
cout<<"en decimal: "<<dec<<numero<<endl;
cout<<"ahora teclea un numero"<<endl;
cin>>hex>>leido;
cout<<"el leido vale: "<<hex<<leido<<endl;
cout<<"y en decimal: "<<dec<<leido<<endl;
cout<<"y en octal:
"<<oct<<leido<<endl; return 0;
}
34
En cuanto a la precisión, al imprimir en pantalla un número de tipo flotante, no
importa cuantas cifras significativas tenga (mientras esté dentro de los límites de
almacenamiento de flotantes), sólo aparecerán 6 números después del punto, y la
ultima cifra será redondeada en caso de pasar los 6 dígitos. Es decir, que si
queremos mandar a la pantalla el número 1.23456789, en su lugar aparecerá
1.234568.
Cuando se quieren resultados más exactos, nos es muy útil la librería iomanip.h
que contiene el manipulador setprecision() con el que podemos determinar la
precisión con la que queremos que aparezcan esos datos en la pantalla. Existe
también la función miembro pecision(), que puede resultar un poco más cómoda
en algunos casos porque el efecto de precisión funciona para todas las instrucciones
cout que le sigan. A ambas se le pasa como parámetro el número de cifras
significativas deseadas. Veamos un ejemplo.
#include <iostream.h>
#include <iomanip.h>
int main(){
cout<<1.23456789<<endl;
cout.precision(4);
cout<<1.23456789<<endl;
cout<<setprecision(5)<<1.23456789<<endl;
cout.precision(7);
cout<<1.23456789<<endl;
cout<<setprecision(9)<<1.23456789<<endl
; return 0;
}
En ocasiones es útil dar una presentación a nuestros datos en la pantalla, tan sólo el
dejar unos cuantos espacios de margen en la pantalla puede ser un poco tedioso
para quienes no están enterados de las siguientes funciones:
35
setw que se encarga de hacer aparecer el texto alineado determinados espacios a
la derecha, si el numero de espacios solicitados para su alineación es menor que el
numero de caracteres que se imprimirán, no tendrá un efecto.
#include <iostream.h>
#include <iomanip.h>
int main(){
cout<<setw(5)<<setfill('%')<<"hola"<<endl;
cout<<setw(5)<<89;
cout<<setw(8)<<"centavo"<<endl;
return 0;
}
cout.setf(ios::right, ios::adjustfield);
cout.setf(ios::right, ios::adjustield);
36
OTRAS FUNCIONES MUY ÚTILES
La función de lectura desde el teclado cin no es la única que existe. Hay otros
métodos de lectura desde el teclado para la lectura de caracteres, la siguiente tabla
resumirá sus principales características.
37
primer
argumento un
número
determinado de
caracteres
write ******** ******** Muestra, de la
cadena enviada
como primer
argumento,
determinado
numero de
caracteres
(segundo
argumento)
ignore Ignora un Ignora el * * * * * * * * ********
carácter del numero de
flujo (opción caracteres
predeterminada enviados como
) argumento
gcount Devuelve el * * * * * * * * ******** ********
número de
caracteres
leídos en la
ultima lectura
sin formato
Tabla 11 Funciones de lectura sin formato
#include <iostream.h>
int main(){
char caracter,nombre[20], apellido[20];
char seg_apellido[20];
38
cin.get(nombre,20,' ');
cin.get();
cin.get(apellido,20,' ');
cin.get();
cin.get(seg_apellido,20);
cout<<caracter<<"Tu letra inicial es:"<<caracter<<endl;
cout<<"tu nombre es: "<<caracter<<nombre<<endl;
cout<<"tu apellido paterno es: "<<apellido<<endl;
cout<<"tu apellido materno es: "<<seg_apellido<<endl;
cout<<"Escribe el nombre de tu empresa: "<<endl;
cin.ignore();
cin.getline(nombre,20);
cout<<"el nombre de tu empresa: "<<nombre<<" tiene "
<<cin.gcount()<<" caracteres"<<endl;
cin.get(); //espera que oprimas enter para terminar
return 0;
}
Puede que esta no sea la mejor manera para hacer un programa de este tipo, pero
para nuestro objetivo creo que esta bien. Analicemos.
Pide al usuario que teclee su nombre completo, para luego leer inmediatamente el
primer carácter que teclea y lo almacena en la variable “caracter”. Sigue leyendo y
almacena lo que escribe en la variable “nombre” hasta que encuentre un espacio o
llegue a 20 caracteres. Luego, otra instrucción get se encarga de leer y desechar el
carácter espacio, para nuevamente leer hasta encontrar otro espacio.
Deja de leer hasta que se presione enter, hayas escrito o no tus dos apellidos. Así
que cuando oprimes enter, “carecer” tiene tu letra inicial y la presenta en pantalla,
para aparecer tu nombre imprime “caracter” seguido de “nombre”, porque a ésta
39
última no almacenó el primer carácter. Las siguientes instrucciones son parecidas
hasta que pide el nombre de tu empresa.
La función ignore descarta del flujo el carácter de terminación, para luego permitir a
getline() leer el nombre de tu empresa con un máximo de 20 caracteres o hasta
que oprimas enter (pero no lo guarda). Se escribe el nombre y con gcount()
presenta los caracteres leídos. Finalmente espera que oprimas enter para terminar el
programa.
40
CAPITULO 4 ESTRUCTURAS DE CONTROL
Estas son las opciones que él se plantea, aunque algunos pensarán en otras más.
Puede estudiar, trabajar o repetir todos los pasos anteriores.
41
if
Escribamos el código:
#include <iostream.h>
int main(){
char examen[2],semestre[2];
cout<<"Contesta si o no a las preguntas"<<endl;
cout<<"Pasaste el examen?"<<endl;
cin.get(examen,2);
cin.ignore(20,'\n');
cout<<"Pasaste el semestre?"<<endl;
cin.get(semestre,2);
cin.ignore(20,'\n'); //ignora el enter
if((examen[0]=='s')&&(semestre[0]=='s')){
cout<<"estas en la universidad"<<endl;
}
cout<<"fin del programa"<<endl;
cin.get(); //espera a que oprimas enter
return 0;
}
42
La condición a cumplir es: (examen[0]= =’s’)&&(semestre[0]= =’s’), en realidad se
trata de dos condiciones que se deben de cumplir: que la variable examen tenga el
carácter ‘s’ y que la variable semestre tenga el carácter ‘s’ (vease la tabla 7
operadores relacionales y de igualdad). Si la primera condición se cumple, entonces
comprueba la segunda condición (gracias a la conjunción lógica &&).
if((examen[0]=='s')&&(semestre[0]=='s')){
cout<<"estas en la universidad"<<endl;
}
else{
cout<<"no estas en la universidad"<<endl;
}
Igualmente el bloque de instrucciones a ejecutar se estructura dentro de llaves,
aunque tampoco es necesario cuando se trata de una sola instrucción.
43
En ocasiones necesitaremos construir bloques de instrucciones if y else más
complejos, es decir anidamientos. El ejemplo del estudiante también nos ayudará a
visualizar este concepto.
De esta manera controlamos las posibles respuestas que pudiese dar. En caso de
que pase el examen y el semestre estará en la universidad, si pasa el semestre pero
no pasa el examen estará trabajando, y en cualquier otro caso, cursará el semestre.
44
#include <iostream.h>
int main(){
char examen[2],semestre[2];
cout<<"Contesta si o no a las preguntas"<<endl;
cout<<"Pasaste el examen?"<<endl;
cin.get(examen,2);
cin.ignore(20,'\n');
cout<<"Pasaste el semestre?"<<endl;
cin.get(semestre,2);
cin.ignore(20,'\n'); //ignora el enter
if((examen[0]=='s')&&(semestre[0]=='s'))
cout<<"estas en la universidad"<<endl;
else
if((examen[0]=='n')&&(semestre[0]=='s'))
cout<<"estaras trabajando"<<endl;
else
cout<<"cursa el sexto semestre"<<endl;
cout<<"fin del programa"<<endl;
cin.get(); //espera a que oprimas enter
return 0;
}
?:
Este se trata de un operador del tipo condicional al estilo if/else. Se utiliza para
condicionales cortos (de una sola línea).
Por ejemplo:
45
#include <iostream.h>
int main(){
int calificacion;
cout<<"Cual fue tu calificacion del semestre?"<<endl;
cin>>calificacion;
cout<<(calificacion>=6 ? "pasaste" : "reprobaste");
cin.ignore();
cin.get();
return 0;
}
switch …
Muchas veces nos metemos en aprietos cuando necesitamos tener el control sobre
muchas opciones que pudiese tomar el usuario, porque resulta muy complicado
pensar en varios if/else anidados, para esos casos tenemos otra herramienta muy
cómoda, la estructura de selección múltiple switch.
46
.
.
caso por default;
}
#include <iostream.h>
int main(){
int opcion;
cout<<"Menu de opciones"<<endl;
cout<<"1.- Opcion 1"<<endl;
cout<<"2.- Opcion 2"<<endl;
cout<<"3.- Opcion 3"<<endl;
cout<<"elige una opcion"<<endl;
cin>>opcion;
switch(opcion){
case 1:
cout<<"ejecucion 1"<<endl;
break;
case 2:
cout<<"ejecucion 2"<<endl;
break;
case 3:
cout<<"ejecucion 3"<<endl;
break;
default:
cout<<"es una opcion no
valida"<<endl; break;
}
cout<<"presiona enter para salir"<<endl;
cin.ignore();
cin.get();
return 0;
}
Notemos que “opcion” es una variable de tipo entero, asi que case 1 , se refiere a
que la variable “opcion” tiene un valor de 1. Si se tratase de una variable de tipo
carácter, entonces debería de escribirse case ‘1’.
47
Encontramos una nueva instrucción, break. Esta se encarga de alterar el flujo de
control. Cuando se encuentra un break, inmediatamente se salta el resto de la
estructura. No es exclusiva de la estructura switch, también se puede colocar en
bloques if, for, while o do while (que se verán a continuación). Sin embargo
es mejor no depender demasiado del break.
while
48
calcular el promedio
mostrar el promedio
#include <iostream.h>
int main(){
int calificacion, suma=0, iteracion=1;
float promedio;
while(iteracion<=10){
cout<<"teclea tu calificacion "<<iteracion<<endl;
cin>>calificacion;
suma+=calificacion;
++iteracion;
}
promedio=(float)suma/(iteracion-1);
cout<<"el promedio de calificaciones es: "
<<promedio<<endl;
cin.ignore();
cin.get();
return 0;
}
El programa es sencillo, quizá una parte que pudiese causar dudas es el cálculo del
promedio. Lo que sucede es que se realiza un cast para convertir temporalmente la
variable suma de int a float, así se hará la división y se tendrá un resultado
decimal cuando sea necesario.
Hasta aquí nuestro programa va bien, pero puede mejorar, podemos tener un mejor
control del programa y hacer que el usuario decida cuantas calificaciones va a
introducir. Podemos hacer que el usuario simplemente teclee un “-1” cuando acabe
de escribir sus calificaciones, así, en lugar de comparar el número de iteraciones,
comprobará si la calificación es igual a “-1” para salirse.
Aquí el programa:
49
#include <iostream.h>
int main(){
int calificacion=0, suma=0, iteracion=0;
float promedio=0;
while(calificacion!=-1){
++iteracion;
suma+=calificacion;
cout<<"teclea tu califiaccion "<<iteracion<<endl;
cin>>calificacion;
}
promedio=(float)suma/(iteracion-1);
cout<<"el promedio de calificaciones es: "
<<promedio<<endl;
cin.ignore();
cin.get();
return 0;
}
50
Otra comprobación da como resultado un falso (por que se escribió -1) y por lo tanto
no entra al ciclo, entonces calcula el promedio, donde notemos que a “iteracion” se le
resta uno para tener el verdadero número de calificaciones introducidas. Por último
presenta el resultado.
Hay otras formas de hacer este programa, por ejemplo cuando no esta inicializada la
variable de calificaciones o iteraciones, y necesitamos que ese ciclo se ejecute por lo
menos una vez. En este caso podemos usar algo muy parecido, se trata de la
sentencia do while.
do while
Cuando necesitamos que un ciclo se ejecute por lo menos una vez, es necesaria
esta sentencia.
do{
Acciones a ejecutar;
}
while(condicion a cumplir);
El programa de ejemplo:
51
#include <iostream.h>
int main(){
int opcion;
do{
cout<<"elije una opcion de la
lista"<<endl; cout<<"1.-opcion 1"<<endl;
cout<<"2.-opcion 2"<<endl;
cout<<"3.-opcion 3"<<endl; cin>>opcion;
}while((opcion<1)||(opcion>3));
cout<<"esta opcion si fue valida"<<endl;
cin.ignore();
cin.get();
return 0;
}
Nunca debemos olvidar el punto y coma después del while. Usada en combinación
con el bloque switch, podemos tener muy buenos resultados y encontrar varias
aplicaciones de ellos.
for
52
Si se trata de una sola instrucción a ejecutar no es necesario ponerla entre llaves,
incluso podría ponerse dentro del paréntesis el for, separado por una coma.
for(asignación inicial ; condicion ; instrucción1)
unica instrucción;
x= Vi sin t
1
y = Vi sin t 2g t2
53
Calcular coordenada y
Imprimir las coordenadas
}
Termina el programa.
No parece tan complicado ¿verdad? Pues en realidad no lo es tanto. El programa
terminado aquí está.
#include <iostream.h>
#include <math.h>
int main (){
int t;
float x=0,y=0,ang,vi, grav=9.81;
cout<<"cual es el angulo de lanzamiento?"<<endl;
cin>>ang;
cout<<"cual es la velocidad inicial?"<<endl;
cin>>vi;
ang=((ang*3.141592)/180);
for(t=0;t<=10;t++){
x=(vi*cos(ang)*t);
y=(vi*sin(ang)*t)-(0.5*grav*t*t);
cout<<"t= "<<t<<" x= "<<x<<" y= "<<y<<endl;
}
cout<<"fin del programa"<<endl;
cin.ignore();
cin.get();
return (0);
}
54
coordenadas, las imprime en pantalla. Y finalmente ejecuta la última instrucción del
for aumentar una unidad a t (t++).
55
CAPÍTULO 5 FUNCIONES
PROTOTIPOS
56
Cuando se declara una función debe de especificarse el tipo de dato que va a
devolver, el nombre de la función, y los parámetros. La siguiente declaración:
int suma(int a, int b);
Especifica una función que devuelve un tipo de dato entero, tiene por nombre suma,
y al invocarla, recibe 2 parámetros de tipo entero.
Por ejemplo:
#include <iostream.h>
int suma(int x, int y);
int main(){
int dato1,dato2;
cout<<"calculare la suma de 2 numeros"<<endl;
cout<<"escribe el dato 1 y luego el dos"<<endl;
cin>>dato1;
cin>>dato2;
cout<<"la suma es: "<<suma(dato1,dato2)<<endl;
cin.ignore();
cin.get();
return 0;
}
int suma(int a, int b){
return a+b;
}
La función main también tiene un prototipo, y por lo tanto también puede recibir
datos.
57
int main ( int argc, char *argv[], char *envp[] )
El parámetro argv es una tabla de cadenas de caracteres (se verá más adelante),
cada cadena de caracteres contiene un argumento pasado en la linea de comandos,
la primera cadena contiene el nombre con el que fue invocado y las siguientes son
los demás argumentos.
El parámetro envp es una tabla de cadenas, que pasa información sobre una
variable de entorno del sistema operativo.
PASO DE ARGUMENTOS
Notemos que el prototipo de la función tiene los nombres de los parámetros distintos
a los de la definición, esto no afectará el comportamiento del programa, pero se vería
mejor si fueran iguales. Lo que no puede cambiar es el tipo de datos que va a recibir.
58
VALORES DE RETORNO
Una función puede regresar cualquier tipo de valor excepto tablas u otras funciones.
Esta limitación podría resolverse utilizando estructuras o punteros, pero se verá más
adelante.
MACROS
Una macro es una parte del código que puede parecer y actuar como una función, se
define después de las librerías mediante un #define.
Sin embargo, no hay que abusar de ellas, porque podrían entorpecer el código y
hacer lento el programa.
#include <iostream.h>
#define mayor(a,b) (a>b)? a: b
int main(){
int a,b;
cout<<"teclea 2 numeros distintos"<<endl;
cin>>a;
cin>>b;
cout<<"el mayor de esos numeros es: "
<<(mayor(a,b))<<endl;
cin.ignore();
cin.get();
return 0;
}
59
Debemos tener cuidado si vamos a usar macros, las macros, al compilar el
programa, se sustituyen directamente en donde se invocan, es decir, que en este
ejemplo, es como si se introdujera directamente los condicionales dentro del cout.
Así, debemos tener cuidado en introducir bloques grandes de código en una macro
(algo nada recomendable), sobre todo, cuidado con los puntos y comas.
Podemos ver que las macros al igual que las funciones pueden tener parámetros, sin
embargo, tienen que escribirse con cuidado.
curva(1+3)
se sustituye por
1+2*1+3+1+3*1+3
60
En el lenguaje C, se acostumbra usar macros para definir constantes (porque a
diferencia de C++, ahí no existe el tipo const. Por ejemplo:
#define PI 3.141592
RECURSIVIDAD
Una función recursiva se programa simplemente para resolver los casos más
sencillos, cuando se llama a una función con un caso más complicado, se divide el
problema en dos partes, la parte que se resuelve inmediatamente y la que necesita
de más pasos, ésta última se manda de nuevo a la función, que a su ves la divide de
nuevo, y así sucesivamente hasta que se llegue al caso base. Cuando se llega al
final de la serie de llamadas, va recorriendo el camino de regreso, hasta que por fin,
presenta el resultado.
61
#include <iostream.h>
long factorial(long numero); //prototipo
int main(){
long numero;
cout<<"número para calcular el factorial:"<<endl;
cin>>numero;
cout<<"el factorial es: "<<factorial(numero)<<endl;
cin.ignore();
cin.get();
return 0;
}
long factorial(long numero){
if(numero<=1)
return 1;
else
return numero*factorial(numero-1);
}
62
CAPÍTULO 6 ARRAYS Y CADENAS
Valor
Localidad en memoria
almacenado
Arreglo[0] 1550 FFFB
Arreglo[1] 130 FFFC
Arreglo[2] 45 FFFD
Arreglo[3] 90 FFFE
Arreglo[4] 76 FFFF
DECLARACIÓN
63
int MiArreglo [12] ;
char nombre[20] ;
ASIGNACIÓN DE VALORES
Así, estos valores estarán almacenados en cada elemento del array. Es muy
importante hacer notar que el primer elemento de un arreglo es el elemento 0,
entonces, MiArreglo[0] contendrá el número 2, el segundo ( MiArreglo[1] ) contendrá
el número 34 y así sucesivamente hasta MiArreglo[4] que es el último elemento del
array. Si un arreglo cuenta con menos inicalizadores que elementos entonces el
resto se inicializará a 0.
64
char MiArray[5]={'h','o','l','a','\0'};
Para acceder a cada elemento del arreglo debemos especificar su posición (la
primera es la posición 0). En tiempo de ejecución podemos asignar valores a cada
elemento cuidando siempre de no sobrepasar el tamaño del arreglo, si
sobrepasamos ese tamaño se escribirán datos en un área de la memoria que no está
asignada para ese array, puede escribir datos en un área en donde se almacenaba
otra variable del programa o un componente del sistema, esto ocasionaría resultados
no deseados.
#include <iostream.h>
#include <iomanip.h> //para presentacion con formato
#include <stdlib.h>
#include <time.h>
int main(){
const int tam_max=20;
int aleatorios[tam_max];
int i,suma=0;
float promedio;
srand((unsigned)time(NULL));
for(i=0;i<tam_max;i++){
aleatorios[i]=rand()%128; //asigna el numero
cout<<"aleatorio generado: " //presenta el numero
<<setw(5)<<aleatorios[i]<<endl;
}
for(i=0;i<tam_max;)
suma+=aleatorios[i++]; //suma los elementos
promedio=(float)suma/tam_max;
cout<<endl<<"el promedio es: "<<promedio<<endl;
cin.get();
return 0;
}
65
El programa anterior muestra el uso de los arreglos. Ya anteriormente habíamos
hecho un ejercicio que calculaba el promedio de una serie de números introducidos
por el usuario, en este caso el programa guarda los números generados por la
máquina en un arreglo para luego calcular el promedio.
Para asignar cada valor aleatorio generado, se utiliza un ciclo for con un contador “i”
que va de 0 hasta el tamaño máximo que pudiera tener el array. El tamaño del array
fue declarado como una constante al principio de la función principal, esto ayudará
en caso de que se quiera aumentar el tamaño del arreglo, así no tendremos que
modificar cada parte de nuestro código en la que se refiera al tamaño, bastará con
cambiar el valor de la constante.
Dentro del ciclo se genera un número aleatorio con la función rand(), usamos el
operador para obtener el resto de la división entera, así nos dará un número menor
de 128. Previamente se utilizó la función srand() para establecer una semilla para
generar los números aleatorios, esa semilla la tomamos llamando al reloj del sistema
con la función time(). Al mismo tiempo imprimimos el número que fue generado.
66
de cadena, cosa que no es posible con cin>> directamente y además de que puede
escribir en sectores de memoria no adecuados.
#include <iostream.h>
int main(){
const int tam_cad=20; char
cadena[tam_cad];
cin.getline(cadena,tam_cad,'\n');
for(int i=0;(i<tam_cad)&&(cadena[i]!='\0');i++)
cadena[i]+=5;
cout<<cadena<<endl;
cin.get();
return 0;
}
¿Qué hace este programa?, sencillamente podemos decir que almacena una cadena
introducida por el usuario, para luego modificar cada carácter por medio de un ciclo
hasta que encuentre el carácter de terminación (\0) o llegue al limite de caracteres.
Quizá no parezca muy interesante este ejemplo, pero hay que recordar que con
cosas pequeñas se construyen grandes cosas, adornemos un poco nuestro
programa, supongamos que la cadena que introduce el usuario es un mensaje que
debe ser secreto, en lugar de sumar 5 a cada carácter podemos sumarle el número
que quiera el usuario, ¿por qué no una clave?.
#include <iostream.h>
int main(){
const int tam_cad=20;
char cadena[tam_cad];
int clave;
67
cout<<"introduce el texto a cifrar"<<endl;
cin.getline(cadena,tam_cad,'\n');
cout<<"ahora dame tu clave (no mas de 3
digitos)"<<endl; cin>>clave;
for(int i=0;(i<tam_cad)&&(cadena[i]!='\0');i++)
cadena[i]+=clave;
cout<<"el texto cifrado es: "<<endl;
cout<<cadena<<endl;
cin.ignore();
cin.get();
return 0;
}
Como ejercicio sugiero que haga un programa que realice la acción contraria, de un
texto cifrado saque el mensaje oculto, y ¿por qué no? intente descifrar un mensaje
sin la clave.
PASO DE ARGUMENTOS
Así como en ejemplos anteriores pasamos una variable a una función, también se
puede pasar como argumento un arreglo. Para pasarlo es necesario hacer una
llamada como la siguiente:
MiFuncion (arreglo);
68
tipoRetorno MiFuncion (tipoArreglo nombre [ ] );
Cuando pasamos como argumento a una función una variable de tipo int, float,
char, etc., estamos pasando el valor de esta variable a otra variable (podría decirse
una copia) que se define en la función, esta forma de pasar argumentos se denomina
“por valor”. Cualquier modificación de valor a esta variable no tendrá efecto en la
variable “original” que pasó su valor a la función. Esta última variable, al ser local,
será destruida cuando termine de ejecutarse la función que la contiene.
En el caso del paso de arreglos, este no se hace por valor, sino que se hace un paso
por referencia simulado. Cuando se declara un arreglo, el nombre de éste es una
variable que apunta al primer elemento del arreglo, es decir que contiene su
dirección en memoria.
FFF0
NombreArreglo
Elemento 0 Elemento 1
FFFA FFFB
Cuando pasamos esta dirección a una función, cualquier modificación que se haga
dentro de esa función de nuestro arreglo tendrá efectos en la variable original.
69
#include <iostream.h>
void modifica(int arreglo[], int
tamano); int main(){
const int tam_arr=5;
int MiArreglo[tam_arr]={5,10,15,20,25};
int i;
modifica(MiArreglo, tam_arr);
for(i=0;i<tam_arr;++i){
cout<<"elemento "<<i<<"es "
<<MiArreglo[i]<<endl;
}
cout<<"presiona enter para terminar"<<endl;
cin.get();
return 0;
}
void modifica(int arreglo[], int tam_arr){
for(int i=0;i<tam_arr;++i)
arreglo[i]*=2;
}
También se puede pasar a una función el valor de un elemento del array, sólo se
pasará el valor del elemento, no se puede modificar el elemento original.
En ocasiones puede resultar poco conveniente que alguna de las funciones que
reciben un arreglo tenga derecho a modificarlo, a veces puede que cambie sus
valores sin que nosotros nos percatemos inmediatamente. Para eso podemos incluir
el calificador const dentro del prototipo y definición de la función, de esta manera no
podrá modificarse nada de este arreglo.
70
tipoRetorno nombreFuncion (const tipoArreglo nombre [ ] );
ARREGLOS MULTIDIMENSIONALES
Como sabemos, se pueden crear arreglos de cualquier tipo de datos, ahora veremos
que también se pueden crear arreglos de arreglos. La forma de declararlos es con
múltiples subíndices, cuantos se quieran tener, nosotros trabajaremos a lo más con
dobles subíndices.
Arreglo
Arreglo[0] Arreglo[0][0] Arreglo[0][1] Arreglo[0][2]
Arreglo[1] Arreglo[1][0] Arreglo[1][1] Arreglo[1][2]
Arreglo[2] Arreglo[2][0] Arreglo[2][1] Arreglo[2][2]
Arreglo[3] Arreglo[3][0] Arreglo[3][1] Arreglo[3][2]
El nombre del arreglo tiene la dirección del primer elemento (Arreglo[0]), y éste a su
vez tiene la dirección del otro arreglo (Arreglo[0][0]), así para cada elemento de
arreglo( 0, 1, 2, 3).
71
Al mandar un arreglo de dos dimensiones, debemos de especificar en el prototipo y
definición de la función el subíndice2 de nuestro array. El siguiente ejemplo mostrará
varios aspectos de ellos.
#include <iostream.h>
#include <iomanip.h>
#include <stdlib.h>
#include <time.h>
int main(){
int ventas[vendedores][meses];
int i;
inicializa(ventas);
calculaTotal(ventas);
cout<<endl<<endl<<"presiona enter para terminar"<<endl;
cin.get();
return 0;
}
void inicializa(int ventas[][meses]){
int i,j; //contadores
srand((unsigned)time(NULL));
for(i=0;i<vendedores;++i){
cout<<"ventas del vendedor "<<i+1<<":
"; for(j=0;j<meses;++j){
ventas[i][j]=rand()%50;
cout<<setw(7)<<ventas[i][j];
}
72
cout<<endl;
}
}
void calculaTotal(const int ventas[][meses]){
int suma=0,total=0,i,j;
cout<<endl<<endl;
for(i=0;i<vendedores;++i){
suma=0;
for(j=0;j<meses;++j){
suma+=ventas[i][j];
}
cout<<"el vendedor "<<i+1<<" vendio "
<<suma<<" productos"<<endl;
total+=suma;
}
cout<<endl<<endl<<"en total se vendieron: "
<<total<<" productos en "<<meses<<" meses"<<endl;
}
La función “inicializa” llena el arreglo con valores aleatorios menores a 50, se utilizan
dos contadores para dos ciclos for, “i” para el primer subíndice, “j” para el segundo.
El ciclo recorre la primera “fila” (viendo el arreglo como una tabla de valores) usando
el contador i y a cada celda, con ayuda de “j”, asigna valores, así cuando “j” llega al
límite de celdas (meses) se aumenta una unidad el contador “i” para continuar con la
otra fila y recorrerla de nuevo.
La función “calculaTotal” tiene una forma muy similar, pero en ésta no se modificarán
valores, sino que se hará la suma de los elementos de cada fila para presentarlos en
pantalla. Una variable “total” se encarga de ir sumando los productos vendidos cada
73
que se cambia de fila en la tabla, para después, al término de los ciclos presentar el
total de artículos vendidos en esos meses.
74
CAPÍTULO 7 APUNTADORES
OPERADORES REFERENCIA-DESREFERENCIA
Un apuntador se define como una variable que contiene una dirección de memoria.
Para declarar un apuntador se hace uso del operador desreferencia o indirección (*),
no se debe confundir con la multiplicación.
tipo *nombre;
int *MiApuntador;
int arreglo[10];
int *apuntador;
apuntador = arreglo;
sucede que, pasamos la dirección del primer elemento del arreglo a la variable
“apuntador” que está determinada para almacenar una dirección de memoria.
75
0F40 0FF0 0FF1 … Direcciones
arreglo [0] [1] … Nombre o elemento
0FF0 548 9765 … Valor que contiene
0FA1 Dirección
apuntador Nombre
0FF0 Valor que contiene
Las variables también tienen una dirección en memoria, y para saber cual es
debemos utilizar el operador referencia o dirección (&).
int MiVariable=20;
int *MiApuntador;
MiApuntador = &MiVariable;
El uso de los apuntadores sirve para hacer uso de una variable con la cual no se
tiene contacto directo, por medio del operador desreferencia. Por ejemplo, podemos
asignar un nuevo valor a esta variable referenciada.
*MiApuntador=9;
76
#include<iostream.h>
int main(){
int variable=10;
int *apuntador;
cout<<"la variable contiene un "<<variable<<endl;
apuntador=&variable;
cout<<"variable esta en la direccion "
<<apuntador<<endl;
*apuntador=15;
cout<<"la variable ahora tiene un
"<<variable<<endl; cout<<"ahora tecle un
numero"<<endl; cin>>*apuntador;
cout<<"y ahora contiene un "<<*apuntador<<endl;
cin.ignore();
cin.get();
return 0;
}
Como podemos ver podemos usar un apuntador para asignar cantidades (o lo que
sea) a la variable referenciada ya sea por instrucción o por medio del teclado.
ARITMÉTICA DE OPERADORES
77
tendrán el mismo resultado que si no se colocaran los operadores * y &.
MiArreglo [ 7 ];
*(MiArreglo + 7);
Aunque no es nada recomendable utilizar este método para tratar los arreglos, nos
da la idea de que se pueden hacer operaciones de suma y resta sobre los
apuntadores. Si hacemos una instrucción como:
apuntador += 6;
*puntero = una_variable+6;
se está haciendo una asignación a “lo que apunta ‘puntero’”. Se modificará el valor
de la variable referenciada por “puntero”. Igual pasa con asignaciones de otro tipo:
*puntero *=3;
78
que en este caso se hace una multiplicación de la variable referenciada por 3 y luego
se vuelve a asignar.
Habíamos dejado pendiente un momento este tema, porque era mejor ver primero el
concepto de apuntadores, ahora que ya sabemos en que consiste, podemos declarar
e inicializar una cadena de caracteres de la siguiente forma:
Alumnos
79
La declaración del arreglo “Alumnos” sería de la siguiente forma:
Notemos que de esta forma no es necesario colocar el carácter ‘\0’ al final de cada
cadena, el compilador la coloca por sí sólo. También se pueden utilizar las otras
formas, que ya conocemos, de inicializar un arreglo de dos dimensiones y se puede
especificar el tamaño de las cadenas.
char MasAlumnos[4][10];
Y para acceder a cada carácter del arreglo declarado de cualquier forma, se utilizan
los subíndices, por ejemplo, asignaremos con la siguiente instrucción un carácter
contenido en el arreglo a otra variable de tipo char:
80
#include<conio.h>
#include<stdlib.h>
#include<iostream.h>
#include<time.h>
int main(){
int cont=0,i=0,num_aleat=0;
char car;
char *cadena[6]={"cinco","siete","texto","poema","radio",\
"raton"};
while(car!=27){
srand((unsigned)time(NULL));
num_aleat=rand()%6;
cout<<endl<<endl<<cadena[num_aleat]<<endl;
for(cont=0,i=0;(cont<100000)&&(cadena[num_aleat][i]!='\0');++cont)
{ if(kbhit()){
car=getch();
if(car==cadena[num_aleat][i]){
cout<<car;
++i;
}
fflush(stdin);
}
}
}
cout<<endl<<"juego terminado"<<endl;
cin.get();
return 0;
}
81
Después se usa un ciclo for, en el cual se inicializa la variable que contará el tiempo
(cont) y la variable de desplazamiento por los elementos de la tabla (i). Este ciclo se
detendrá cuando el contador de tiempo llegue a 100000 o cuando se llegue al
carácter ‘\0’ en la cadena.
Dentro de ese ciclo for se encuentra la parte más interesante del programa, usamos
una función (kbhit) que se encarga de detectar si se ha oprimido una tecla, esta
tecla no aparecerá en la pantalla pero sí se quedará dentro del flujo, si detecta que
se ha oprimido entonces, usando la función getch(), leerá y guardará en la variable
car aquel carácter que se quedó dentro del flujo, pero sin presentarlo en pantalla, si
el carácter leído corresponde con el carácter de la posición referida por “i”, entonces
si se presentará en pantalla y se continuará con el siguiente carácter (++i). Saliendo
del condicional se limpia el flujo de entrada (función fflush() definida en
stdlib.h) para evitar que se quede algún residuo o basura.
82
El paso por referencia consiste en pasar la dirección en memoria que ocupa esa
variable para que la función que la recibe pueda hacer uso de ella, sin necesidad de
hacer una copia como ocurre con el paso por valor.
nombre_funcion (arreglo[numero_cadena]);
83
#include<iostream.h>
void aMayusculas(char *cadena);
void cambiaNum(int *numero);
int main(){
char palabra[10];
int numero;
cout<<"teclea una cadena "<<endl;
cin.getline(palabra,10);
aMayusculas(palabra);
cout<<endl<<palabra<<endl;
cout<<"ahora teclea un numero"<<endl;
cin>>numero;
cambiaNum(&numero);
cout<<"este numero se cambio a: "<<numero;
cin.ignore();
cin.get();
return 0;
}
void aMayusculas(char *cadena){
for(int i=0;cadena[i]!='\0';++i)
cadena[i]+=('A'-'a');
}
void cambiaNum(int *numero){
*numero *= *numero;
}
Gracias a las referencias de C++ es posible hacer una función cambiaNum() con
una sintaxis más sencilla y de una manera más amigable, utilizando el '&'.
84
de esta manera surtirá el mismo efecto que la que habiamos definido, cuando se
invoque sólo se hará:
cambiaNum(numero);
85
CAPÍTULO 8 ESTRUCTURAS
Para los objetivos de este trabajo excluiremos el tipo class (clase), pero a lo largo del
capítulo mencionaremos en varias ocasiones este concepto para tener una idea de lo
que se trata.
ENUMERACIONES
En ocasiones habremos de declarar constantes enteras una tras otra con valores
consecutivos, por ejemplo:
para evitar este tipo de declaraciones una tras otra, existe el tipo enumerativo. La
declaración anterior se puede hacer de una mejor forma:
enum {a,b,c,d};
86
Una enumeración puede ser global o local. Además de que puede tener un nombre
que los identifique, podemos indicar desde donde empieza la numeración.
Después de hacer esta enumeración, se puede hacer una nueva a partir del nombre.
meses calendario;
#include<iostream.h>
enum colores{rojo,amarillo,verde};
int main(){
int i=0,contador=0; //unos contadores
colores semaforo;
cout<<"este programa mostrara el tipo enumerativo,"
<<" por medio de un semaforo de crucero"
<<" simulado"<<endl;
while(contador<3){
semaforo=verde;
cout<<"semaforo en verde, el peaton no pasa"<<endl;
cout<<"el peaton pide el paso con un boton"
<<"(presione enter)"<<endl;
cin.get();
semaforo=amarillo;
cout<<"semaforo en amarillo,
precaucion"<<endl; for(i=0;i<500000000;i++);
semaforo=rojo;
cout<<"semaforo en rojo, ALTO, pasa el
peaton"<<endl; for(i=0;i<500000000;i++);
87
contador++;
}
return 0;
}
UNIONES
El tipo de datos union puede contener datos de tipos y tamaños diferentes, esta
variable almacenará cualquier tipo de dato en una única localidad en memoria. Por
ejemplo:
union edificio{
int habitaciones;
int despachos;
char empresa[10];
};
declara un nuevo tipo de dato llamado “edificio”, para usar una variable de tipo
edificio bastará con hacer una declaración como:
edificio casa;
la variable casa tendrá el suficiente espacio en memoria para almacenar una cadena
(el tipo de dato de mayor longitud dentro de la union). Es responsabilidad del
programador extraer adecuadamente el tipo de dato deseado.
88
La forma en que está estructurada en la memoria nuestra variable es como la que
sigue:
Byte1 Byte2 Byte3 Byte4 Byte5 Byte6 Byte7 Byte8 Byte9 Byte10 Espacio para las
variables “habitaciones” y “despachos”
#include<iostream.h>
#include<iomanip.h>
union edificio{
int habitaciones;
int despachos;
char empresa[10];
};
int main(){
edificio casa, agencia, gobierno;
cout<<"cuantas habitaciones tiene tu
casa?"<<endl; cin>>casa.habitaciones;
cout<<"escribe el nombre de la agencia en la\
que trabajas"<<endl;
cin.ignore();
cin.getline(agencia.empresa,10);
cout<<"cuantos despachos tiene la oficina de gobierno \
de tu localidad?"<<endl;
cin>>gobierno.despachos;
cout<<"cuantos despachos tiene el edificio de la agencia
" <<agencia.empresa<<"?"<<endl;
89
cin>>agencia.despachos;
cout<<"edificio"<<setw(25)<<"habitaciones/despachos"
<<endl;
cout<<"casa"<<setw(18)<<casa.habitaciones<<endl;
cout<<"agencia"<<setw(15)<<agencia.despachos<<endl;
cout<<"gobierno"<<setw(14)<<gobierno.despachos<<endl;
cin.ignore();
cin.get();
return 0;
}
Para accesar a los miembros de una variable de tipo union es necesario utilizar el
operador punto (.), seguido de la variable a extraer. En este ejemplo hemos extraído
un entero de la variable “casa” por medio de casa.habitaciones, si se hace una
extracción como casa.empresa no sabemos exactamente que es lo que aparecerá
porque pueden existir otros datos en esa área de la memoria asignada a esta
cadena; y si se hiciese lo contrario, asignar una cadena y luego extraer un entero,
seguramente no obtendremos lo que deseamos. Como con cualquier otro tipo de
datos, podemos realizar operaciones con el contenido de los miembros de la union,
operaciones básicas, envío como argumentos, conversiones, etc.
El uso de las variables de tipo union no es muy común, alguien seguramente habrá
querido extraer un tipo entero, luego asignar una cadena y posteriormente utilizar de
nuevo ese entero. Que útil seria que dentro de una sola variable podamos tener
oportunidad de extraer tanto un tipo como otro sin perder los datos, ¿se imagina
poder regresar mediante la instrucción return más de un dato?.
90
ESTRUCTURAS
Las estructuras son colecciones de elementos, los cuales pueden ser de diferente
tipo, y a diferencia de las uniones, en éstas no se comparte la misma área de
memoria para los elementos.
struct nombre_estructura{
tipo nombre_elemento1;
tipo nombre_elemento2;
};
nombre_estructura nueva_variable;
Para acceder a cada uno de sus elementos usamos el operador punto (.), seguido
del nombre del nombre del elemento, de la misma forma que con las uniones.
Una estructura puede ser declarada de forma global o local, pero es más común
hacerlo fuera de toda función.
91
#include<iostream.h>
#include<math.h>
struct proyectil{
float VelocidadInicial, angulo;
float PosX, PosY;
};
float calculaCaida(proyectil
cosa); int main(){
proyectil misil;
misil.PosX=misil.PosY=0;
float distancia;
cout<<"Este programa calculará la distancia, en linea\
recta,en la que caerá un proyectil"<<endl;
cout<<"escribe la velocidad inicial para lanzarlo:
"; cin>>misil.VelocidadInicial;
cout<<"escribe ahora el angulo de lanzamiento: ";
cin>>misil.angulo;
distancia=calculaCaida(misil);
cout<<"la distancia a la que caerá el proyectil es:
" <<distancia<<" metros aproximadamente"<<endl;
cin.ignore();
cin.get();
}
float calculaCaida(proyectil cosa){
int t=1; //tiempo
const float grav=9.81; //gravedad
cosa.angulo/=57.2957; //transformamos a radianes
do{
cosa.PosX=(cosa.VelocidadInicial*cos(cosa.angulo)*t);
cosa.PosY=(cosa.VelocidadInicial*sin(cosa.angulo)*t)\
-(0.5*grav*t*t);
++t;
}while(cosa.PosY>0);
return(cosa.PosX);
}
Aunque las estructuras son una buena manera de mandar bloques de datos a una
función, y es posible regresar estructuras (por la instrucción return), el coste es
92
alto, el programa se hace lento, gasta CPU y memoria. Para ello, y gracias a que se
trata como un nuevo tipo de variable, es posible hacer una paso por referencia, así
evitaríamos que se hiciese una copia de toda la estructura, y sólo se pasara la
dirección.
La forma de hacer un paso por referencia es igual que con cualquier otro tipo de
variables, sin embargo, al accesar a sus miembros debemos de hacerlo por medio
del operador flecha (->). Usando nuestro ejemplo anterior, simplemente cambiarían
unas lineas:
.
.
cosa->angulo/=57.2957; //transformamos a radianes
do{
cosa->PosX=(cosa->VelocidadInicial*cos(cosa->angulo)*t);
cosa->PosY=(cosa->VelocidadInicial*sin(cosa->angulo)*t)\
-(0.5*grav*t*t);
++t;
}while(cosa->PosY>0);
return(cosa->PosX);
.
.
Y gracias a las nuevas referencias de C++ que describimos en el capítulo anterior,
podemos simplemente incluir un carácter más en nuestro código para utilizarlo como
referencia, en nuestra función (y la declaración por supuesto) incluimos un '&':
93
Las estructuras también pueden tener por miembros a funciones, en cuyo caso se
invoca de la misma forma en la que se accesa a una variable. Le sugiero animarse a
usarlas, intente hacer unos ejercicios con ellas. Sin embargo, para esos casos es
mejor y más útil utilizar otro tipo de datos definido en C++, se trata de las clases
(class), para los fines de este trabajo las clases quedan fuera, debido a que se
requiere describir y practicar bastante con la programación orientada a objetos. El
lector debe de tener en cuenta su existencia, para que en un futuro, si se está
interesado, se adentre más en el mundo de la programación, en una de mejor nivel,
con mejores técnicas, y por ende con más capacidades.
94
int main(){
alumno alan;
alan.inicia(alan);
cout<<"alan creado"<<endl;
alan.boleta=2005630170;
alan.semestre=5;
alan.constancia(alan);
return 0;
}
95
CAPÍTULO 9 ENTRADA Y SALIDA POR ARCHIVOS
La entrada y salida por archivos es uno de los temas más importantes para la
programación, es necesario para poder programar desde una pequeña agenda hasta
una completa base de datos, pero antes de entrar de lleno a este tema, y
aprovechando los conocimientos adquiridos hasta el momento, quiero mostrar el uso
de la memoria dinámica.
MEMORIA DINÁMICA
Una de las formas en que podemos asegurarnos que una variable declarada dentro
de un bloque no sea borrada al término de éste, es mediante la utilización del
calificador static. De ésta manera, la variable perdurará hasta el término de todo el
programa.
96
Pero en algunos casos esto nos será insuficiente, vamos a necesitar “destruir” el
variables antes de terminar programa, para hacer esto contamos con los
operadores new y delete.
Se puede utilizar el operador new para crear cualquier tipo de variables, en todos los
casos devuelve un puntero a la variable creada. En el momento en que se quiera
borrar esta variable deberemos utilizar el operador delete, todas las variables
creadas mediante el operador new deben de ser borradas con el otro operador.
En el siguiente ejemplo utilizaremos estos dos operadores para mostrar sus ventajas.
#include<iostream.h>
int main(){
char *cadena2;
int fincontador=10;
cout<<"programa de prueba"<<endl;
for(int i=0;i<fincontador;++i){
cout<<"contador funcionando "<<i<<endl;
}
int respuesta;
cout<<"crear variable?, 1 para
si"; cin>>respuesta;
char cadena[3]="hi";
if(respuesta==1){
int LongCad;
cout<<"variable creada"<<endl;
cout<<"longitud de cadena: ";
cin>>LongCad;
cadena2=new char[LongCad];
cout<<"escribe: "<<endl;
cin.ignore();
cin.getline(cadena2,LongCad);
cout<<"cadena escrita: "<<cadena2<<endl;
}else{
char cadena[10]="rayos, no";
}
cout<<cadena<<endl;
97
cout<<cadena2<<endl;
delete cadena2;
cin.ignore();
cin.get();
return 0;
}
Las partes que nos interesan de este programa son la declaración de la variable tipo
apuntador que se encuentra al principio del main, la asignación de espacio dentro
del bloque if, y por último la destrucción de nuestra variable lineas antes del término
del programa.
El uso de la memoria dinámica nos será muy útil en muchos casos, en otros quizá
prefiramos hacerlo de la manera más común. Estos operadores funcionan tanto para
variables simples como para compuestas (definidas por el programador). De nueva
cuenta debo mencionar a las clases, porque en éstas se maneja mucho este
concepto, y de nuevo invito al lector a que, terminando esta lectura, se adentre más
en el mundo de la programación consultando otra bibliografía.
Si se anima a trabajar con clases lo felicito, antes quisiera darle una idea manejando
estructuras con funciones. El siguiente programa es una modificación del último que
vimos en el capítulo anterior, la diferencia está en el manejo de los operadores
descritos hace unos párrafos, y por ende en el manejo de apuntadores a estructuras.
#include<iostream.h>
#include<iomanip.h>
const int NumMaterias=11;
struct alumno {
int boleta, semestre;
int calificaciones[NumMaterias];
void constancia(alumno * este){
98
cout<<"constancia impresa"<<endl;
cout<<"alumno con boleta: "<<este->boleta;
cout<<setw(50)<<"del semestre numero: "
<<este->semestre<<endl;
cout<<"\nCALIFICACIONES DEL SEMESTRE: "<<endl;
for(int i=0;i<NumMaterias;++i){
cout<<"asignatura "<<i+1<<" : "
<<este->calificaciones[i]<<endl;
}
}
void inicia(alumno * este){
for(int i=0;i<NumMaterias;++i)
este->calificaciones[i]=0;
este->boleta=0;
este->semestre=0;
}
};
int main(){
alumno *alan =new alumno;
alan->inicia(alan);
cout<<"alan creado"<<endl;
alan->boleta=2005630170;
alan->semestre=5;
alan->constancia(alan);
delete alan;
alumno *alfonse=new alumno;
alfonse->inicia(alfonse);
alfonse->constancia(alfonse);
delete alfonse;
alan->constancia(alan);
cin.get();
return 0;
}
99
Note que después de la destrucción de la variable “alan” se crea otra de nombre
“alfonse” que también se destruye, y posteriormente se invoca de nuevo a la función
“constancia” de “alan”, dependiendo del compilador utilizado puede haber distintos
resultados, pero es lógico que no se obtendrá lo que deseamos porque esa variable
ya no existe.
ARCHIVOS
Para poder usar un flujo estándar basta con incluir la biblioteca iostream.h como lo
hemos hecho hasta ahora. Cuando decidimos utilizar la función cin.get() no
sabíamos exactamente el porque de la utilización del punto(.), ahora que hemos visto
un poco el concepto de estructura podemos decir que se trata de la invocación a una
función miembro del flujo cin. Sí, el flujo es un objeto, viéndolo desde la perspectiva
de las estructuras y no precisamente de las clases como debería de ser, se trata de
un tipo de dato que contiene variables y funciones que pueden ser invocadas.
Las estructuras (en realidad clases) para la entrada y salida de datos tienen un orden
jerárquico, en ellas existe la herencia que básicamente consiste en que una de orden
100
inferior obtiene las mismas variables y funciones que la de orden mayor, además de
que puede agregar más.
ios
istream ostream
iostream
Para poder trabajar los ficheros como flujos es necesario incluir la librería
fstream.h, y según la utilización que queramos dar a este fichero (lectura o
escritura) deberemos declarar el tipo de flujo.
Para crear un archivo de salida declaramos una variable de tipo ofstream, el cual
ya está declarado dentro de nuestra librería. Es mejor ver un ejemplo de base.
#include<fstream.h>
int main(){
ofstream archivo;
archivo.open("miarchivo.txt");
archivo<<"hola desde este archivo\n";
archivo<<"ya he escrito algo\n";
archivo.close();
}
101
ofstream archivo(“miarchivo.txt”);
#include<iostream.h>
#include<fstream.h>
int main(){
ofstream archivo("miarchivo.txt", ios::app);
archivo<<"hola desde este archivo de
nuevo\n"; archivo<<"ya he escrito algo de
nuevo\n"; archivo.close();
}
El método para abrir un archivo en modo lectura es muy similar, pero en este caso
utilizaremos ifstream. Para tener el control del fichero, aparte de conocer los
modos de apertura de un archivo, debemos de conocer el delimitador, así como en
las cadenas existe el carácter de fin de cadena('\0'), en los archivos está el fin de
archivo (EOF).
102
#include<iostream.h>
#include<fstream.h>
int main(){
char caracter;
ifstream archivo("miarchivo.txt",
ios::in); while(!archivo.eof()){
archivo.get(caracter);
cout<<caracter;
}
archivo.close();
}
#include<iostream.h>
#include<fstream.h>
int main(){
char caracter;
ifstream archivo("miarchivo2.txt", ios::in);
if(archivo){
while(!archivo.eof()){
archivo.get(caracter);
cout<<caracter;
}
archivo.close();
}else{
cerr<<"el archivo no existe"<<endl;;
return 1;
103
}
return 0;
}
Además de éstas, existen otras funciones que nos serán muy útiles para que no sea
tan secuencial la forma en la que leemos o escribimos el archivo.
Hasta aquí el tema de manejo de archivos creo que nos ha dado las suficientes
herramientas para desarrollar cosas mejores.
¡¡Ohh, la computadora tiene un espíritu dentro!!!, quizá somos muchas las personas
que hemos visto a alguien decir eso, en el bachillerato llegué a ver varias personas
un poco asustadas por ello. Para practicar un poco más, y utilizar algunas funciones
vistas hasta ahora le muestro el siguiente programa.
104
#include<iostream.h>
#include<fstream.h>
#include<string.h>
int main(){
char texto_preg[300],texto_resp[300],*compara=NULL;
ifstream archivo("arch.txt", ios::in); if(!archivo){
cerr<<"error al abrir el
archivo"; return 1;
}
cout<<"* hola"<<endl;
cout<<"> ";
cin.getline(texto_resp,290);
while(texto_resp[0]!='\0'){
archivo.seekg(0);
do{
archivo.getline(texto_preg,290);
compara=strstr(texto_resp,texto_preg);
if(archivo.eof()){
cout<<"* no se contestar, dimelo por favor"<<endl;
cin.getline(texto_preg,290);
archivo.close();
ofstream archivoS("arch.txt",ios::app);
archivoS<<texto_resp<<endl;
archivoS<<texto_preg<<endl;
archivoS.close();
archivo.open("arch.txt", ios::in);
}
}while(compara==NULL);
cout<<"> ";
archivo.getline(texto_preg,290);
cout<<"* "<<texto_preg<<endl;
cout<<"> ";
cin.getline(texto_resp,290);
}
archivo.close();
return 0;
}
105
hola
como estas?
bien
que haces?
nada
pues ponte a hacer algo, a que te dedicas?
estudio
y que estudias?
informatica
ha que bueno!!, de donde eres?
ixtapaluca
que interesante, hay algo que quieras preguntarme?
como te llamas?
acaso eso importa?
como te llamas
pregunta de nuevo
Se posiciona al inicio del archivo, y, dentro de otro bucle, lee la cadena de caracteres
del archivo con un máximo de 290 caracteres y la almacena en “texto_preg”.
Utilizando la función strstr() de la biblioteca string.h, compara la cadena
introducida por el usuario con la cadena que acaba de leer del archivo, la función
strstr() devuelve un apuntador a la primera localización de la cadena
“texto_preg” en “texto_resp”, si no se encuentra devuelve NULL.
106
Estos pasos de buscar y, si no encuentra entonces preguntar, continuarán mientras
no se encuentren coincidencias entre lo escrito y lo que está dentro del archivo.
Después, continuando con el bucle de mayor nivel, vuelve a leer del archivo una
cadena de caracteres, y empieza la conversación de nuevo. Para terminar el
programa simplemente el usuario debe teclear enter sin ningún otro caracter.
107
APÉNDICE
Seguramente en el compilador que ha estado utilizando, sea Visual C++, Dev C++ o
cualquier otro que no sea muy viejo, es decir anterior al año de 1998, le ha estado
marcando algunos “Warnings” a la hora de compilar su código fuente, trate de
corregirlos. Uno de ellos que quizá no sepa a que se refiere es:
Este warning está presente en el compilador GCC, y aparece debido a los archivos
de cabecera que hemos empleado hasta este momento.
En el estándar de C++ las bibliotecas dejan de utilizar el “.h”, es decir que en lugar de
utilizar <iostream.h>, ahora tendrá que escribirse <iostream>, en vez de
<iomanip.h> será <iomanip>.
A pesar que esto tiene varias ventajas, que tal vez no vea en este momento, se
tendría que colocar “std” antes de cada llamada a una función de la biblioteca, debido
a que toda la biblioteca estándar de C++ está definida en el espacio de nombres
llamado std. Con esto, tendríamos que hacer una llamada a escribir en pantalla con
la instrucción std::cout.
Para evitar esto, y por consiguiente hacer menos extenso el código a escribir,
podemos emplear la directriz using, indicando al compilador el espacio de nombres
donde está referenciado.
108
Por ejemplo, el siguiente programa es la nueva versión de uno de nuestros primeros
programas escritos.
#include <iostream>
using namespace std;
int main(){
cout<< “adios a todos” <<endl;
return 0;
}
Para tener una idea de las capacidades aportadas por la biblioteca estándar,
presentamos la siguiente tabla en donde se clasifican las librerías deacuerdo a su
funcionalidad.
ENTRADA/SALIDA
109
<cwctype> Clasificación de caracteres extendidos
<string> Clases para manipular cadenas de caracteres
CONTENEDORES
<bitset> Matriz de bits
<deque> Cola de dos extremos de elementos de tipo T
<list> Lista doblemente enlazada de elementos de tipo T
<map> Matriz asociativa de elementos de tipo T
<queue> Cola de elementos de tipo T
<set> Conjunto de elementos de tipo T (contenedor
asociativo)
<stack> Pila de elementos de tipo T
<vector> Matriz de elementos de tipo T
ITERADORES
<iterator> Soporte para iteradores
ALGORITMOS
<algorithm> Algoritmos generales (buscar, ordenar, contar, etc.)
<cstdlib> bsearch y qsort
NÚMEROS
<cmath> Funciones matemáticas
<complex> Operaciones con números complejos
<cstdlib> Números aleatorios estilo C
<numeric> Algoritmos numéricos generalizados
<valarray> Operaciones con matrices numéricas
DIAGNÓSTICOS
<cassert> Macro ASSERT
<cerrno> Tratamiento de errores estilo C
<exception> Clase base para todas las excepciones
<stdexcept> Clases estándar utilizadas para manipular excepciones
UTILIDADES GENERALES
<ctime> Fecha y hora estilo C
<functional> Objetos función
<memory> Funciones para manipular bloques de memoria
110
<utility> Manipular pares de objetos
LOCALIZACIÓN
<clocale> Control estilo C de las diferencias culturales
<locale> Control de las diferencias culturales
SOPORTE DEL LENGUAJE
<cfloat> Limites numéricos en coma flotante de estilo C
<climits> Limites numéricos estilo C
<csetjmp> Salvar y restaurar el estado de la pila
<csignal> Establecimiento de manejadores para condiciones
excepcionales (también conocidos como señales)
<cstdarg> Lista de parámetros de función de longitud variable
<cstddef> Soporte de la biblioteca al lenguaje C
<cstdlib> Definición de funciones, variables y tipos comunes
<ctime> Manipulación de la hora y fecha
<exception> Tratamiento de excepciones
<limits> Limites numéricos
<new> Gestión de memoria dinámica>
<typeinfo> Identificadores de tipos durante la ejecución
Biblioteca estándar de C++5
111
Ilustración 1: Evolución de algunos lenguajes
112
RECOMENDACIONES Y/O SUGERENCIAS
La forma en la que he desarrollado este manual no permite del todo consultar una
parte sin haber leído una anterior. En algunas ocasiones encontrará comentarios o
referencias a ejemplos vistos en una parte precedente al texto en cuestión.
A una persona que ya tenga conocimientos de este lenguaje puede resultarle más
rápida su consulta si presta especial atención a las tablas proporcionadas y a los
ejemplos mostrados, para ver parámetros, definiciones, declaraciones, e
implementación del código.
Al finalizar la lectura y estudio de este manual se contará con los elementos para
desarrollar programas estructurados. La principal característica de C++ es que es un
lenguaje orientado a objetos, es por eso que, si se tiene el interés de tener un mejor
nivel de programación y hacer cosas mejores, es necesario que se estudie la
programación orientada a objetos.
El lenguaje C++ ha sido una base para otros lenguajes de programación, es por ello
que encontramos varias similitudes con otros. Y, siendo un lenguaje vigente para el
desarrollo de aplicaciones, resulta muy útil aprenderlo. Sin embargo, considero que
no es absolutamente necesario aprender a programar con objetos en C++ antes que
en cualquier otro lenguaje, de hecho, personalmente recomiendo adentrarse desde
113
ahora en el lenguaje Java, con el cual, además de que proporciona varias ventajas
que en otros lenguajes difícilmente tenemos (como que los punteros no existen), se
ha convertido en uno de los lenguajes con más amplia “cobertura”, refiriéndome con
esto a que las implementaciones de este lenguaje prácticamente no tienen límites,
pudiendo encontrar aplicaciones desarrolladas con él en cualquier lado.
114
BIBLIOGRAFÍA
Sánchez, Jorge.
Java 2
www.jorgesanchez.net
2004, 312pp.
Schildt, Herbert.
C, Manual de referencia
Edit. Osborne McGraw-Hill.
4ª ed., 2000. 709 pp.
115