Documentos de Académico
Documentos de Profesional
Documentos de Cultura
2.1.- Constantes
Podemos definir a una constante como una localidad de memoria (objeto), la cual tiene un
nombre y un tipo de dato asociados, además de un valor que permanece fijo durante el
tiempo de ejecución.
Los valores para las constantes, permitidos por Borland C++, se clasifican en cuatro clases:
Para manejar los caracteres de control se utilizan las secuencias de escape que
empiezan con el carácter de diagonal hacia atrás (\) seguida de un carácter. Si el
carácter que sigue a la diagonal es alguno de los caracteres mostrados en la tabla 2.1,
se obtendrá el efecto explicado en ella; pero si es cualquiera de los demás caracteres del
Código ASCII, se visualizará el carácter tal cual.
Borland C++ permite el uso de dos caracteres juntos como valores de caracteres.
III).- Punto flotante, cualquiera con punto decimal ó con formato exponencial.
donde: pera, uva, manzana y fresa son constantes de enumeración y tienen los
siguientes valores:
pera = 0
uva = 1
manzana = 2
fresa = 3
pera = 0
uva = 1
manzana = 10
fresa = 6
2.2.- Variables
Una variable es un espacio de memoria que tiene un nombre y un tipo de dato asociados,
además de un valor que puede cambiarse durante el tiempo de ejecución.
En el Lenguaje C++ puede declararse una variable en cualquier lugar del programa, con la
única restricción de que la declaración preceda a la primera instrucción donde se utiliza tal
variable.
[, var2, ... ] ;
Ejemplos:
int algo, otro ;
2.3.- Ambito
El ámbito es una zona de programa donde puede utilizarse un identificador para accesar su
objeto . El ámbito va a depender, básicamente, del lugar del programa en que aparece la
declaración.
Ambito de BLOQUE.
Un bloque está formado por las instrucciones delimitadas por un par de llaves { }.
Es posible anidar una serie de bloques, y pueden declararse variables dentro de cada
bloque. Si, en diferentes bloques, existen variables con el mismo identificador, todas serán
consideradas como variables diferentes. Así que puede tenerse:
..............
..............
int x=5; // x del bloque 1
{
int x=10; // x del bloque 2
{
int x=20; // x del bloque 3
{
int x=30; // x del bloque 4
printf("x=%d",x); // x=30
}
printf("%d",x); // x=20
}
printf("%d",x); // x=10
}
printf("%d",x); // x=5
.............
.............
Debe tenerse cuidado al utilizar identificadores iguales para diferentes variables. Lo más
recomendable es no utilizar los mismos identificadores y no intentar manejar variables en
un ámbito diferente al que pertenecen.
Ambito de FUNCION.
En esta clase sólo se encuentran los identificadores que se utilizan como etiquetas cuando se
tienen instrucciones goto.
El identificador de una etiqueta debe ser único dentro de una función, y no puede utilizarse
la instrucción goto para saltar de una función a otra.
Ambito de ARCHIVO.
Las variables declaradas fuera de cualquier bloque en un archivo son consideradas como
variables globales, y el ámbito de sus identificadores abarca todos los bloques contenidos en
el archivo en cuestión; por lo que: una variable con éste ámbito puede ser utilizada en las
funciones del archivo que estén definidas después del punto donde se declaró dicha
variable.
2.4.- Duración
Los objetos con duración estática están localizados en memoria durante todo el tiempo de
ejecución del programa. Las funciones, las variables con ámbito de archivo y las variables
con especificadores de clase de almacenamiento static ó extern, tienen duración estática.
Los objetos con duración estática son inicializados a cero , en ausencia de un valor inicial
explícito.
Los objetos de duración local, conocidos también como objetos automáticos, son creados en
la pila de la memoria RAM ó en los registros del microprocesador. La memoria asignada a
éstos objetos es liberada cuando finaliza la ejecución del bloque donde fueron creados. Los
objetos de duración local deben utilizarse siempre en un ámbito local ó de función.
. ENLACE EXTERNO,
. ENLACE INTERNO,
. SIN ENLACE.
Cada instancia de un identificador con enlace externo representa al mismo objeto ó función
a través de todo el conjunto de archivos y librerías que componen el programa.
Cada instancia de un identificador con enlace interno representa al mismo objeto ó función
solamente dentro de un archivo.
1. Cualquier identificador de objeto ó archivo que tenga ámbito de archivo tendrá enlace
interno si su declaración contiene el especificador static.
Para C++, si el mismo identificador aparece con ambos tipos de enlace en el mismo
archivo, el identificador tendrá enlace externo.
a).- Cualquier identificador declarado para ser algo diferente de un objeto ó función (
p.ej. un identificador typedef ).
b).- Los parámetros de las funciones.
c).- Los identificadores de ámbito de bloque para objetos declarados sin el el
especificador extern.
Para aclarar lo relacionado con el especificador extern, revisemos los listados 2.1 y 2.2.
// EXTERN1.CPP
// EXTERN2.CPP
#include <iostream.h>
// DECLARACION de variables globales que:
extern int edad; // se encuentran en otro archivo
extern char nombre[];
void main()
{
cout << "\nCUAL ES TU NOMBRE ? " ; cin>> nombre ;
cout << "\nCUANTOS AÑOS TIENES, " << nombre << " ?" ; cin>> edad ; cout <<
"\n\n" ; cout << " TE FALTAN " << 100-edad ; cout << " PARA LLEGAR A LOS CIEN,
" << nombre << "\n" ; }
Listado 2.1.- EXTERN2.CPP, que declara y utiliza variables globales definidas en otro
archivo.
Los objetos que se manejan en C++ van a tener un tipo de dato asociado, el cual determina
la cantidad de espacio de almacenamiento que se le asigna a cada uno de los objetos de tal
tipo, así como el conjunto de operaciones que podrán realizarse con los valores
almacenados. Las operaciones serán representadas a través de identificadores específicos
llamados operadores.
Los operadores aritméticos se aplican sobre objetos con valores numéricos, como se
muestra en la tabla 2.2 .
<= Menor ó igual que="=" Igual que !="Diferente" que ( No igual que )
Los operadores lógicos se aplican sobre los enunciados que resultan de las operaciones
relacionales, y el resultado siempre será un valor de verdad. Los operadores lógicos son:
&& Y ( Conjunción )
|| O ( Disyunción )
! NO ( Negación )
& Y ( Conjunción )
| O ( Disyunción )
Si tenemos la declaración:
char indice = 81 ;
En este caso se utilizó el número 127 porque es el único número entero que puede escribirse
en un octeto ( byte ) y que tiene los siete primeros bits con valor 1 .
Ejemplo 2.6.2
Se requiere que en el número 112 tengan valor 1 los bits que correspondan con los del
número 7 que tengan valor 1. En este caso, la operación a utilizar es la disyunción entre
bits, quedando las instrucciones en la siguiente forma:
char masc ;
masc = 112 | 7 ;
Ejemplo 2.6.3
La disyunción exclusiva sirve para poner a uno los bits del primer operando cuyos
correspondientes bits en el segundo operando sean distintos, como se ve a continuación:
x = 125 ^ 120 ;
char x ;
Manualmente se tendría:
Los operadores de desplazamiento mueven todos los bits, de una variable entera ó de
carácter, hacia la izquierda ó hacia la derecha.
A medida que los bits son desplazados hacia un extremo, los lugares desocupados del
estremo contrario van siendo ocupados por ceros. Los unos que salen por los extremos no se
pueden recuperar(no hay rotación) .
Un valor izquierdo es una expresión que designa un objeto. Las expresiones utilizadas como
valor izquierdo corresponden a objetos cuyos valores pueden cambiar durante la ejecución
de un programa. Generalmente, en la expresión correspondiente a un valor izquierdo
aparece el identificador de una variable. Cuando el valor izquierdo se refiere a la dirección
de una variable, la expresión puede constar de una combinación de varios identificadores.
Los operadores de asignación sirven para asignar un valor derecho a un valor izquierdo, y
están formados por la combinación del operador de asignación simple = con otro operador,
como se muestra en la tabla 2.3 .
En esta unidad estudiaremos las instrucciones que sirven para controlar el flujo de
ejecución de un programa en C++ . De acuerdo a las características de cada una, las
clasificaremos en grupos de estructuras básicas de:
3.1.- Secuencia
A este grupo pertenecen las instrucciones que están formadas por una o varias expresiones
simples colocadas una a continuación de la otra. La sintaxis para las instrucciones
estructurados en secuencia es la siguiente:
instruccion_1 ;
instruccion_2 ;
.........
instruccion_N ;
A este grupo pertenecen aquellas instrucciones que sirven para que la ejecución del
programa tome una de varias opciones existentes en una ramificación.
if( condición )
[else]
[bloque_2]
donde:
bloque_1 y bloque_2 pueden estar formados por uno ó
más instrucciones.
else es opcional, y en caso de no existir, bloque_2
tampoco existirá.
Esta estructura puede anidarse para elgir entre un grupo de más de dos opciones, tomando
la siguiente forma:
if(condición_1)
bloque_1;
else if(condición_2)
bloque_2;
else if(condición_3)
bloque_3;
............
else
bloque_N;
#include <iostream.h>
void main()
{
long ncontrol;
#include <iostream.h>
#include <conio.h>
void main()
{
int calif;
clrscr();
cout << "CALIFICACION: "; cin>> calif;
if(calif > 100)
cout << "ERROR: CALIFICACION DEMASIADO ALTA ....."; else if(calif < 0)
cout << "ERROR: CALIFICACION DEMASIADO BAJA ....."; else if( (calif>= 70) &&
(calif <=100)) cout << "CALIFICACION APROBATORIA."; else cout << "CALIFICACION
REPROBATORIA."; }
Esta instrucción es útil cuando se tiene que elegir entre más de dos opciones, como es el caso
de manejo de menús. Esta instrucción es preferible que el uso de anidamientos de varios if-
else.
Su sintaxis es:
switch(expresión_entera)
{
case Const_1 : Bloque_1 ; break ;
case Const_2 : Bloque_2 ; break ;
.............................
.............................
.............................
case Const_N : Bloque_N ; break ;
default : Bloque_X ;
}
#include <iostream.h>
#include <conio.h>
void main()
{
char opcion;
clrscr();
gotoxy(30,5);
cout << "MENU DE OPCIONES"; gotoxy(30,8);
cout << "1.- CREACION"; gotoxy(30,10);
cout << "2.- MODIFICACION"; gotoxy(30,12);
cout << "3.- ELIMINACION"; gotoxy(30,14);
cout << "0.- SALIDA"; gotoxy(30,18);
cout << "SU OPCION ? "; opcion= getche();
cout << "\n\n";
switch(opcion)
{
case '1': clrscr(); cout << "RUTINA DE CREACION\n"; break;
case '2': clrscr(); cout << "RUTINA DE MODIFICACION\n"; break;
case '3': clrscr(); cout << "RUTINA DE ELIMINACION\n"; break;
case '0': clrscr(); cout << "SALIDA AL SISTEMA OPERATIVO\n";break;
default:clrscr(); cout << "OPCION INVALIDA.....\n";
}
}
3.3.- Iteración
Con esta instrucción se maneja una estructura en la que, de entrada, se evalúa una
condición. En caso de que el resultado de tal evaluación sea un valor diferente de cero , se
ejecuta un bloque de instrucciones, en el cual debe existir una instrucción que modifique la
condición, ya que de lo contrario ejecutará un ciclo infinito ( loop ). Si el resultado de la
evaluación es un valor igual a cero , el bloque de instrucciones no se ejecuta y finaliza la
ejecución de la instrucción.
while(condición)
bloque;
#include <iostream.h>
#include <conio.h>
#define FALSO 0
void main()
{
int valor=1;
clrscr();
while(valor!=FALSO)
{
cout << "\nTeclee un valor entero ( 0="salir" ) : "; cin>> valor;
}
}
do
bloque;
while(condición);
Como una aplicación de la instrucción do-while , se presenta en el listado 3.5 una variante
al problema resuelto en el listado 3.3 .
#include <iostream.h>
#include <conio.h>
void main()
{
char opcion;
do{ // inicia ciclo 1
clrscr();
gotoxy(30,5);
cout << "MENU DE OPCIONES"; gotoxy(30,8); cout << "1.- CREACION";
gotoxy(30,10); cout << "2.- MODIFICACION"; gotoxy(30,12); cout << "3.-
ELIMINACION"; gotoxy(30,14); cout << "0.- SALIDA"; gotoxy(30,18); cout << "SU
OPCION ? "; window(42,18,42,18); do{ // inicia ciclo 2 clrscr();
opcion="getche();" }while((opcion < '0')||(opcion>'3'));// fin ciclo 2
window(1,1,80,25);
switch(opcion)
{
case '1': clrscr();
cout << "RUTINA DE CREACION\n"; break; case '2':
clrscr(); cout << "RUTINA DE MODIFICACION\n"; break; case '3': clrscr(); cout
<< "RUTINA DE ELIMINACION\n"; break; case '0': clrscr(); cout << "SALIDA AL
SISTEMA OPERATIVO\n"; break; } cout << "\n\nPULSE CUALQUIER TECLA PARA
CONTINUAR.."; getch(); }while(opcion!="0" ); // fin ciclo 1 }
Entre las instrucciones de iteración, for es la más versátil, ya que, entre otras
características, permite la declaración de variables dentro de su estructura.
donde:
inicialización es un bloque de instrucciones que puede
incluir la declaración de las variables
involucradas y la asignación de valores
iniciales.
Los bloques de inicialización, condición y control no son obligatorios, pero sí lo son los tres
punto y coma que los separan; de tal suerte que la forma mínima de una instrucción for
quedaría así:
for(;;) // ciclo infinito
; // no realiza tarea alguna
#include <iostream.h>
#include <conio.h>
int main()
{
clrscr();
Además de la función main(), con frecuencia es necesario utilizar funciones adicionales que
pueden ser accesadas a través del enlace de librerías precompiladas ó a través de su
definición en el archivo de código fuente ó en archivos de cabecera.
En esta unidad estudiaremos los procedimientos necesarios para el manejo de las funciones
definidas en el código fuente.
En principio, debemos distinguir entre: declarar, definir e invocar una función, ya que la
confusión de éstos términos es causa de frecuentes problemas.
Desde los orígenes del Lenguaje C ha existido la distinción entre definir y declarar una
función. Cuando se define una función se le está reservando espacio de almacenamiento en
memoria; en cambio cuando se declara solo se está avisando que más adelante se encuentra
una función con ciertas características, pero no se le reserva espacio en memoria.
donde:
Cuando se declara una función, se está avisando al compilador que más adelante
encontrará la definicion de tal función, y que por el momento, tome nota de las
características de ella, como son: el tipo de dato que retorna, su nombre y los tipos de
argumentos que va a recibir. Con esto, no habrá ningún problema en invocar a la función
en un bloque de programa ubicado antes del lugar donde se encuentra escrita su definición.
En el ejemplo 4.1, las líneas:
void saludo();
float calcula(float);
También cabe hacer notar que en la declaración no se requiere escribir identificadores para
los argumentos, como se observa en el ejemplo 4.1, sino que basta con incluir los tipos de
datos de los argumentos. Se pueden incluir identificadores de argumentos, sólo que el
ámbito de tales identificadores estará restringido a la declaración de la función
correspondiente.
En este caso, el identificador arg no tiene uso alguno; por lo que es innecesaria su inclusión.
// ENCABEZADOS
#include <iostream.h>
#include <conio.h>
// DECLARACION DE FUNCIONES
void saludo();
float calcula(float);
// DEFINICION DE LA FUNCION PRINCIPAL
void main()
{
float costo, precio;
clrscr();
cout << "COSTO : $ "; cin>> costo;
saludo(); //INVOCACION A LA FUNCION saludo()
precio = calcula(costo); //INVOCACION A LA FUNCION calcula()
cout << "PRECIO : $ " << precio; } // DEFINICION DE LA FUNCION saludo()
void saludo() { clrscr(); cout << "!! BIENVENIDO A LA VENTA ESPECIAL !!"; } //
DEFINICION DE LA FUNCION calcula() float calcula(float x) { return( x * 1.6);
}
void main(void)
{
double result, a=13500.45, b=16763.87;
result = suma(a,b); // Invocación a la función suma()
// definida en ARITME.OBJ
cout << result; }
Este es el criterio que se sigue al utilizar los archivos de cabecera que contiene el paquete
compilador.
#include <stdio.h>
se está incluyendo el archivo que contiene los prototipos de las funciones que se utilizan
para el manejo de la entrada/salida estándar.
En la mayoría de los casos, los identificadores ó nombres de los objetos deben ser únicos,
esto es, que dos objetos dentro del mismo ámbito no deben tener el mismo nombre. Una de
las excepciones la constituyen las funciones, que pueden compartir el mismo nombre entre
varias de ellas, dando la impresión de que a una sola función se le ha "sobrecargado de
tareas", razón por la cual se les llama funciones sobrecargadas.
Por ejemplo, supongamos que deseamos una función que sirva para sumar números. Lo
ideal sería contar con una sola función que realizara la suma de números de diferentes tipos
y que retornara un valor de acuerdo al tipo de resultado. El Lenguaje C++ permite resolver
este problema por medio de la sobrecarga de funciones.
A continuación se muestran los prototipos para cada una de las funciones que comparten el
nombre suma :
float suma(float,float);
double suma(double,double);
Aquí surge la pregunta: ¿ cómo distingue el compilador entre cada una de las funciones
suma() ?.
Debido a que varias funciones sobrecargadas pueden usar el mismo identificador, C++
utiliza el concepto de nombres ampliados para controlar cada función individualmente. El
nombre ampliado de una función se construye tomando como base el nombre de la función
y los tipos de los argumentos. El tipo de retorno de la función no se utiliza en la formación
del nombre ampliado. La composición del nombre ampliado ocurre a nivel del compilador,
no al nivel del enlazador. El enlazador resuelve fácilmente las referencias externas para
sobrecargar las funciones debido a que éstas tienen nombres ampliados únicos.
Las reglas básicas usadas en Borland C++ para los nombres ampliados son relativamente
simples como se observa a continuación :
1. Se utiliza primero el nombre de la clase, precedido por el carácter @.
2. Enseguida viene el nombre de la función, precedido por el carácter @.
3. Si la función no es parte de una clase, el nombre ampliado empieza con el símbolo @
seguido por el nombre de la función. Se respetan las reglas establecidas para la
creación de identificadores.
4. El nombre de la función está seguido por una secuencia $q ; las letras minúsculas que
le siguen designan cada tipo de argumento declarado.
La tabla 4.1 muestra una lista de las letras que se utilizan para manejar los tipos
predefinidos de C++ en la formación de los nombres ampliados.
Tabla 4.1.- Letras para los tipos de argumentos en la creación de nombres ampliados.
Utilizando la tabla 4.1, se pueden predecir fácilmente los nombres ampliados de las
funciones, como se muestra a continuación: