SEGUNDA PARTE PROGRAMACION 1
Operadores De Asignación
En principio puede resultar algo futil gastar papel en describir al operador IGUAL A ( = ) , sin embargo es necesario remarcar ciertas características del mismo .
Anteriormente definimos a una asignación como la copia del resultado de una expresión ( rvalue ) sobre otra ( lvalue ) , esto implica que dicho lvalue debe tener LUGAR (es decir poseer una posición de memoria ) para alojar dicho valor .
Es por lo tanto válido escribir a = 17;
pero no es aceptado , en cambio
17 = a; /* incorrecto */
ya que la constante numérica 17 no posee una ubicación de memoria donde alojar al valor de a .
Aunque parezca un poco extraño al principio las asignaciones, al igual que las otras operaciones , dan un resultado que puede asignarse a su vez a otra expresión .
De la misma forma que (a + b) es evaluada y su resultado puedo copiarlo en otra variable : c = (a + b) ; una asignación (a = b) da como resultado el valor de b , por lo que es lícito escribir
c = ( a = b ) ;
Debido a que las asignaciones se evalúan de derecha a izquierda , los paréntesis son superfluos , y podrá escribirse entonces :
c = a = b = 17;
con lo que las tres variables resultarán iguales al valor de la constante .
El hecho de que estas operaciones se realicen de derecha a izquierda también permite realizar instrucciones del tipo :
a = a + 17 ;
Significando esto que al valor que TENIA anteriormente a , se le suma la constante y LUEGO se copia el resultado en la variable .
Como este último tipo de operaciones es por demás común , existe en C un pseudocódigo , con el fín de abreviarlas .
Así una operación aritmética o de bit cualquiera (simbolizada por OP )
a = (a) OP (b) ;
Puede escribirse en forma abreviada como:
a OP= b ;
Por ejemplo a += b ; /* equivale : a = a + b */
a -= b ; /* equivale : a = a - b */
a *= b ; /* equivale : a = a * b */
a /= b ; /* equivale : a = a / b */
a %= b ; /* equivale : a = a % b */
Nótese que el pseudooperador debe escribirse con los dos símbolos seguidos , por ejemplo += , y no será aceptado +(espacio) = .
Los operadores de asignación están resumidos en la TABLA.
Tabla de Operadores de Asignación
Símbolo Descripción Ejemplo Orden De Evaluación
= igual a a = b 13
op= pseudocodigo a += b 13
=?: asig.condicional a = (c>b)?d:e 12
Vemos de la tabla anterior que aparece otro operador denominado ASIGNACION CONDICIONAL . El significado del mismo es el siguiente : lvalue = ( operación relacional ó logica ) ? (rvalue 1) : (rvalue 2) ;
de acuerdo al resultado de la operación condicional se asignará a lvalue el valor de rvalue 1 ó 2 . Si aquella es CIERTA será lvalue = rvalue 1 y si diera FALSO , lvalue = rvalue 2 .
Por ejemplo, si quisiéramos asignar a c el menor de los valores a ó b , bastará con escribir :
c = ( a < b ) ? a : b ;
EXPRESIONES Y EVALUACIÓN DE OPERACIONES
Orden de prioridad de operadores aritméticos
Multiplicativos
* Multiplicación
/ División
% Resto en división entera
Unarios
! Negación lógica (NOT)
~ Complemento en binario
+ Más
Menos
++ Preincremento o postincremento
Predecremento o postdecrement
& Dirección
* Valor en la dirección de
sizeof Tamaño del operando en bytes
new Espacio en memoria dinámica
delete Desasigna espacio en memoria
Prioridad
*
/
%
+
-
Evaluación secuencial de expresiones aritméticas
65.0 / 2
32.5 65 / 2
32 65 % 2
1
5 + 3 * 3 - 4 + 12 * 10 5 + 9 - 4 + 120
14 - 4 + 120
10 + 120
130 6 + 9 * 8 / 2 * 4 - 2 * 3
6 + 72 / 2 * 4 - 2 * 3
6 + 36 * 4 - 2 * 3
6 + 144 - 2 * 3
6 + 144 - 6
150 - 6
144 (63 -20) /(35 -15)
43 / 20
2
(63 -20.0) /(35 -15)
43.0 / 20
2.0
4.2 / 2 + 3.9 / 3
2.1 + 3.9 / 3
2.1 + 1.3
4.4 3 + sqrt(8 % 6 * 10 / 5)
3 + sqrt( 2 * 10 / 5)
3 + sqrt(20 / 5)
3 + sqrt(4)
3 + 2
5 (60 - 20) /35.0 -15
40 /35.0 - 15
1.142 - 15
-13.858
ESTRUCTURA DE UN PROGRAMA
Anatomia de un Programa C
Siguiendo la tradición, la mejor forma de aprender a programar en cualquier lenguaje es editar, compilar, corregir y ejecutar pequeños programas descriptivos. Analicemos por lo tanto el primer ejemplo.
EJEMPLO 1
#include <stdio.h>
main()
{
printf("Bienvenido a la Programación en lenguaje C n"
;
return 0;
}
Función Main()
Dejemos de lado por el momento el análisis de la primer línea del programa, y pasemos a la segunda.
La función main() indica donde empieza el programa, cuyo cuerpo principal es un conjunto de sentencias delimitadas por dos llaves, una inmediatamente después de la declaración main() " { ", y otra que finaliza el listado " } ". Todos los programas C arrancan del mismo punto: la primer sentencia dentro de dicha función, en este caso printf ("......"
.
En el EJEMPLO 1 el programa principal está compuesto por sólo dos sentencias: la primera es un llamado a una función denominada printf(), y la segunda, return, que finaliza el programa retornando al Sistema Operativo.
Recuérdese que el lenguaje C no tiene operadores de entrada-salida por lo que para escribir en video es necesario llamar a una función externa. En este caso se invoca a la función printf(argumento) existente en la Librería y a la cual se le envía como argumento aquellos caracteres que se desean escribir en la pantalla. Los mismos deben estar delimitados por comillas.
La secuencia n que aparece al final del mensaje es la notación que emplea C para el carácter "nueva línea" que hace avanzar al cursor a la posición extrema izquierda de la línea siguiente. Más adelante analizaremos otras secuencias de escape habituales.
La segunda sentencia (return 0) termina el programa y devuelve un valor al Sistema operativo, por lo general cero si la ejecución fue correcta y valores distintos de cero para indicar diversos errores que pudieron ocurrir. Si bien no es obligatorio terminar el programa con un return, es conveniente indicarle a quien lo haya invocado, sea el Sistema Operativo o algún otro programa, si la finalización ha sido exitosa, o no. De cualquier manera en este caso, si sacamos esa sentencia el programa correrá exactamente igual, pero al ser compilado, el compilador nos advertirá de la falta de retorno.
Cada sentencia de programa queda finalizada por el terminador "; ", el que indica al compilador el fin de la misma. Esto es necesario ya que, sentencias complejas pueden llegar a tener más de un renglón, y habrá que avisarle al compilador donde terminan.
Es perfectamente lícito escribir cualquier sentencia abarcando los renglones que la misma necesite, por ejemplo podría ser:
printf("Bienvenido a la Programación"
"en lenguaje C n"
;
Encabezamiento
Las líneas anteriores a la función main() se denominan ENCABEZAMIENTO (HEADER) y son informaciones que se le suministran al Compilador.
La primera línea del programa está compuesta por una directiva: " #include " que implica la orden de leer un archivo de texto especificado en el nombre que sigue a la misma ( <stdio.h> ) y reemplazar esta línea por el contenido de dicho archivo.
En este archivo están incluidas declaraciones de las funciones luego llamadas por el programa (por ejemplo printf() ) necesarias para que el compilador las procese. Por ahora no nos preocupemos por el contenido del archivo ya que más adelante, en el capítulo de funciones, analizaremos exhaustivamente dichas declaraciones.
Hay dos formas distintas de invocar al archivo, a saber, si el archivo invocado está delimitado por comillas (por ejemplo "stdio.h"
el compilador lo buscará en el directorio activo en el momento de compilar y si en cambio se lo delimita con los signos <.......> lo buscará en algun otro directorio, cuyo nombre habitualmente se le suministra en el momento de la instalación del compilador en el disco ( por ejemplo C:TCINCLUDE). Por lo general estos archivos son guardados en un directorio llamado INCLUDE y el nombre de los mismos está terminado con la extensión .h.
La razón de la existencia de estos archivos es la de evitar la repetición de la escritura de largas definiciones en cada programa.
Nótese que la directiva "#include" no es una sentencia de programa sino una orden de que se copie literalmente un archivo de texto en el lugar en que ella está ubicada ,por lo que no es necesario terminarla con "; ".
Para optimizar el código producido, los lenguajes en general y como parte de la máxima "Divide y Vencerás", colocan una serie de utilidades(funciones, tipos de datos, variables, etc.) en archivos separados, los cuales de pueden utilizar como si estuvieran en el programa que estamos diseñando.
El C/C++ en particular trae una gran cantidad de archivos a incluir por medio de la directiva del compilador #include, la cual debe ser colocada preferiblemente al inicio del programa y siempre por fuera del ámbito de las funciones.
Los archivos a incluir en el turbo C++ los puede encontrar en el nivel de ayuda del editor. Los siguientes serán los utilizados en el presente manual, y con esta sintaxis:
#include <iostream.h> #include <conio.h> #include <string.h>
#include <iomanip.h> #include <dos.h> #include <stdlib.h>
#include <stdio.h> #include <math.h> #include <values.h>
#include <ctype.h> #include <graphics.h> #include <fstream.h>
Separadores de Instrucciones
Cada lenguaje utiliza alguna convención para separar las diferentes instrucciones del mismo; en el lenguaje C el separador es el símbolo de punto y coma ;. Se debe colocar el punto y coma al final de cada instrucción (statement). En C/C++ el punto y coma marca el fin de una instrucción, es decir es su terminador. Se exceptúan las instrucciones del preprocesador (define, include, etc.), las cuales no llevan punto y coma al final.
En tiempo de compilación el "compilador" revisará la sintaxis de las diferentes instrucciones y en caso de encontrar alguna con terminador inadecuado, esto es sin punto y coma, dará un error de sintaxis: " ; expected", es decir que esperaba un punto y coma y encontró otro carácter, en general este otro caracter lo encuentra en la instrucción siguiente, donde marcará el error y confundiendo al recién iniciado. Observe los punto y comas en los programas presentados en este capítulo.
Comentarios
La inclusión de comentarios en un programa es una saludable práctica, como lo reconocerá cualquiera que haya tratado de leer un listado hecho por otro programador ó por sí mismo, varios meses atrás. Para el compilador, los comentarios son inexistentes, por lo que no generan lineas de código, permitiendo abundar en ellos tanto como se desee.
En el lenguaje C se toma como comentario todo caracter interno a los símbolos: /* */ . Los comentarios pueden ocupar uno o más renglones, por ejemplo:
/* este es un comentario corto */
/* este otro
es mucho
más largo
que el anterior */
Todo caracter dentro de los símbolos delimitadores es tomado como comentario incluyendo a " * " ó " ( " , etc.
Operaciones de Entrada/Salida
Un programa para que pueda trabajar, entre otras cosas, debe poder operar los datos que se proporcionan mediante un dispositivo de entrada y poder enviar los resultados después de procesados con la ayuda de un algoritmo a un dispositivo de salida. En la forma estándar o por defecto (default) el dispositivo de entrada será el teclado y el dispositivo de salida la pantalla o monitor.
Instrucción de Escritura En Pantalla
Para transferir valores de constantes, variables, expresiones algebraicas, o expresiones delimitadas como cadenas de caracteres de la memoria del computador a la pantalla, emplearemos la instrucción Printf() , en su forma por defecto, y la cual se encuentra en el archivo a incluir sodio.h. También se utiliza puts() para las cadenas de caracteres.
Para lograr ejecutar un programa se deberán utilizar varias secuencias de teclas, las principales a necesitar e ir "memorizando" son las contenidas en la siguiente Tabla:
Secuencias de teclas más utilizadas.
Tecla Orden Del Menú
F1 Ayuda del editor
F2 Grabar en disco
F3 Cargar desde disco
F4 Ejecutar programa hasta el cursor
F5 Hace zoom en la ventana activa
F6 Cambia de ventana activa
F7 Rastreo del programa con llamado de funciones
F8 Rastreo del programa saltando funciones
F9 Compila y enlaza el programa
F10 Activa el menú principal
F10 File New Comenzar un programa nuevo
F10 File Change Dir Cambiar directorio actual
F10 Window Close All Cerrar todas las ventanas
F10 Help Index Índice alfabético de ayuda
CTRL + F8 Marca punto en el cual detenerse ejecución
CTRL + F9 Compilar y ejecutar(correr)
CTRL + Y Borrar una línea
CTRL + T Borrar una palabra o espacios
Shift + Teclas Mover Marcar bloque
Shift + Del Borrar bloque marcado
Shift + Ins Restaurar bloque borrado
CTRL + KV Mover bloque marcado
CTRL + KC Copiar bloque marcado
CTRL + KR Leer un archivo como bloque
CTRL + KW Grabar un bloque como archivo
CTRL + KP Imprimir bloque marcado
ALT + 0 Lista ventanas abiertas
ALT + 1 al 9 Activa ventana 1 al 9
ALT + F1 Pantalla ayuda anterior
ALT + F3 Elimina ventana activa
ALT + F4 Abre ventana de depuración
ALT + F5 Cambia a ventana de ejecución del programa
ALT + F7 Error anterior
ALT + F8 Error siguiente
ALT + F9 Compilar a archivo .OBJ
ALT + X Salir(eXit) del editor del C++
Cuerpo del Programa
Los programas en C/C++ deberán estar compuestos de al menos una función, la función main(), sin esta el programa no trabajará por sí solo. Cada función del programa, consta de la secuencia de instrucciones o algoritmo que la computadora deberá realizar.
El algoritmo debe incluir identificadores, operadores y palabras claves. Todo algoritmo se desarrollará con tres tipos de instrucciones: Secuenciales, Selectivas y Repetitivas; el entendimiento de estas tres es el objetivo principal de este curso.
De esta forma el algoritmo es simplemente la secuencia de pasos que interpretan un problema específico, en algún campo del saber, y que la computadora podrá ejecutar y de esta forma nosotros obtener los resultados deseados.
El C++ es un lenguaje de formato libre. Los espacios en blanco adicionales y los caracteres de salto de línea no son relevantes para el compilador, excepto cuando se requieren para conservar identificadores y las palabras claves o dentro de variables de tipo de cadena. Las líneas del programa pueden tener una longitud máxima de hasta 127 caracteres, siendo preferible utilizar menos de los primeros 80 por motivos de presentación en las impresiones del código fuente. Recordar que la pantalla tiene en modo de texto 80 columnas.
PROCESO DE CREACIÓN Y EJECUCIÓN DE UN PROGRAMA
Probablemente este es el lugar más adecuado para explicar cómo se obtiene un fichero ejecutable a partir de un programa C++.
Para empezar necesitamos un poco de vocabulario técnico. Veremos algunos conceptos que se manejan frecuentemente en cualquier curso de programación y sobre todo en manuales de C y C++.
Fichero fuente y programa o código Los programas C y C++ se escriben con la ayuda de un editor de textos del mismo modo que cualquier texto corriente. Los ficheros que contiene programas en C o C++ en forma de texto se conocen como ficheros fuente, y el texto del programa que contiene se conoce como programa fuente. Nosotros siempre escribiremos programas fuente y los guardaremos en ficheros fuente.
Ficheros objeto, código objeto y compiladores:
Los programas fuente no pueden ejecutarse. Son ficheros de texto, pensados para que los comprendan los seres humanos, pero incomprensibles para los ordenadores.
Para conseguir un programa ejecutable hay que seguir algunos pasos. El primero es compilar o traducir el programa fuente a su código objeto equivalente. Este es el trabajo que hacen los compiladores de C y C++. Consiste en obtener un fichero equivalente a nuestro programa fuente comprensible para el ordenador, este fichero se conoce como fichero objeto, y su contenido como código objeto.
Los compiladores son programas que leen un fichero de texto que contiene el programa fuente y generan un fichero que contiene el código objeto.
El código objeto no tiene ningún significado para los seres humanos, al menos no directamente. Además es diferente para cada ordenador y para cada sistema operativo. Por lo tanto existen diferentes compiladores para diferentes sistemas operativos y para cada tipo de ordenador.
Librerías:
Junto con los compiladores de C y C++, se incluyen ciertos ficheros llamados librerías. Las librerías contienen el código objeto de muchos programas que permiten hacer cosas comunes, como leer el teclado, escribir en la pantalla, manejar números, realizar funciones matemáticas, etc. Las librerías están clasificadas por el tipo de trabajos que hacen, hay librerías de entrada y salida, matemáticas, de manejo de memoria, de manejo de textos, etc.
Hay un conjunto de librerías muy especiales, que se incluyen con todos los compiladores de C y de C++. Son las librerías ANSI o estándar. Pero también hay librerías no estándar, y dentro de estas las hay públicas y comerciales. En este curso sólo usaremos librerías ANSI.
Ficheros ejecutables y enlazadores:
Cuando obtenemos el fichero objeto, aún no hemos terminado el proceso. El fichero objeto, a pesar de ser comprensible para el ordenador, no puede ser ejecutado. Hay varias razones para eso:
1. Nuestros programas usaran, en general, funciones que estarán incluidas en librerías externas, ya sean ANSI o no. Es necesario combinar nuestro fichero objeto con esas librerías para obtener un ejecutable.
2. Muy a menudo, nuestros programas estarán compuestos por varios ficheros fuente, y de cada uno de ellos se obtendrá un fichero objeto. Es necesario unir todos los ficheros objeto, más las librerías en un único fichero ejecutable.
3. Hay que dar ciertas instrucciones al ordenador para que cargue en memoria el programa y los datos, y para que organice la memoria de modo que se disponga de una pila de tamaño adecuado, etc. La pila es una zona de memoria que se usa para que el programa intercambie datos con otros programas o con otras partes del propio programa. Veremos esto con más detalle durante el curso.
Existe un programa que hace todas estas cosas, se trata del "link", o enlazador. El enlazador toma todos los ficheros objeto que componen nuestro programa, los combina con los ficheros de librería que sea necesario y crea un fichero ejecutable.
Una vez terminada la fase de enlazado, ya podremos ejecutar nuestro programa.
Errores
Por supuesto, somos humanos, y por lo tanto nos equivocamos. Los errores de programación pueden clasificarse en varios tipos, dependiendo de la fase en que se presenten.
Errores de sintaxis: son errores en el programa fuente. Pueden deberse a palabras reservadas mal escritas, expresiones erróneas o incompletas, variables que no existen, etc. Los errores de sintaxis se detectan en la fase de compilación. El compilador, además de generar el código objeto, nos dará una lista de errores de sintaxis. De hecho nos dará sólo una cosa o la otra, ya que si hay errores no es posible generar un código objeto.
Avisos: además de errores, el compilador puede dar también avisos (warnings). Los avisos son errores, pero no lo suficientemente graves como para impedir la generación del código objeto. No obstante, es importante corregir estos avisos, ya que el compilador tiene que decidir entre varias opciones, y sus decisiones no tienen por qué coincidir con lo que nosotros pretendemos, se basan en las directivas que los creadores del compilador decidieron durante su creación.
Errores de enlazado: el programa enlazador también puede encontrar errores. Normalmente se refieren a funciones que no están definidas en ninguno de los ficheros objetos ni en las librerías. Puede que hayamos olvidado incluir alguna librería, o algún fichero objeto, o puede que hayamos olvidado definir alguna función o variable, o lo hayamos hecho mal.
Errores de ejecución: incluso después de obtener un fichero ejecutable, es posible que se produzcan errores. En el caso de los errores de ejecución normalmente no obtendremos mensajes de error, sino que simplemente el programa terminará bruscamente. Estos errores son más difíciles de detectar y corregir. Existen programas auxiliares para buscar estos errores, son los llamados depuradores (debuggers). Estos programas permiten detener la ejecución de nuestros programas, inspeccionar variables y ejecutar nuestro programa paso a paso. Esto resulta útil para detectar excepciones, errores sutiles, y fallos que se presentan dependiendo de circunstancias distintas.
Errores de diseño: finalmente los errores más difíciles de corregir y prevenir. Si nos hemos equivocado al diseñar nuestro algoritmo, no habrá ningún programa que nos pueda ayudar a corregir los nuestros. Contra estos errores sólo cabe practicar y pensar.
UNIDAD II
INSTRUCCIONES FUNDAMENTALES (DE CONTROL)
INSTRUCCIONES DE ENTRADA Y SALIDA DE DATOS
Operaciones de Entrada/Salida
Un programa para que pueda trabajar, entre otras cosas, debe poder operar los datos que se proporcionan mediante un dispositivo de entrada y poder enviar los resultados después de procesados con la ayuda de un algoritmo a un dispositivo de salida. En la forma estándar o por defecto (default) el dispositivo de entrada será el teclado y el dispositivo de salida la pantalla o monitor.
Instrucción de Escritura en Pantalla
Para transferir valores de constantes, variables, expresiones algebraicas, o expresiones delimitadas como cadenas de caracteres de la memoria del computador a la pantalla, emplearemos la instrucción printf() , en su forma por defecto, y la cual se encuentra en el archivo a incluir stdio.h. También se utiliza puts() para las cadenas de caracteres.
Printf(“Texto y/o formato de salida”,variable o constante);
Printf(“Texto y/o formato de salida”,variable o constante);
Printf(“Texto y/o formato de salida”,operación aritmética);
Printf(“Texto”);
Printf(“Texto y/o formato de salida”,operación lógica)
Printf(“Estado civil: “);
Printf(“Salario: %d”, sal);
Printf(“%d”,a>b);
Printf(“%f”,123*23);
Printf(“Francisco tiene %d años y Pedro %d”,ed1,ed2);
Puts(“texto”);
Puts(variable cadena);
Puts(concatenación);
Puts(“Nombre: “);
Puts(“Reprobado”);
Puts(Ed);
Puts(a+b+”hola”);
Instrucción de Lectura
Para leer y almacenar valores a la memoria del computador, emplearemos la instrucción scanf() , en su forma por defecto, y la cual se encuentra en el archivo a incluir stdio.h. También se utiliza gets() para las cadenas de caracteres.
Scanf(“formato”,&variable);
Scanf(“formatos”,&var1,&var2…,&varn);
Scanf(“%d”,&ed);
Scanf(“%d %d %d”,&a,&b,&c);
Scanf(“%f”,&sal);
Scanf(“%s”,&nom);
Gets(variable cadena);
Gets(nom);
INSTRUCCIONES DE SELECCIÓN: SIMPLES Y ANIDADAS
Todo algoritmo se desarrollará con tres tipos de instrucciones: Secuenciales, Selectivas y Repetitivas; el entendimiento de estas tres es el objetivo principal de este curso.
Proposición If - Else
Esta proposición sirve para ejecutar ciertas sentencias de programa, si una expresión resulta CIERTA ú otro grupo de sentencias, si aquella resulta FALSA. Su interpretación literal sería: SI es CIERTA tal cosa, haga esto (la o las sentencias) , si no lo es saltará a la siguiente instrucción.
El caso más sencillo sería :
if(expresión)
sentencia ;
ó
if(expresión) sentencia ;
Cuando la sentencia que sigue al IF es única, las dos formas de escritura expresadas arriba son equivalentes . La sentencia sólo se ejecutará si el resultado de "expresión" es distinto de cero (CIERTO) , en caso contrario el programa salteará dicha sentencia , realizando la siguiente en su flujo.
Veamos unos ejemplos de las distintas formas que puede adoptar la "expresión" dentro de un IF :
if( a > b ) if( (a > b) != 0 ) las dos expresiones son idénticas, aunque a veces resulta más claro expresarla de la segunda manera, sobre todo en los primeros contactos con el lenguaje.
if(a) if(a != 0)
if(!a) if(a == 0 ) Las dos superiores son idénticas entre sí , al igual que las dos inferiores Obsérvese que (!a) dará un valor CIERTO sólo cuando a sea FALSO. (ver operador NEGACION en el capítulo anterior )
if( a == b )
if( a = b ) /* Error */ La primera es una expresión correcta , el IF se realizará sólo si a es igual a b. En cambio la segunda es un error , ya que no se está comparando a con b , sino ASIGNANDO el valor de esta a aquella . Sin embargo, a veces puede usarse como un truco (un poco sucio) de programacion , ya que primero se realiza la asignación y luego se evalúa el resultado de esta para realizar el IF , es entonces equivalente a escribir :
a = b ;
if(a) .................... con el ahorro de una linea de programa ( a costa de la legibilidad del mismo ).
En casos más complejos que los anteriores, la proposición IF puede estar seguida por un bloque de sentencias :
if(expresión) if(expresión) {
{ sentencia 1 ;
sentencia 1 ; sentencia 2 ;
sentencia 2 ; ...............
............. }
}
Las dos maneras son equivalentes, por lo que la posición de la llave de apertura del bloque queda librada al gusto del programador. El indentado de las sentencias (sangría) es también optativo, pero sumamente recomendable ,sobre todo para permitir la lectura de proposiciones muy complejas ó anidadas , como se verá luego. El bloque se ejecutará en su conjunto si la expresión resulta CIERTA. El uso del ELSE es optativo, y su aplicación resulta en la ejecución de una , ó una serie de sentencias en el caso de que la expresión del IF resulta FALSA.
Su aplicación puede verse en el ejemplo siguiente :
if(expresión) if(expresión)
{ {
sentencia 1 ; sentencia 1 ;
sentencia 2 ; sentencia 2 ;
} }
sentencia 3 ; else
sentencia 4 ; {
sentencia 5 ; sentencia 3 ;
sentencia 4 ;
}
sentencia 5 ;
En el ejemplo de la izquierda no se usa el ELSE y por lo tanto las sentencias 3, 4 y 5 se ejecutan siempre.
En el segundo caso , las sentencias 1 y 2 se ejecutan solo si la expresión es CIERTA , en ese caso las 3 y 4 NO se ejecutarán para saltarse directamente a la 5 , en el caso de que la expresión resulte FALSA se realizarán las 3 y 4 en lugar de las dos primeras y finalmente la 5 .
La proposición ELSE queda siempre asociada al IF más cercano, arriba de él .
Es común también, en caso de decisiones múltiples, el uso de anidamientos ELSE-IF de la forma indicada abajo:
if(exp.1) if(exp.1)
sentencia1 ; sentencia1 ;
else if(exp.2) else if(exp.2)
sentencia2 ; sentencia2 ;
else if(exp.3) else if(exp.3)
sentencia3 ; sentencia3 ;
else else
sentencia5 ; sentencia5 ;
Si bien se suele escribir según la modalidad de la izquierda , a la derecha hemos expresado las asociaciones entre los distintos ELSE é IF por medio del indentado del texto.
Proposición switch
El SWITCH es una forma sencilla de evitar largos, tediosos y confusos anidamientos de ELSE-IF .
Supongamos que estamos implementando un Menú, con varias elecciones posibles. El esqueleto de una posible solución al problema usando if-else podría ser el siguiente:
________________________________________
#include <<stdio.h>>
main()
{
int c ;
printf("nMENU :"
;
printf("n A = ADICIONAR A LA LISTA "
;
printf("n B = BORRAR DE LA LISTA "
;
printf("n O = ORDENAR LA LISTA "
;
printf("n I = IMPRIMIR LA LISTA "
;
printf("nnESCRIBA SU SELECCION , Y LUEGO <<ENTER>> : "
;
if( (c = getchar()) != 'n' )
{
if( c == 'A')
printf("nUD. SELECCIONO AGREGAR"
;
else
if( c == 'B')
printf("nUD. SELECCIONO BORRAR"
;
else
if( c == 'O' )
printf("nUD. SELECCIONO ORDENAR"
;
else
if( c == 'I' )
printf("nUD. SELECCIONO IMPRIMIR"
;
else
printf("naaUD. APRETO UN CARACTER ILEGAL" ) ;
}
else
printf("n¡ UD. NO HA SELECCIONADO NADA !" ) ;
}
Como es fácil de ver, cuando las opciones son muchas, el texto comienza a hacerse difícil de entender y engorroso de escribir.
El mismo programa, utilizando un SWITCH, quedaría mucho más claro de leer, y sencillo de escribir, como se aprecia en el EJEMPLO siguiente.
#include <stdio.h>
#include <conio.h>
main()
{
int c ;
printf("nMENU :"
;
printf("n A = ADICIONAR A LA LISTA "
;
printf("n B = BORRAR DE LA LISTA "
;
printf("n O = ORDENAR LA LISTA "
;
printf("n I = IMPRIMIR LA LISTA "
;
printf("nnESCRIBA SU SELECCION , Y LUEGO <<ENTER>> : "
;
c = getchar() ;
switch (c)
{
case 'A' :
printf("nUD. SELECCIONO AGREGAR"
;
break ;
case 'B' :
printf("nUD. SELECCIONO BORRAR"
;
break ;
case 'O' :
printf("nUD. SELECCIONO ORDENAR"
;
break ;
case 'I' :
printf("nUD. SELECCIONO IMPRIMIR"
;
break ;
case 'n':
printf("n¡ UD. NO HA SELECCIONADO NADA !" ) ;
break ;
default :
printf("naaUD. APRETO UN CARACTER ILEGAL" ) ;
break ;
}
}
________________________________________
El SWITCH empieza con la sentencia: switch (expresión) . La expresión contenida por los paréntesis debe ser ENTERA, en nuestro caso un carácter; luego mediante una llave abre el bloque de las sentencias de comparación. Cada una de ellas se representa por la palabra clave "case" seguida por el valor de comparación y terminada por dos puntos. Seguidamente se ubican las sentencias que se quieren ejecutar , en el caso que la comparación resulte CIERTA . En el caso de resultar FALSA, se realizará la siguiente comparación , y así sucesivamente .
Prestemos atención también a la sentencia BREAK con la que se termina cada CASE. Una característica poco obvia del SWITCH, es que si se eliminan los BREAK del programa anterior , al resultar CIERTA una sentencia de comparación, se ejecutarán las sentencias de ese CASE particular pero TAMBIEN la de todos los CASE por debajo del que ha resultado verdadero. Quizás se aclare esto diciendo que , las sentencias propias de un CASE se ejecutarán si su comparación ú otra comparación ANTERIOR resulta CIERTA . La razón para este poco "juicioso" comportamiento del SWITCH es que así se permite que varias comparaciones compartan las mismas sentencias de programa, por ejemplo :
.................
case 'X' :
case 'Y' :
case 'Z' :
printf(" UD. ESCRIBIO X , Y , ó Z "
;
break ;
..................
La forma de interrumpir la ejecución luego de haber encontrado un CASE cierto es por medio del BREAK, el que dá por terminado el SWITCH .
Al final del bloque de sentencias del SWITCH , aparece una optativa llamada DEFAULT , que implica : si no se ha cumplido ningún CASE , ejecute lo que sigue. Es algo superfluo poner el BREAK en este caso , ya que no hay más sentencias después del DEFAULT , sin embargo , como el orden en que aparecen las comparaciones no tiene importancia para la ejecución de la instrucción, puede suceder que en futuras correcciones del programa se agregue algún nuevo CASE luego del DEFAULT , por lo que es conveniente preverlo , agregando el BREAK , para evitar errores de laboriosa ubicación .
Más adelante volveremos sobre otros usos del BREAK.
INSTRUCCIONES DE REPETICIÓN: FIJA Y CONDICIONAL
La mayoría de programas requieren que una determinada cantidad de instrucciones se ejecuten más de una vez. Hasta el momento la única forma de hacerlo sería o copiándolas varias veces, las instrucciones, o copiarlas dentro de una función e invocarla repetidamente. La instrucción Mientras(while) soluciona este problema, permitiendo ejecutar reiteradamente iteraciones (ciclos, bucles, lazos, rizos). De esta forma será posible "devolvernos" en la secuencia lógica del algoritmo.
La Iteración While
El WHILE es una de las tres iteraciones posibles en C . Su sintaxis podría expresarse de la siguiente forma :
while(expresion) ó while(expresión) {
proposición 1 ; proposición 1 ;
proposición 2 ;
...............
proposición n ;
}
Esta sintaxis expresada en palabras significaría: mientras (expresión) dé un resultado CIERTO ejecútese la proposición 1 , en el caso de la izquierda ó ejecútese el bloque de sentencias , en el caso de la derecha.
Por lo general , dentro de la proposición ó del bloque de ellas , se modifican términos de la expresión condicional , para controlar la duración de la iteración .
La Iteración Do - While
Su sintaxis será :
do {
proposición 1 ;
proposición 2 ;
...............
} while (expresión) ;
Expresado en palabras , esto significa : ejecute las proposiciones , luego repita la ejecución mientras la expresión dé un resultado CIERTO . La diferencia fundamental entre esta iteración y la anterior es que el DO-WHILE se ejecuta siempre AL MENOS una vez , sea cual sea el resultado de expresión.
Iteración For
El FOR es simplemente una manera abreviada de expresar un WHILE , veamos su sintaxis :
for ( expresión1 ; expresión2 ; expresion3 ) {
proposición1 ;
proposición2 ;
..............
}
Esto es equivalente a :
expresión1 ;
while ( expresión2 ) {
proposición1 ;
proposición2 ;
..............
expresion3 ;
}
La expresión1 es una asignación de una ó más variables , (equivale a una inicialización de las mismas ) , la expresión2 es una relación de algún tipo que , mientras dé un valor CIERTO , permite la iteración de la ejecución y expresión3 es otra asignación , que comúnmente varía alguna de las variables contenida en expresión2 .
Todas estas expresiones , contenidas en el paréntesis del FOR deben estar separadas por PUNTO Y COMA y NO por comas simples .
No es imprescindible que existan TODAS las expresiones dentro del paréntesis del FOR , pudiéndose dejar en blanco algunas de ellas , por ejemplo :
for ( ; exp2 ; exp3) ó
for (exp1 ; ; ) ó
for ( ; ; )
Estas dos últimas expresiones son interesantes desde el punto de vista de su falta de término relacional , lo que implica que el programador deberá haber previsto alguna manera alternativa de salir del lazo ( probablemente mediante BREAK ó RETURN como veremos más adelante ) ya que sino , la ejecución del mismo es infinita ( ó tan larga como se mantenga encendida la computadora ) .
APLICACIÓN DE ANIDAMIENTO DE INSTRUCCIONES
Explicado y ejemplificado en los dos puntos anteriores
Operadores De Asignación
En principio puede resultar algo futil gastar papel en describir al operador IGUAL A ( = ) , sin embargo es necesario remarcar ciertas características del mismo .
Anteriormente definimos a una asignación como la copia del resultado de una expresión ( rvalue ) sobre otra ( lvalue ) , esto implica que dicho lvalue debe tener LUGAR (es decir poseer una posición de memoria ) para alojar dicho valor .
Es por lo tanto válido escribir a = 17;
pero no es aceptado , en cambio
17 = a; /* incorrecto */
ya que la constante numérica 17 no posee una ubicación de memoria donde alojar al valor de a .
Aunque parezca un poco extraño al principio las asignaciones, al igual que las otras operaciones , dan un resultado que puede asignarse a su vez a otra expresión .
De la misma forma que (a + b) es evaluada y su resultado puedo copiarlo en otra variable : c = (a + b) ; una asignación (a = b) da como resultado el valor de b , por lo que es lícito escribir
c = ( a = b ) ;
Debido a que las asignaciones se evalúan de derecha a izquierda , los paréntesis son superfluos , y podrá escribirse entonces :
c = a = b = 17;
con lo que las tres variables resultarán iguales al valor de la constante .
El hecho de que estas operaciones se realicen de derecha a izquierda también permite realizar instrucciones del tipo :
a = a + 17 ;
Significando esto que al valor que TENIA anteriormente a , se le suma la constante y LUEGO se copia el resultado en la variable .
Como este último tipo de operaciones es por demás común , existe en C un pseudocódigo , con el fín de abreviarlas .
Así una operación aritmética o de bit cualquiera (simbolizada por OP )
a = (a) OP (b) ;
Puede escribirse en forma abreviada como:
a OP= b ;
Por ejemplo a += b ; /* equivale : a = a + b */
a -= b ; /* equivale : a = a - b */
a *= b ; /* equivale : a = a * b */
a /= b ; /* equivale : a = a / b */
a %= b ; /* equivale : a = a % b */
Nótese que el pseudooperador debe escribirse con los dos símbolos seguidos , por ejemplo += , y no será aceptado +(espacio) = .
Los operadores de asignación están resumidos en la TABLA.
Tabla de Operadores de Asignación
Símbolo Descripción Ejemplo Orden De Evaluación
= igual a a = b 13
op= pseudocodigo a += b 13
=?: asig.condicional a = (c>b)?d:e 12
Vemos de la tabla anterior que aparece otro operador denominado ASIGNACION CONDICIONAL . El significado del mismo es el siguiente : lvalue = ( operación relacional ó logica ) ? (rvalue 1) : (rvalue 2) ;
de acuerdo al resultado de la operación condicional se asignará a lvalue el valor de rvalue 1 ó 2 . Si aquella es CIERTA será lvalue = rvalue 1 y si diera FALSO , lvalue = rvalue 2 .
Por ejemplo, si quisiéramos asignar a c el menor de los valores a ó b , bastará con escribir :
c = ( a < b ) ? a : b ;
EXPRESIONES Y EVALUACIÓN DE OPERACIONES
Orden de prioridad de operadores aritméticos
Multiplicativos
* Multiplicación
/ División
% Resto en división entera
Unarios
! Negación lógica (NOT)
~ Complemento en binario
+ Más
Menos
++ Preincremento o postincremento
Predecremento o postdecrement
& Dirección
* Valor en la dirección de
sizeof Tamaño del operando en bytes
new Espacio en memoria dinámica
delete Desasigna espacio en memoria
Prioridad
*
/
%
+
-
Evaluación secuencial de expresiones aritméticas
65.0 / 2
32.5 65 / 2
32 65 % 2
1
5 + 3 * 3 - 4 + 12 * 10 5 + 9 - 4 + 120
14 - 4 + 120
10 + 120
130 6 + 9 * 8 / 2 * 4 - 2 * 3
6 + 72 / 2 * 4 - 2 * 3
6 + 36 * 4 - 2 * 3
6 + 144 - 2 * 3
6 + 144 - 6
150 - 6
144 (63 -20) /(35 -15)
43 / 20
2
(63 -20.0) /(35 -15)
43.0 / 20
2.0
4.2 / 2 + 3.9 / 3
2.1 + 3.9 / 3
2.1 + 1.3
4.4 3 + sqrt(8 % 6 * 10 / 5)
3 + sqrt( 2 * 10 / 5)
3 + sqrt(20 / 5)
3 + sqrt(4)
3 + 2
5 (60 - 20) /35.0 -15
40 /35.0 - 15
1.142 - 15
-13.858
ESTRUCTURA DE UN PROGRAMA
Anatomia de un Programa C
Siguiendo la tradición, la mejor forma de aprender a programar en cualquier lenguaje es editar, compilar, corregir y ejecutar pequeños programas descriptivos. Analicemos por lo tanto el primer ejemplo.
EJEMPLO 1
#include <stdio.h>
main()
{
printf("Bienvenido a la Programación en lenguaje C n"

;
return 0;
}
Función Main()
Dejemos de lado por el momento el análisis de la primer línea del programa, y pasemos a la segunda.
La función main() indica donde empieza el programa, cuyo cuerpo principal es un conjunto de sentencias delimitadas por dos llaves, una inmediatamente después de la declaración main() " { ", y otra que finaliza el listado " } ". Todos los programas C arrancan del mismo punto: la primer sentencia dentro de dicha función, en este caso printf ("......"

.
En el EJEMPLO 1 el programa principal está compuesto por sólo dos sentencias: la primera es un llamado a una función denominada printf(), y la segunda, return, que finaliza el programa retornando al Sistema Operativo.
Recuérdese que el lenguaje C no tiene operadores de entrada-salida por lo que para escribir en video es necesario llamar a una función externa. En este caso se invoca a la función printf(argumento) existente en la Librería y a la cual se le envía como argumento aquellos caracteres que se desean escribir en la pantalla. Los mismos deben estar delimitados por comillas.
La secuencia n que aparece al final del mensaje es la notación que emplea C para el carácter "nueva línea" que hace avanzar al cursor a la posición extrema izquierda de la línea siguiente. Más adelante analizaremos otras secuencias de escape habituales.
La segunda sentencia (return 0) termina el programa y devuelve un valor al Sistema operativo, por lo general cero si la ejecución fue correcta y valores distintos de cero para indicar diversos errores que pudieron ocurrir. Si bien no es obligatorio terminar el programa con un return, es conveniente indicarle a quien lo haya invocado, sea el Sistema Operativo o algún otro programa, si la finalización ha sido exitosa, o no. De cualquier manera en este caso, si sacamos esa sentencia el programa correrá exactamente igual, pero al ser compilado, el compilador nos advertirá de la falta de retorno.
Cada sentencia de programa queda finalizada por el terminador "; ", el que indica al compilador el fin de la misma. Esto es necesario ya que, sentencias complejas pueden llegar a tener más de un renglón, y habrá que avisarle al compilador donde terminan.
Es perfectamente lícito escribir cualquier sentencia abarcando los renglones que la misma necesite, por ejemplo podría ser:
printf("Bienvenido a la Programación"
"en lenguaje C n"

;
Encabezamiento
Las líneas anteriores a la función main() se denominan ENCABEZAMIENTO (HEADER) y son informaciones que se le suministran al Compilador.
La primera línea del programa está compuesta por una directiva: " #include " que implica la orden de leer un archivo de texto especificado en el nombre que sigue a la misma ( <stdio.h> ) y reemplazar esta línea por el contenido de dicho archivo.
En este archivo están incluidas declaraciones de las funciones luego llamadas por el programa (por ejemplo printf() ) necesarias para que el compilador las procese. Por ahora no nos preocupemos por el contenido del archivo ya que más adelante, en el capítulo de funciones, analizaremos exhaustivamente dichas declaraciones.
Hay dos formas distintas de invocar al archivo, a saber, si el archivo invocado está delimitado por comillas (por ejemplo "stdio.h"

el compilador lo buscará en el directorio activo en el momento de compilar y si en cambio se lo delimita con los signos <.......> lo buscará en algun otro directorio, cuyo nombre habitualmente se le suministra en el momento de la instalación del compilador en el disco ( por ejemplo C:TCINCLUDE). Por lo general estos archivos son guardados en un directorio llamado INCLUDE y el nombre de los mismos está terminado con la extensión .h.
La razón de la existencia de estos archivos es la de evitar la repetición de la escritura de largas definiciones en cada programa.
Nótese que la directiva "#include" no es una sentencia de programa sino una orden de que se copie literalmente un archivo de texto en el lugar en que ella está ubicada ,por lo que no es necesario terminarla con "; ".
Para optimizar el código producido, los lenguajes en general y como parte de la máxima "Divide y Vencerás", colocan una serie de utilidades(funciones, tipos de datos, variables, etc.) en archivos separados, los cuales de pueden utilizar como si estuvieran en el programa que estamos diseñando.
El C/C++ en particular trae una gran cantidad de archivos a incluir por medio de la directiva del compilador #include, la cual debe ser colocada preferiblemente al inicio del programa y siempre por fuera del ámbito de las funciones.
Los archivos a incluir en el turbo C++ los puede encontrar en el nivel de ayuda del editor. Los siguientes serán los utilizados en el presente manual, y con esta sintaxis:
#include <iostream.h> #include <conio.h> #include <string.h>
#include <iomanip.h> #include <dos.h> #include <stdlib.h>
#include <stdio.h> #include <math.h> #include <values.h>
#include <ctype.h> #include <graphics.h> #include <fstream.h>
Separadores de Instrucciones
Cada lenguaje utiliza alguna convención para separar las diferentes instrucciones del mismo; en el lenguaje C el separador es el símbolo de punto y coma ;. Se debe colocar el punto y coma al final de cada instrucción (statement). En C/C++ el punto y coma marca el fin de una instrucción, es decir es su terminador. Se exceptúan las instrucciones del preprocesador (define, include, etc.), las cuales no llevan punto y coma al final.
En tiempo de compilación el "compilador" revisará la sintaxis de las diferentes instrucciones y en caso de encontrar alguna con terminador inadecuado, esto es sin punto y coma, dará un error de sintaxis: " ; expected", es decir que esperaba un punto y coma y encontró otro carácter, en general este otro caracter lo encuentra en la instrucción siguiente, donde marcará el error y confundiendo al recién iniciado. Observe los punto y comas en los programas presentados en este capítulo.
Comentarios
La inclusión de comentarios en un programa es una saludable práctica, como lo reconocerá cualquiera que haya tratado de leer un listado hecho por otro programador ó por sí mismo, varios meses atrás. Para el compilador, los comentarios son inexistentes, por lo que no generan lineas de código, permitiendo abundar en ellos tanto como se desee.
En el lenguaje C se toma como comentario todo caracter interno a los símbolos: /* */ . Los comentarios pueden ocupar uno o más renglones, por ejemplo:
/* este es un comentario corto */
/* este otro
es mucho
más largo
que el anterior */
Todo caracter dentro de los símbolos delimitadores es tomado como comentario incluyendo a " * " ó " ( " , etc.
Operaciones de Entrada/Salida
Un programa para que pueda trabajar, entre otras cosas, debe poder operar los datos que se proporcionan mediante un dispositivo de entrada y poder enviar los resultados después de procesados con la ayuda de un algoritmo a un dispositivo de salida. En la forma estándar o por defecto (default) el dispositivo de entrada será el teclado y el dispositivo de salida la pantalla o monitor.
Instrucción de Escritura En Pantalla
Para transferir valores de constantes, variables, expresiones algebraicas, o expresiones delimitadas como cadenas de caracteres de la memoria del computador a la pantalla, emplearemos la instrucción Printf() , en su forma por defecto, y la cual se encuentra en el archivo a incluir sodio.h. También se utiliza puts() para las cadenas de caracteres.
Para lograr ejecutar un programa se deberán utilizar varias secuencias de teclas, las principales a necesitar e ir "memorizando" son las contenidas en la siguiente Tabla:
Secuencias de teclas más utilizadas.
Tecla Orden Del Menú
F1 Ayuda del editor
F2 Grabar en disco
F3 Cargar desde disco
F4 Ejecutar programa hasta el cursor
F5 Hace zoom en la ventana activa
F6 Cambia de ventana activa
F7 Rastreo del programa con llamado de funciones
F8 Rastreo del programa saltando funciones
F9 Compila y enlaza el programa
F10 Activa el menú principal
F10 File New Comenzar un programa nuevo
F10 File Change Dir Cambiar directorio actual
F10 Window Close All Cerrar todas las ventanas
F10 Help Index Índice alfabético de ayuda
CTRL + F8 Marca punto en el cual detenerse ejecución
CTRL + F9 Compilar y ejecutar(correr)
CTRL + Y Borrar una línea
CTRL + T Borrar una palabra o espacios
Shift + Teclas Mover Marcar bloque
Shift + Del Borrar bloque marcado
Shift + Ins Restaurar bloque borrado
CTRL + KV Mover bloque marcado
CTRL + KC Copiar bloque marcado
CTRL + KR Leer un archivo como bloque
CTRL + KW Grabar un bloque como archivo
CTRL + KP Imprimir bloque marcado
ALT + 0 Lista ventanas abiertas
ALT + 1 al 9 Activa ventana 1 al 9
ALT + F1 Pantalla ayuda anterior
ALT + F3 Elimina ventana activa
ALT + F4 Abre ventana de depuración
ALT + F5 Cambia a ventana de ejecución del programa
ALT + F7 Error anterior
ALT + F8 Error siguiente
ALT + F9 Compilar a archivo .OBJ
ALT + X Salir(eXit) del editor del C++
Cuerpo del Programa
Los programas en C/C++ deberán estar compuestos de al menos una función, la función main(), sin esta el programa no trabajará por sí solo. Cada función del programa, consta de la secuencia de instrucciones o algoritmo que la computadora deberá realizar.
El algoritmo debe incluir identificadores, operadores y palabras claves. Todo algoritmo se desarrollará con tres tipos de instrucciones: Secuenciales, Selectivas y Repetitivas; el entendimiento de estas tres es el objetivo principal de este curso.
De esta forma el algoritmo es simplemente la secuencia de pasos que interpretan un problema específico, en algún campo del saber, y que la computadora podrá ejecutar y de esta forma nosotros obtener los resultados deseados.
El C++ es un lenguaje de formato libre. Los espacios en blanco adicionales y los caracteres de salto de línea no son relevantes para el compilador, excepto cuando se requieren para conservar identificadores y las palabras claves o dentro de variables de tipo de cadena. Las líneas del programa pueden tener una longitud máxima de hasta 127 caracteres, siendo preferible utilizar menos de los primeros 80 por motivos de presentación en las impresiones del código fuente. Recordar que la pantalla tiene en modo de texto 80 columnas.
PROCESO DE CREACIÓN Y EJECUCIÓN DE UN PROGRAMA
Probablemente este es el lugar más adecuado para explicar cómo se obtiene un fichero ejecutable a partir de un programa C++.
Para empezar necesitamos un poco de vocabulario técnico. Veremos algunos conceptos que se manejan frecuentemente en cualquier curso de programación y sobre todo en manuales de C y C++.
Fichero fuente y programa o código Los programas C y C++ se escriben con la ayuda de un editor de textos del mismo modo que cualquier texto corriente. Los ficheros que contiene programas en C o C++ en forma de texto se conocen como ficheros fuente, y el texto del programa que contiene se conoce como programa fuente. Nosotros siempre escribiremos programas fuente y los guardaremos en ficheros fuente.
Ficheros objeto, código objeto y compiladores:
Los programas fuente no pueden ejecutarse. Son ficheros de texto, pensados para que los comprendan los seres humanos, pero incomprensibles para los ordenadores.
Para conseguir un programa ejecutable hay que seguir algunos pasos. El primero es compilar o traducir el programa fuente a su código objeto equivalente. Este es el trabajo que hacen los compiladores de C y C++. Consiste en obtener un fichero equivalente a nuestro programa fuente comprensible para el ordenador, este fichero se conoce como fichero objeto, y su contenido como código objeto.
Los compiladores son programas que leen un fichero de texto que contiene el programa fuente y generan un fichero que contiene el código objeto.
El código objeto no tiene ningún significado para los seres humanos, al menos no directamente. Además es diferente para cada ordenador y para cada sistema operativo. Por lo tanto existen diferentes compiladores para diferentes sistemas operativos y para cada tipo de ordenador.
Librerías:
Junto con los compiladores de C y C++, se incluyen ciertos ficheros llamados librerías. Las librerías contienen el código objeto de muchos programas que permiten hacer cosas comunes, como leer el teclado, escribir en la pantalla, manejar números, realizar funciones matemáticas, etc. Las librerías están clasificadas por el tipo de trabajos que hacen, hay librerías de entrada y salida, matemáticas, de manejo de memoria, de manejo de textos, etc.
Hay un conjunto de librerías muy especiales, que se incluyen con todos los compiladores de C y de C++. Son las librerías ANSI o estándar. Pero también hay librerías no estándar, y dentro de estas las hay públicas y comerciales. En este curso sólo usaremos librerías ANSI.
Ficheros ejecutables y enlazadores:
Cuando obtenemos el fichero objeto, aún no hemos terminado el proceso. El fichero objeto, a pesar de ser comprensible para el ordenador, no puede ser ejecutado. Hay varias razones para eso:
1. Nuestros programas usaran, en general, funciones que estarán incluidas en librerías externas, ya sean ANSI o no. Es necesario combinar nuestro fichero objeto con esas librerías para obtener un ejecutable.
2. Muy a menudo, nuestros programas estarán compuestos por varios ficheros fuente, y de cada uno de ellos se obtendrá un fichero objeto. Es necesario unir todos los ficheros objeto, más las librerías en un único fichero ejecutable.
3. Hay que dar ciertas instrucciones al ordenador para que cargue en memoria el programa y los datos, y para que organice la memoria de modo que se disponga de una pila de tamaño adecuado, etc. La pila es una zona de memoria que se usa para que el programa intercambie datos con otros programas o con otras partes del propio programa. Veremos esto con más detalle durante el curso.
Existe un programa que hace todas estas cosas, se trata del "link", o enlazador. El enlazador toma todos los ficheros objeto que componen nuestro programa, los combina con los ficheros de librería que sea necesario y crea un fichero ejecutable.
Una vez terminada la fase de enlazado, ya podremos ejecutar nuestro programa.
Errores
Por supuesto, somos humanos, y por lo tanto nos equivocamos. Los errores de programación pueden clasificarse en varios tipos, dependiendo de la fase en que se presenten.
Errores de sintaxis: son errores en el programa fuente. Pueden deberse a palabras reservadas mal escritas, expresiones erróneas o incompletas, variables que no existen, etc. Los errores de sintaxis se detectan en la fase de compilación. El compilador, además de generar el código objeto, nos dará una lista de errores de sintaxis. De hecho nos dará sólo una cosa o la otra, ya que si hay errores no es posible generar un código objeto.
Avisos: además de errores, el compilador puede dar también avisos (warnings). Los avisos son errores, pero no lo suficientemente graves como para impedir la generación del código objeto. No obstante, es importante corregir estos avisos, ya que el compilador tiene que decidir entre varias opciones, y sus decisiones no tienen por qué coincidir con lo que nosotros pretendemos, se basan en las directivas que los creadores del compilador decidieron durante su creación.
Errores de enlazado: el programa enlazador también puede encontrar errores. Normalmente se refieren a funciones que no están definidas en ninguno de los ficheros objetos ni en las librerías. Puede que hayamos olvidado incluir alguna librería, o algún fichero objeto, o puede que hayamos olvidado definir alguna función o variable, o lo hayamos hecho mal.
Errores de ejecución: incluso después de obtener un fichero ejecutable, es posible que se produzcan errores. En el caso de los errores de ejecución normalmente no obtendremos mensajes de error, sino que simplemente el programa terminará bruscamente. Estos errores son más difíciles de detectar y corregir. Existen programas auxiliares para buscar estos errores, son los llamados depuradores (debuggers). Estos programas permiten detener la ejecución de nuestros programas, inspeccionar variables y ejecutar nuestro programa paso a paso. Esto resulta útil para detectar excepciones, errores sutiles, y fallos que se presentan dependiendo de circunstancias distintas.
Errores de diseño: finalmente los errores más difíciles de corregir y prevenir. Si nos hemos equivocado al diseñar nuestro algoritmo, no habrá ningún programa que nos pueda ayudar a corregir los nuestros. Contra estos errores sólo cabe practicar y pensar.
UNIDAD II
INSTRUCCIONES FUNDAMENTALES (DE CONTROL)
INSTRUCCIONES DE ENTRADA Y SALIDA DE DATOS
Operaciones de Entrada/Salida
Un programa para que pueda trabajar, entre otras cosas, debe poder operar los datos que se proporcionan mediante un dispositivo de entrada y poder enviar los resultados después de procesados con la ayuda de un algoritmo a un dispositivo de salida. En la forma estándar o por defecto (default) el dispositivo de entrada será el teclado y el dispositivo de salida la pantalla o monitor.
Instrucción de Escritura en Pantalla
Para transferir valores de constantes, variables, expresiones algebraicas, o expresiones delimitadas como cadenas de caracteres de la memoria del computador a la pantalla, emplearemos la instrucción printf() , en su forma por defecto, y la cual se encuentra en el archivo a incluir stdio.h. También se utiliza puts() para las cadenas de caracteres.
Printf(“Texto y/o formato de salida”,variable o constante);
Printf(“Texto y/o formato de salida”,variable o constante);
Printf(“Texto y/o formato de salida”,operación aritmética);
Printf(“Texto”);
Printf(“Texto y/o formato de salida”,operación lógica)
Printf(“Estado civil: “);
Printf(“Salario: %d”, sal);
Printf(“%d”,a>b);
Printf(“%f”,123*23);
Printf(“Francisco tiene %d años y Pedro %d”,ed1,ed2);
Puts(“texto”);
Puts(variable cadena);
Puts(concatenación);
Puts(“Nombre: “);
Puts(“Reprobado”);
Puts(Ed);
Puts(a+b+”hola”);
Instrucción de Lectura
Para leer y almacenar valores a la memoria del computador, emplearemos la instrucción scanf() , en su forma por defecto, y la cual se encuentra en el archivo a incluir stdio.h. También se utiliza gets() para las cadenas de caracteres.
Scanf(“formato”,&variable);
Scanf(“formatos”,&var1,&var2…,&varn);
Scanf(“%d”,&ed);
Scanf(“%d %d %d”,&a,&b,&c);
Scanf(“%f”,&sal);
Scanf(“%s”,&nom);
Gets(variable cadena);
Gets(nom);
INSTRUCCIONES DE SELECCIÓN: SIMPLES Y ANIDADAS
Todo algoritmo se desarrollará con tres tipos de instrucciones: Secuenciales, Selectivas y Repetitivas; el entendimiento de estas tres es el objetivo principal de este curso.
Proposición If - Else
Esta proposición sirve para ejecutar ciertas sentencias de programa, si una expresión resulta CIERTA ú otro grupo de sentencias, si aquella resulta FALSA. Su interpretación literal sería: SI es CIERTA tal cosa, haga esto (la o las sentencias) , si no lo es saltará a la siguiente instrucción.
El caso más sencillo sería :
if(expresión)
sentencia ;
ó
if(expresión) sentencia ;
Cuando la sentencia que sigue al IF es única, las dos formas de escritura expresadas arriba son equivalentes . La sentencia sólo se ejecutará si el resultado de "expresión" es distinto de cero (CIERTO) , en caso contrario el programa salteará dicha sentencia , realizando la siguiente en su flujo.
Veamos unos ejemplos de las distintas formas que puede adoptar la "expresión" dentro de un IF :
if( a > b ) if( (a > b) != 0 ) las dos expresiones son idénticas, aunque a veces resulta más claro expresarla de la segunda manera, sobre todo en los primeros contactos con el lenguaje.
if(a) if(a != 0)
if(!a) if(a == 0 ) Las dos superiores son idénticas entre sí , al igual que las dos inferiores Obsérvese que (!a) dará un valor CIERTO sólo cuando a sea FALSO. (ver operador NEGACION en el capítulo anterior )
if( a == b )
if( a = b ) /* Error */ La primera es una expresión correcta , el IF se realizará sólo si a es igual a b. En cambio la segunda es un error , ya que no se está comparando a con b , sino ASIGNANDO el valor de esta a aquella . Sin embargo, a veces puede usarse como un truco (un poco sucio) de programacion , ya que primero se realiza la asignación y luego se evalúa el resultado de esta para realizar el IF , es entonces equivalente a escribir :
a = b ;
if(a) .................... con el ahorro de una linea de programa ( a costa de la legibilidad del mismo ).
En casos más complejos que los anteriores, la proposición IF puede estar seguida por un bloque de sentencias :
if(expresión) if(expresión) {
{ sentencia 1 ;
sentencia 1 ; sentencia 2 ;
sentencia 2 ; ...............
............. }
}
Las dos maneras son equivalentes, por lo que la posición de la llave de apertura del bloque queda librada al gusto del programador. El indentado de las sentencias (sangría) es también optativo, pero sumamente recomendable ,sobre todo para permitir la lectura de proposiciones muy complejas ó anidadas , como se verá luego. El bloque se ejecutará en su conjunto si la expresión resulta CIERTA. El uso del ELSE es optativo, y su aplicación resulta en la ejecución de una , ó una serie de sentencias en el caso de que la expresión del IF resulta FALSA.
Su aplicación puede verse en el ejemplo siguiente :
if(expresión) if(expresión)
{ {
sentencia 1 ; sentencia 1 ;
sentencia 2 ; sentencia 2 ;
} }
sentencia 3 ; else
sentencia 4 ; {
sentencia 5 ; sentencia 3 ;
sentencia 4 ;
}
sentencia 5 ;
En el ejemplo de la izquierda no se usa el ELSE y por lo tanto las sentencias 3, 4 y 5 se ejecutan siempre.
En el segundo caso , las sentencias 1 y 2 se ejecutan solo si la expresión es CIERTA , en ese caso las 3 y 4 NO se ejecutarán para saltarse directamente a la 5 , en el caso de que la expresión resulte FALSA se realizarán las 3 y 4 en lugar de las dos primeras y finalmente la 5 .
La proposición ELSE queda siempre asociada al IF más cercano, arriba de él .
Es común también, en caso de decisiones múltiples, el uso de anidamientos ELSE-IF de la forma indicada abajo:
if(exp.1) if(exp.1)
sentencia1 ; sentencia1 ;
else if(exp.2) else if(exp.2)
sentencia2 ; sentencia2 ;
else if(exp.3) else if(exp.3)
sentencia3 ; sentencia3 ;
else else
sentencia5 ; sentencia5 ;
Si bien se suele escribir según la modalidad de la izquierda , a la derecha hemos expresado las asociaciones entre los distintos ELSE é IF por medio del indentado del texto.
Proposición switch
El SWITCH es una forma sencilla de evitar largos, tediosos y confusos anidamientos de ELSE-IF .
Supongamos que estamos implementando un Menú, con varias elecciones posibles. El esqueleto de una posible solución al problema usando if-else podría ser el siguiente:
________________________________________
#include <<stdio.h>>
main()
{
int c ;
printf("nMENU :"

;
printf("n A = ADICIONAR A LA LISTA "

;
printf("n B = BORRAR DE LA LISTA "

;
printf("n O = ORDENAR LA LISTA "

;
printf("n I = IMPRIMIR LA LISTA "

;
printf("nnESCRIBA SU SELECCION , Y LUEGO <<ENTER>> : "

;
if( (c = getchar()) != 'n' )
{
if( c == 'A')
printf("nUD. SELECCIONO AGREGAR"

;
else
if( c == 'B')
printf("nUD. SELECCIONO BORRAR"

;
else
if( c == 'O' )
printf("nUD. SELECCIONO ORDENAR"

;
else
if( c == 'I' )
printf("nUD. SELECCIONO IMPRIMIR"

;
else
printf("naaUD. APRETO UN CARACTER ILEGAL" ) ;
}
else
printf("n¡ UD. NO HA SELECCIONADO NADA !" ) ;
}
Como es fácil de ver, cuando las opciones son muchas, el texto comienza a hacerse difícil de entender y engorroso de escribir.
El mismo programa, utilizando un SWITCH, quedaría mucho más claro de leer, y sencillo de escribir, como se aprecia en el EJEMPLO siguiente.
#include <stdio.h>
#include <conio.h>
main()
{
int c ;
printf("nMENU :"

;
printf("n A = ADICIONAR A LA LISTA "

;
printf("n B = BORRAR DE LA LISTA "

;
printf("n O = ORDENAR LA LISTA "

;
printf("n I = IMPRIMIR LA LISTA "

;
printf("nnESCRIBA SU SELECCION , Y LUEGO <<ENTER>> : "

;
c = getchar() ;
switch (c)
{
case 'A' :
printf("nUD. SELECCIONO AGREGAR"

;
break ;
case 'B' :
printf("nUD. SELECCIONO BORRAR"

;
break ;
case 'O' :
printf("nUD. SELECCIONO ORDENAR"

;
break ;
case 'I' :
printf("nUD. SELECCIONO IMPRIMIR"

;
break ;
case 'n':
printf("n¡ UD. NO HA SELECCIONADO NADA !" ) ;
break ;
default :
printf("naaUD. APRETO UN CARACTER ILEGAL" ) ;
break ;
}
}
________________________________________
El SWITCH empieza con la sentencia: switch (expresión) . La expresión contenida por los paréntesis debe ser ENTERA, en nuestro caso un carácter; luego mediante una llave abre el bloque de las sentencias de comparación. Cada una de ellas se representa por la palabra clave "case" seguida por el valor de comparación y terminada por dos puntos. Seguidamente se ubican las sentencias que se quieren ejecutar , en el caso que la comparación resulte CIERTA . En el caso de resultar FALSA, se realizará la siguiente comparación , y así sucesivamente .
Prestemos atención también a la sentencia BREAK con la que se termina cada CASE. Una característica poco obvia del SWITCH, es que si se eliminan los BREAK del programa anterior , al resultar CIERTA una sentencia de comparación, se ejecutarán las sentencias de ese CASE particular pero TAMBIEN la de todos los CASE por debajo del que ha resultado verdadero. Quizás se aclare esto diciendo que , las sentencias propias de un CASE se ejecutarán si su comparación ú otra comparación ANTERIOR resulta CIERTA . La razón para este poco "juicioso" comportamiento del SWITCH es que así se permite que varias comparaciones compartan las mismas sentencias de programa, por ejemplo :
.................
case 'X' :
case 'Y' :
case 'Z' :
printf(" UD. ESCRIBIO X , Y , ó Z "

;
break ;
..................
La forma de interrumpir la ejecución luego de haber encontrado un CASE cierto es por medio del BREAK, el que dá por terminado el SWITCH .
Al final del bloque de sentencias del SWITCH , aparece una optativa llamada DEFAULT , que implica : si no se ha cumplido ningún CASE , ejecute lo que sigue. Es algo superfluo poner el BREAK en este caso , ya que no hay más sentencias después del DEFAULT , sin embargo , como el orden en que aparecen las comparaciones no tiene importancia para la ejecución de la instrucción, puede suceder que en futuras correcciones del programa se agregue algún nuevo CASE luego del DEFAULT , por lo que es conveniente preverlo , agregando el BREAK , para evitar errores de laboriosa ubicación .
Más adelante volveremos sobre otros usos del BREAK.
INSTRUCCIONES DE REPETICIÓN: FIJA Y CONDICIONAL
La mayoría de programas requieren que una determinada cantidad de instrucciones se ejecuten más de una vez. Hasta el momento la única forma de hacerlo sería o copiándolas varias veces, las instrucciones, o copiarlas dentro de una función e invocarla repetidamente. La instrucción Mientras(while) soluciona este problema, permitiendo ejecutar reiteradamente iteraciones (ciclos, bucles, lazos, rizos). De esta forma será posible "devolvernos" en la secuencia lógica del algoritmo.
La Iteración While
El WHILE es una de las tres iteraciones posibles en C . Su sintaxis podría expresarse de la siguiente forma :
while(expresion) ó while(expresión) {
proposición 1 ; proposición 1 ;
proposición 2 ;
...............
proposición n ;
}
Esta sintaxis expresada en palabras significaría: mientras (expresión) dé un resultado CIERTO ejecútese la proposición 1 , en el caso de la izquierda ó ejecútese el bloque de sentencias , en el caso de la derecha.
Por lo general , dentro de la proposición ó del bloque de ellas , se modifican términos de la expresión condicional , para controlar la duración de la iteración .
La Iteración Do - While
Su sintaxis será :
do {
proposición 1 ;
proposición 2 ;
...............
} while (expresión) ;
Expresado en palabras , esto significa : ejecute las proposiciones , luego repita la ejecución mientras la expresión dé un resultado CIERTO . La diferencia fundamental entre esta iteración y la anterior es que el DO-WHILE se ejecuta siempre AL MENOS una vez , sea cual sea el resultado de expresión.
Iteración For
El FOR es simplemente una manera abreviada de expresar un WHILE , veamos su sintaxis :
for ( expresión1 ; expresión2 ; expresion3 ) {
proposición1 ;
proposición2 ;
..............
}
Esto es equivalente a :
expresión1 ;
while ( expresión2 ) {
proposición1 ;
proposición2 ;
..............
expresion3 ;
}
La expresión1 es una asignación de una ó más variables , (equivale a una inicialización de las mismas ) , la expresión2 es una relación de algún tipo que , mientras dé un valor CIERTO , permite la iteración de la ejecución y expresión3 es otra asignación , que comúnmente varía alguna de las variables contenida en expresión2 .
Todas estas expresiones , contenidas en el paréntesis del FOR deben estar separadas por PUNTO Y COMA y NO por comas simples .
No es imprescindible que existan TODAS las expresiones dentro del paréntesis del FOR , pudiéndose dejar en blanco algunas de ellas , por ejemplo :
for ( ; exp2 ; exp3) ó
for (exp1 ; ; ) ó
for ( ; ; )
Estas dos últimas expresiones son interesantes desde el punto de vista de su falta de término relacional , lo que implica que el programador deberá haber previsto alguna manera alternativa de salir del lazo ( probablemente mediante BREAK ó RETURN como veremos más adelante ) ya que sino , la ejecución del mismo es infinita ( ó tan larga como se mantenga encendida la computadora ) .
APLICACIÓN DE ANIDAMIENTO DE INSTRUCCIONES
Explicado y ejemplificado en los dos puntos anteriores