apuntes básicos en c y java 2011

141
Programación básica en C y Java (elaboró: José Luis López Goytia) 1 / 141 PROGRAMACIÓN BÁSICA EN C Y JAVA José Luis López Goytia (elaboración: 2010; última revisión: 2011) TEMA PÁG. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 Aspectos metodológicos 1. Criterios de calidad del software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2. Pruebas de caja negra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 3. Ciclo de desarrollo de sistemas (método de cascada) . . . . . . . . . . . . . . . . . . . . . 12 4. Concepto de compilador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 Programando en lenguaje C 5. Un primer acercamiento al desarrollo de software . . . . . . . . . . . . . . . . . . . . . . . . . 25 6. El paradigma de la programación estructurada . . . . . . . . . . . . . . . . . . . . . . . . . . 40 7. Los primeros elementos para codificar en lenguaje C . . . . . . . . . . . . . . . . . . . . . . 51 8. Condicionales en lenguaje C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 9. Ciclos en lenguaje C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 10. Arreglos en lenguaje C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 11. Subrutinas en lenguaje C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 12. Apuntadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 Programando en Java 13. Enfoque de la programación orientada a objetos . . . . . . . . . . . . . . . . . . . 96 14. ¿Cómo funciona Java? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 15. Creación de una clase sencilla en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 16. El uso de múltiples clases en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 17. Arreglos en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 18. Herencia y polimorfismo en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 19. Composición en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 Bibliografía . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

Upload: princessbberry

Post on 01-Dec-2015

138 views

Category:

Documents


1 download

TRANSCRIPT

Programación básica en C y Java (elaboró: José Luis López Goytia) 1 / 141

PROGRAMACIÓN BÁSICA EN C Y JAVA

José Luis López Goytia

(elaboración: 2010; última revisión: 2011)

TEMA PÁG. Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

Aspectos metodológicos 1. Criterios de calidad del software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2. Pruebas de caja negra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 3. Ciclo de desarrollo de sistemas (método de cascada) . . . . . . . . . . . . . . . . . . . . . 12 4. Concepto de compilador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

Programando en lenguaje C 5. Un primer acercamiento al desarrollo de software . . . . . . . . . . . . . . . . . . . . . . . . . 25 6. El paradigma de la programación estructurada . . . . . . . . . . . . . . . . . . . . . . . . . . 40 7. Los primeros elementos para codificar en lenguaje C . . . . . . . . . . . . . . . . . . . . . . 51 8. Condicionales en lenguaje C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 9. Ciclos en lenguaje C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 10. Arreglos en lenguaje C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 11. Subrutinas en lenguaje C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 12. Apuntadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

Programando en Java 13. Enfoque de la programación orientada a objetos . . . . . . . . . . . . . . . . . . . 96 14. ¿Cómo funciona Java? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 15. Creación de una clase sencilla en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 16. El uso de múltiples clases en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115 17. Arreglos en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 18. Herencia y polimorfismo en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125 19. Composición en Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 Bibliografía . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

Programación básica en C y Java (elaboró: José Luis López Goytia) 2 / 141

INTRODUCCIÓN

Este material está dirigido para estudiantes que comienzan su carrera en informática o disciplinas

afines. Parte del supuesto que no han tomado ningún curso de programación y en un futuro se harán

profesionales del área.

Por ello se fomentan en primera instancia los aspectos conceptuales, que normalmente se dejan de

lado en materiales de este tipo. En la segunda parte se desarrollan los aspectos básicos de lenguaje C,

los cuales tienen un enlace natural con los fundamentos de Java, que se abordan en la tercera parte.

Todos los programas fueron probados con herramientas reconocidas y gratuitas: el compilador Dev C++

para el caso de C y el entorno NetBeans para el caso de Java. Bajo esta estructura se pretende dar un

camino natural a fin de abordar los lenguajes C y Java bajo un enfoque metodológico claro.

En el caso de la UPIICSA, abarcaría la parte central de las materias de de Lenguajes de

Programación I y Lenguajes de Programación III de las carreras de Ingeniería en Informática y

Licenciatura en Ciencias de la Informática. Se espera que para próximas actualizaciones esas materias

se conserven con otros nombres.

Finalmente, hay que advertir los alcances del presente trabajo para no crear falsas expectativas. No

tiene el propósito de abarcar todas las instrucciones de C y Java; únicamente dan sus fundamentos de

una manera disciplinada y metodológica, por lo cual deben ser complementados con otros libros o –lo

que para los estudiantes es más natural- con búsquedas en la Web.

Programación básica en C y Java (elaboró: José Luis López Goytia) 3 / 141

CRITERIOS DE CALIDAD DEL SOFTWARE

CONTENIDO

Corrección Robustez Compatibilidad Eficiencia Portabilidad Facilidad de uso

Funcionalidad Oportunidad Otras cualidades Ejercicios y casos reales Bibliografía

Un software debe reunir ciertas características para que su funcionamiento sea adecuado. Existen factores externos visibles para el usuario final. Es importante recalcar que “usuario final” no se refiere únicamente a quien opera directamente el sistema; abarca a las personas que compran el software o adquieren el desarrollo. Otras cualidades, como la legibilidad, son perceptibles únicamente para quienes leen el código fuente. Esos factores son internos. El autor Bertrand Meyer1 proporciona un listado de las cualidades externas que debe reunir el software. Se citan a continuación, con algún comentario que juzguemos pertinente. CORRECCION (Indice) “Corrección es la capacidad de los productos software para realizar con exactitud sus tareas [y sin errores], tal y como se definen en las especificaciones”. “La corrección es la cualidad principal. Si un sistema no hace lo que supone que debe hacer, poco importan el resto de las consideraciones que hagamos sobre él –si es rápido, si tiene una bonita interfaz de usuario…” Para llegar a la corrección se requiere como primer paso especificar los requisitos del sistema en una forma precisa, lo cual no es sencillo. Este paso requiere de diversas técnicas de Ingeniería de software. En esta parte el usuario final está directamente involucrado. Para ampliar información: consulte los temas de Ciclo de Desarrollo de Sistemas en general, y haga hincapié en las etapas de análisis y pruebas. En una segunda etapa, se trata de construir el software que cumpla dichas especificaciones. Lo cual corresponde más a temas de lenguajes de programación y bases de datos. Son rubros en donde prácticamente no interviene el usuario final. Hay que hacer hincapié que se construye un software bajo el supuesto de que los niveles inferiores son correctos. Por ejemplo: quien está elaborando un programa sobre desviación estándar parte del hecho de que las funciones de raíz cuadrada realizadas por el compilador son correctas. Ciertamente, nunca hay una garantía absoluta en ello, pero es la única forma realista de trabajar. ROBUSTEZ (Indice) “Robustez es la capacidad de los sistemas de software de reaccionar apropiadamente ante condiciones excepcionales”.

1 Meyer, Bertrand; Construcción de software Orientado a Objetos; Prentice-Hall; Segunda edición; Madrid, 1999; págs. 3-13.

Programación básica en C y Java (elaboró: José Luis López Goytia) 4 / 141

“La robustez complementa la corrección. La corrección tiene que ver con el comportamiento de un sistema en los casos previstos por su especificación: la robustez caracteriza lo que sucede fuera de tal especificación”. Es decir, lo que sucedería en casos excepcionales, entendiendo por “excepcional” un caso no previsto por la especificación y por “normal” algo “planificado durante el diseño del software”. Una forma práctica de abordar la robustez es garantizar que el sistema no termine abruptamente su ejecución en todos aquéllos casos anómalos que de antemano se sabe que pudieran llegar a darse. Por ejemplo: que se intente grabar cuando no hay espacio suficiente el disco; que se intente copiar a una unidad de disco inexistente; que se dañe una tabla en la base de datos; que se intente realizar una división entre cero; que el saldo neto de una quincena de un trabajador resultara en negativo al aplicar todos los descuentos autorizados, etc. COMPATIBILIDAD (Indice) “Compatibilidad es la facilidad de combinar unos elementos de software con otros.” Al menos hay dos enfoques para garantizar la compatibilidad: • Una prueba directa en un ambiente de pruebas con el software que va a convivir simultáneamente. Si

el software apenas se va a desarrollar se puede hacer una prueba preliminar con algunas rutinas del nuevo sistema.

• Un análisis de los diferentes estándares y protocolos manejados por los sistemas para observar que existe compatibilidad (formatos de archivo, estructuras de datos, interfaces de usuarios, etc).

Debe destacarse que muchos problemas de compatibilidad se resuelven cambiando diversos parámetros de configuración en uno o varios de los sistemas que están ejecutándose simultáneamente. También puede darse el caso de que no puede solucionarse el problema de compatibilidad, pero no se requiere que ambos sistemas trabajen al mismo tiempo. Dejar esta situación así hasta que el software sea sustituido al paso del tiempo es una solución práctica en muchísimos casos. EFICIENCIA (Indice) “Eficiencia es la capacidad de un sistema software para exigir la menor cantidad posible de recursos hardware, tales como tiempo del procesador, espacio ocupado de memoria interna y externa o ancho de banda utilizado en los dispositivos de comunicación”. Con respecto a la eficiencia se puede caer en dos actitudes opuestas (y ambas equivocadas): restar su importancia, porque cada día son más rápidas las computadoras; o tener una obsesión por las cuestiones del rendimiento, y por ello tratar de optimizar al máximo. Una de las formas de mejorar la eficiencia es incrementar la ventaja de los buenos algoritmos sobre los malos. Por ejemplo: supongamos que para sacar un reporte se leen uno por uno medio millón de registros de un archivo histórico. Otro desarrollador hace una pequeña rutina que combina las condiciones dadas por el usuario para traer –en promedio- unos 2000 registros. En este caso, el tiempo de procesamiento disminuye mucho más por usar un buen algoritmo que por emplear una computadora con mayores recursos. Para tener elementos sobre la eficiencia de un algoritmo, consulte información sobre función de trabajo. Ahora bien, optimizar un proceso muchas veces implica un mayor esfuerzo de programación y a veces impacta negativamente a la claridad y a la reutilización. La mayoría de los procesos no se ejecutan cotidianamente y por eso motivo –o por otros motivos igualmente válidos- no requieren ese esfuerzo

Programación básica en C y Java (elaboró: José Luis López Goytia) 5 / 141

extra. Por el contrario, hay algunas rutinas que por su uso frecuente ameritan ser optimizadas al máximo. El desarrollador debe hacer un balance entre la eficiencia y el tiempo de desarrollo. PORTABILIDAD (Indice) “Portabilidad (transportabilidad) es la facilidad de transferir los productos software a diferentes entornos hardware y software”. “La portabilidad tiene que ver con las variaciones no sólo del hardware físico sino más generalmente de la máquina hardware-software, la que realmente programamos y que incluye el sistema operativo, el sistema de ventanas (si se emplea) y otras herramientas fundamentales. En este rubro debe tomarse en cuenta desde un principio si el software que se ofrece se ejecutará para una computadora personal, red LAN, INTERNET o cualquier otro tipo de plataforma. FACILIDAD DE USO (Indice) “Facilidad de uso es la facilidad con la cual personas con diferentes formaciones y aptitudes pueden aprender a usar los productos software y aplicarlos a la resolución de problemas. También cubre la facilidad de instalación, de operación y de supervisión.” Uno de los problemas de la facilidad de uso es “como proporcionar explicaciones y guías detalladas a los usuarios novatos sin fastidiar a los usuarios expertos que quieren ir directos al grano”. Debe construirse un buen diseño, de acuerdo a una estructura clara y pensada en términos del usuario final. Debe considerarse que un usuario final puede ser alguien diestro en el manejo del sistema y en el área que aborda el software, pero también alguien que toma el software por primera vez y no tenga prácticamente ningún conocimiento del tema. Por ejemplo: puede ser un experto en nómina que lleva manejando este software tres años, o un capturista que lo comenzó a utilizar hace un par de horas. Un sistema sencillo e intuitivo no está peleado con un sistema rápido de manejar y con opciones avanzadas. Implica tener ayuda documental clara, completa y concisa, tanto en línea como remota. FUNCIONALIDAD (Indice) “Funcionalidad es el conjunto de posibilidades que proporciona un sistema”. Para lanzar la versión de un producto se debe cubrir un área lo suficientemente amplia del conjunto completo de características para atraer a los consumidores previstos en lugar de alejarlos. Seguramente se dejarán algunas características de lado, pero las que se decida incluir deben cubrir todas las características de calidad. “Hay que rechazar el pasar a considerar nuevas propiedades hasta que no se esté satisfecho con las que se tiene”. Para solucionar el problema de mantener la calidad y avanzar lo más posible en ofrecer más facilidades, debe trabajarse “una y otra vez sobre la consistencia del producto global, tratando de que todo encaje en un molde general. Un buen producto de software está basado en un número pequeño de potentes ideas: incluso si tiene muchas propiedades especializadas, éstas deberían explicarse como consecuencia de los conceptos básico”. El “gran plan” debe estar visible y todo debería ocupar su sitio dentro de él.

Programación básica en C y Java (elaboró: José Luis López Goytia) 6 / 141

OPORTUNIDAD (Indice) “Oportunidad es la capacidad de un sistema de software de ser lanzado cuando los usuarios lo desean, o antes.” “La oportunidad es una de las mayores frustraciones de nuestra industria. Un gran producto software que aparece demasiado tarde puede no alcanzar su objetivo. Esto es cierto en otras industrias también, pero pocas evolucionan tan rápidamente como el software… la oportunidad es todavía, para grandes [y pequeños] proyectos, un fenómeno poco común. OTRAS CUALIDADES (Indice) Conviene destacar otras cualidades que también afectan a los sistemas de software y a la gente que compra estos sistemas o encarga su desarrollo. “Verificabilidad es la facilidad para preparar procedimientos de aceptación, especialmente datos de prueba y procedimientos para detectar fallos y localizar errores durante las fases de validación y operación. “Integridad es la capacidad de los sistemas software para proteger sus diversos componentes (programas, datos, etc.) contra modificaciones y accesos no autorizados. Esta capacidad se basa –entre otras formas- en políticas de claves de acceso y algoritmos de encriptamiento. “Reparabilidad es la capacidad para facilitar la reparación de los defectos. “Economía, junto con la oportunidad, es la capacidad que un sistema tiene de completarse con el presupuesto asignado o por debajo del mismo. Razonablemente costoso. En sentido estricto, no se refiere al software en sí, sino a su comercialización, pero no hay que perderlo de vista. El software se debe ofrecer a un precio que sea atractivo para compradores potenciales en razón de la problemática que soluciona y de las ofertas que realiza la competencia a la cual se enfrenta, tanto en su adquisición como en su costo de mantenimiento. Garantía de soporte y actualización. El proveedor del software debe garantizar el soporte oportuno durante todo el tiempo de vida del software, así como sus adecuaciones por cambios tecnológicos, de ley o por nuevos requerimientos de la empresa. Muchas de estas actualizaciones se pueden hacer vía INTERNET. Atractivo. El software, además de ser funcional y fácil de usar, debe ser visualmente atractivo, pues de otra forma perdería a muchos usuarios potenciales. Facilidad de mantenimiento. Que el software realizado pueda adaptarse con relativa facilidad a nuevos requerimientos. Modular. Que el software sea modular, lo cual facilita el desarrollo, mantenimiento y reutilización de código. EJERCICIO: IDENTIFICACIÓN DE LAS CARACTERÍSTICAS EN CASOS REALES D(Indice)

• Elija dos software que haya utilizado. Uno que le haya sido agradable de emplear y otro que le haya causado diversos problemas. Evalué para cada uno las características de software. Utilice una escala del 0 al 10.

Programación básica en C y Java (elaboró: José Luis López Goytia) 7 / 141

• El programa para recibir las informativas de sueldos y salarios de la Secretaría de Hacienda y Crédito Público del año 2002 fue publicado una semana antes de la fecha límite en que los contribuyentes deben entregar la información. Al instalarlo, no corrió en Windows Millenium ni en monitores VGA y si la máquina ya tenía la versión del año pasado, no actualizaba la ayuda. ¿Qué características de un software no cumple?

• Se hizo un sistema en SQL Server que funciona correctamente. Sin embargo, corre con

demasiada lentitud y cuando se intentó pasar a Access, se presentaron problemas con el código. ¿Qué características de software no cumplió?

• El Instituto Mexicano del Seguro social (IMSS) dio a conocer su sistema, el cual cubría lo

necesario para el IMSS, pero descuidaba varios requerimientos útiles para la empresa. El IMSS aclaró que no era un error; así se había considerado desde el inicio. Sin embargo, varias empresas se dieron cuenta que podían abrir las tablas del sistema por fuera. ¿Qué características de software no cumplió?

EJERCICIO: IDENTIFICACIÓN DE CARACTERÍSTICAS A NIVEL CÓDIGO (Indice) • Un usuario acordó con usted realizar un programa que realizara la siguiente pantalla:

Este programa obtiene la división dos números sin utilizar el operador de división

Teclee el primer número: 13 Teclee el segundo número: 5 1) 13 - 5 = 8 2) 8 - 5 = 3 El resultado es: 2 Oprima cualquier tecla para continuar...

El programa, ya elaborado, tiene el siguiente código:

/* Autor: José Luis López Goytia; noviembre/2005; Compilador: Dev-C++ 4.9.8.0 */ #include <conio.h> #include <string.h> main() { int cantidad, divisor, sobrante, resultado; printf("Este programa obtiene la división dos números sin utilizar el operador de división\n\n"); printf("Teclee el primer número: "); scanf("%d", &cantidad); printf("Teclee el segundo número: "); scanf("%d", &divisor); if (divisor == 0) printf("No se puede realizar una división entre cero.\n\n"); else { // se realiza a través de restas sucesivas sobrante = cantidad; resultado = 0; while (sobrante >= divisor) { resultado++; sobrante -= divisor;

Programación básica en C y Java (elaboró: José Luis López Goytia) 8 / 141

printf("%d ) %d - %d = %d\n", resultado, sobrante + divisor, divisor, sobrante); } printf("El resultado es: %d\n", resultado); } printf("Gracias."); printf("\n\nOprima cualquier tecla para continuar..."); getch(); }

El código en general es correcto. Sin embargo, no tiene robustez. Modifique el código de tal modo que el programa no “truene”, aunque se le indiquen datos inconsistentes (por ejemplo: letras en lugar de números o una división entre cero). ¿Qué porcentaje de líneas se tuvieron que modificar?

BIBLIOGRAFIA (Indice) Meyer, Bertrand; Construcción de software Orientado a Objetos; Prentice-Hall; Segunda edición; Madrid, 1999; 1198 páginas.

Programación básica en C y Java (elaboró: José Luis López Goytia) 9 / 141

PRUEBAS DE “CAJA NEGRA”

CONTENIDO

Concepto de caja negra ¿Qué probar? Límite de las pruebas de “caja negra” Ejercicios sugeridos

CONCEPTO DE CAJA NEGRA (Indice) El concepto de “caja negra” representa el punto de vista del usuario. Dicho de otra forma: se hacen partiendo del supuesto que no se tiene acceso al código. Sólo se puede operar el sistema con las opciones que están disponibles para el usuario De preferencia, estas pruebas deben diseñarse inmediatamente después de definir los requerimientos. El enfoque es: “si al terminar la programación este programa arroja estos resultados, daremos por bueno el producto”. El proceso debiera ser entonces como sigue:

REQUERIMIENTOS >> DISEÑO DE PRUEBAS >> CODIFICACIÓN >> APLICAR PRUEBAS Pasar las pruebas correctamente se convierte en uno de los criterios indispensables para la aceptación del producto. El programa no estará terminado hasta que arroje los resultados esperados. Por tanto, sería un grave error ponerlo en producción antes. No es una exageración; es “sentido común”. ¿No le parece sensato probar el agua de frutas que acaba de hacer antes de llevarla a sus invitados? Es increíble el número de casos en que esto se deja de lado. Hay que hacer hincapié en que las pruebas son parte del proceso de programación. Se deben ir realizando pruebas por módulos conforme el plan de trabajo establecido y no dejarlas al final de todo el proyecto. Cuando se prueba hasta el final se corre el riesgo de que se hayan cometido errores de tal magnitud que es más fácil rehacer el sistema que corregirlo. ¿QUÉ PROBAR? (Indice) Como el programador pudiera equivocarse en cada proceso, lo ideal sería realizar una prueba para cada caso distinto (distinto desde el punto de vista del usuario). No tiene caso realizar 100 pruebas de casos “típicos”. Bastaría con un par de casos “típicos” y una prueba para cada uno de los casos “atípicos” esperados. A manera de ejemplo, suponga que va a probar un programa que obtiene el mayor de dos números. El siguiente lote de pruebas estaría mal diseñado: PRUEBA 1: si introducimos los valores 10 y 12 el resultado será 12. PRUEBA 2: si introducimos los valores 3 y 5 el resultado será 5. PRUEBA 3: si introducimos los valores 1 y 3 el resultado será 3.

puesto que conceptualmente todos son iguales: en todos los casos el segundo es mayor. Lo que sería conveniente es tener una prueba por cada caso distinto.

Programación básica en C y Java (elaboró: José Luis López Goytia) 10 / 141

PRUEBA 1: si introducimos los valores 10 y 12 el resultado será 12. PRUEBA 2: si introducimos los valores 12 y 10 el resultado será 12. PRUEBA 3: si introducimos los valores 5 y 5 el resultado será 5.

¿Qué probar? El diseño de las pruebas se volverá más sencillo si recordamos las características que debe reunir un buen software. Para probar la corrección: Pruebas por cada caso de naturaleza distinta: se ejecutará el programa con cada caso que se considere distinto, incluyendo situaciones típicas y atípicas. En algunos casos con casos simulados y en otros casos con datos reales. Pruebas de configuración: se revisará la configuración que está cargada en el sistema. Por ejemplo: directorio de sucursales, catálogo de productos, catálogo de puestos, etc. Pruebas integrales: se prueba el sistema funcionando de manera íntegra. La forma más práctica es simulando un usuario del sistema (alumno, empleado, cliente, etc.) y realizando con él todas operaciones típicas y atípicas a las que suele acceder, para verificar que el proceso en su conjunto es correcto. Es muy usual combinar estas pruebas con las pruebas en paralelo. Las pruebas en paralelo consisten en ejecutar el sistema a la par con el sistema anterior para comparar los resultados. En ocasiones, el nuevo sistema se ejecuta algunos días después -para evitar sobrecargas de trabajo- pero partiendo de la misma información que alimentó al viejo sistema. Para probar la robustez: Se realizan los errores “típicos” para verificar que el sistema los maneja adecuadamente: dar tipos de datos incorrectos (por ejemplo, una fecha errónea o una letra cuando se espera un número); hacer funcionar el sistema cuando algún dispositivo está desconectado (por ejemplo: la impresora); alimentar datos intentado producir una división entre cero; etc. Para probar la compatibilidad: Hacer correr el sistema junto con los otros programas que se ejecutarán simultáneamente. Para probar la eficiencia: Se debe correr el sistema con la carga máxima de datos que va a soportar. Este proceso se conoce también como pruebas de carga máxima. Esta es otra de las pruebas que casi siempre se deja de lado. Los problemas se detectan, justamente, cuando el sistema se somete a su esfuerzo máximo. Las pruebas de eficiencia se notan solamente con un gran número de datos. Para probar la portabilidad: Se debe correr el sistema en los diferentes entornos en que se supone debe correr. Por ejemplo: en monitores de diferente resolución.

Programación básica en C y Java (elaboró: José Luis López Goytia) 11 / 141

Para verificar la facilidad de uso: En este caso, se piensa en verificaciones más que en pruebas. El lenguaje debe ser dirigido al usuario; las pantallas deben entenderse por sí solas; la operación debe ser intuitiva y fácil; no debe haber faltas de ortografía, y las pantallas deben ajustarse a los estándares de color, manejo y tipo de letras establecidos. Para verificar la funcionalidad: Al finalizar la etapa de requerimientos se establecieron todas las funciones que debería cubrir el sistema a realizar. El sistema terminado debe cubrir toda esa funcionalidad. Una de las herramientas más sencillas –que incluso parece burda- es realizar un check list . Sin embargo, a veces ni siquiera se realiza esta tarea. Para verificar la oportunidad: Se debe verificar si la entrega es oportuna conforme al plan de trabajo establecido y, en caso contrario, tomar las medidas que se consideren convenientes. Para verificar la integridad: Revisión de los usuarios y la configuración de sus respectivos permisos. Pruebas de que éstos funcionen correctamente. Pruebas de respaldos. LÍMITES DE LAS PRUEBAS DE “CAJA NEGRA” (Indice) Conviene recordar que ningún lote de pruebas detecta todos los errores. Como criterio general se considera que el número de fallas detectadas es proporcional al número oculta de ellas. Por otra parte, las pruebas de “caja negra” son desde el punto de vista usuario. No revisa estándares técnicos ni la estructura interna del sistema, porque ambos aspectos no son visibles desde el exterior. Por ello este enfoque debe combinarse con otro tipo de revisiones para lograr un control de calidad completo del desarrollo de software. EJERCICIOS SUGERIDOS (Indice) Se recomienda hacer una serie de programas –algunos que se ejecutan correctamente y otros con errores- para que el alumno establezca lotes de pruebas a fin de detectar cuales programas no corren bien y en que casos.

Programación básica en C y Java (elaboró: José Luis López Goytia) 12 / 141

CICLO DE DESARROLLO DE SISTEMAS (MÉTODO DE CASCADA)

CONTENIDO La necesidad de un desarrollo metodológico Las etapas del método de cascada Síntomas de una mala aplicación del ciclo de desarrollo de sistemas Ejemplos reales Bibliografía

LA NECESIDAD DE UN DESARROLLO METODOLÓGICO (Indice) Quizá la primer forma en que se desarrollo un programa es la de tener una idea general de los que se

hace y programarlo. Cuando al fin hace lo que deseamos –y después de unas pruebas muy generales- se presenta al profesor, quien detecta errores y nos pide modificaciones. A la desvelada de sábado y domingo se añade la del miércoles para, al fin, presentarlo correctamente.

Ahora cambiemos un poco los sustantivos y observemos el resultado.

Quizá la primer forma en que se desarrolló un sistema es la de tener una idea muy general de lo que hace y desarrollarlo. Cuando al fin se hace lo que deseamos –y después de unas pruebas muy generales- se presenta a un director de la empresa, quien detecta errores y nos pide modificaciones. A los seis meses de trabajo se añaden otros tres para, al fin presentarlo correctamente.

Definitivamente, trabajar sin aspectos metodológicos adecuados difícilmente puede llevar a buen término un desarrollo de software. Solamente una labor realizada con calidad en cada uno de sus pasos y con base en la metodología diseñada correctamente –y seguida en forma disciplinada- puede dar un sistema confiable y eficiente. En caso contrario, las quejas de los usuarios serán frecuentes y será conveniente tener siempre nuestro curriculum vitae bien preparado (por si es necesario buscar otro trabajo).

Algunas de las frases más escuchadas en el área de desarrollo de software: “ni les creas; nunca entregan las cosas a tiempo” (usuarios refiriéndose al área de informática); “ni saben lo que quieren ni te dan información completa” (informática refiriéndose a usuarios); “dejó el sistema echo un desmadre” (desarrolladores refiriéndose a los desarrolladores que trabajaron antes en el sistema); “dice una cosa y luego se echa para atrás” (todos refiriéndose a todos).

Con excepción de la última frase, las demás pueden tender a desaparecer cambiando la cultura bajo la cual trabaja el área de informática y adoptando métodos de organización y desarrollo adecuados. La última solo podrá solucionarse parcialmente, pues nace de la falta de orden en el desarrollo, pero también de deshonestidades y “golpes bajos”. Lamentablemente, aunque la honestidad es uno de los sentimientos que –por lo menos en teoría- alaba más nuestra sociedad, también se permite y en ocasiones se alaba que se obtengan resultados con base en falsas promesas.

Un método que sigue funcionando es el método de cascada. En ella el desarrollo se divide en etapas que deben darse en forma secuencial. En el caso de modificaciones se seguirá este método para los cambios a realizar.

A continuación se ofrece un cuadro que sintetiza las etapas del método de cascada. Conviene hacer hincapié en que la documentación no es una etapa, se hace a la par que avanza el proyecto. Por otro parte, se incluye la etapa de autorización del proyecto, que prácticamente ningún autor considera como parte del método de cascada. Sin embargo, la realidad cotidiana nos empuja a considerarla como la base de las actividades siguientes.

Programación básica en C y Java (elaboró: José Luis López Goytia) 13 / 141

LAS ETAPAS DEL METODO DE CASCADA (Indice)

Etapa

Objetivo y descripción de la etapa

Documentación entregada

% del

tiempo de desarrollo

Autorización del proyecto

Que se autorice el proyecto: alcance, tiempos y recursos. Rubros a cubrir: evaluación alternativas; estimación de tiempos; estimación de costo-beneficio; establecer el contenido general; definición de plataformas en que debe ejecutarse. Técnicas utilizadas: entrevistas con el directivo; consultas a especialistas; herramientas de planeación (gráficas de GANTT, ruta crítica), etc.

contrato

10

Análisis

Definir los requerimientos a detalle del nuevo sistema Rubros cubrir: resultados que arrojará el nuevo sistema (incluyendo reportes); entradas que alimentarán al nuevo sistema (incluyendo pantallas); documentación de cálculos; glosario de términos y estándares de presentación; readecuación de procesos administrativos. Técnicas utilizadas: análisis del sistema actual; revisión de reglamentación vigente; entrevistas con el usuario operativo; diagrama de flujo de datos, etc.

especificación de requerimientos

20

Diseño

Arquitectura general del producto Rubros a cubrir: diseño modular; normalización de bases de datos; script de creación de bases de datos; diccionario de campos; estándares técnicos; algoritmos principales. Técnicas utilizadas: pruebas de portabilidad; diseño modular (Top-Down); reglas de normalización de base de datos; complejidad computacional; explotación de las tablas del sistema de la base de datos, herramientas automatizadas de creación de scripts (Vg. Erwin); etc.

manual técnico

15

Codificación y pruebas por módulo

Construcción del producto conforme a especificaciones.

código fuente comentado

25

Programación básica en C y Java (elaboró: José Luis López Goytia) 14 / 141

Rubros a cubrir: diseño lote de pruebas; descripción de rutinas genéricas; estándares de programación; código fuente comentado y probado. Técnicas utilizadas: diseño de lote de pruebas; seudocódigo; diagramas de sintaxis; enfoque de caja blanca y caja negra; lenguajes de programación; etc.

Pruebas integrales

Prueba integral del producto Rubros a cubrir: diseño de lote de pruebas integral; manual de usuario; manual de instalación (incluye discos de instalación). Técnicas utilizadas: carga de datos reales; creación de discos de instalación; pruebas en paralelo; pruebas de carga máximo; prueba integral; revisión de la configuración del nuevo sistema; pruebas de control de accesos y de seguridad en general.

discos de instalación y manuales.

12

Carga y puesta a punto

Puesta en funcionamiento del sistema Rubros a cubrir: capacitación; cartas de liberación. Técnicas utilizadas: carga de datos reales; formas de instalación masiva; formas de soporte cercano a nuevos usuarios.

adecuaciones por corrección de errores o nuevos requerimientos.

18

Mantenimiento

Mantener al sistema en un funcionamiento correcto Rubros a cubrir: modificaciones de funcionamiento; adecuación de datos históricos. Técnicas utilizadas: contratos de mantenimiento; establecimiento de estándares.

actualización del sistema con su respectivo soporte documental

De 2 a 4 veces del desarrollo original

SINTOMAS DE UNA MALA APLICACIÓN DEL CICLO DE DESARROLLO DE SISTEMAS (Indice) La siguiente lista es una lista de algunos síntomas típicos cuando no se sigue el ciclo de desarrollo de sistemas. Elija un desarrollo de sistemas que haya tenido problemas y señale los síntomas con los que coincidía. Los síntomas están ubicados en la etapa en la cual se generaron, aunque hayan sido descubiertos posteriormente.

Programación básica en C y Java (elaboró: José Luis López Goytia) 15 / 141

AUTORIZACION ( ) No se tiene un contrato o plan de trabajo por escrito al arrancar el proyecto.

( ) Se habían realizado varias pláticas para promover el proyecto y se descubrió que la persona no tenía un interés real o no tenía una influencia significativa en la decisión

( ) Ya se tenían avances significativos del proyecto y no autorizaron el proyecto. ( ) No se hizo una estimación de tiempos con bases sólidas. ( ) No se hizo una estimación de costos con bases sólidas. ( ) El contrato no indica los costos y alcances del mantenimiento. ( ) No se consideró la "curva de aprendizaje" en los tiempos y costos. ( ) No se consideraron la compatibilidad entre versiones.

ANALISIS

( ) No hay documentos que expliquen los procesos de cálculo.

( ) Se presentan ambigüedades o puntos encontrados acerca del significado de varios términos en etapas posteriores.

( ) En etapas posteriores se agregan muchos reportes que no estaban considerados. ( ) En etapas posteriores se agregan módulos completos que no estaban considerados. ( ) Cuando se le presenta el proyecto al usuario dice que no era lo que él había pensado.

( ) Los reportes y consultas no se pueden limitar por los parámetros más usuales que necesita el usuario (fechas, sucursales, etc.)

( ) Cada programador le da al sistema una presentación diferente (colores, menús, etc.) ( ) El dueño o el directivo no respeta las decisiones del líder de proyecto.

DISEÑO

( ) No existe un diagrama general del sistema.

( ) Al hacer la prueba integral se presentan problemas porque hay campos o rutinas que cada programador manejó con nombres distintos cuando deberían tener un solo nombre.

( ) La consulta de los nombres y tipos de campos es muy lenta.

( ) Hay varias partes del código que hacen prácticamente lo mismo y se programaron varias veces.

( ) Se dificulta encontrar los nombres de programas o tablas porque no existe un estándar. ( ) Los programas corren bien pero son demasiado lentos. ( ) El sistema permite la entrada a datos inconsistentes. ( ) El sistema en general no valida datos típicos (por ejemplo: fechas).

( ) El sistema no permite modificar un dato que iba a cambiar a mediano plazo. Por ejemplo: el monto del salario mínimo general.

CODIFICACION Y PRUEBAS POR MODULO

( ) Cuando se va a probar un módulo no se tiene prediseñado un lote de pruebas. ( ) Los programas no están comentados. ( ) No se aplicaron estándares de presentación ni estándares técnicos. ( ) Los programas "truenan" o arrojan resultados incorrectos. ( ) Un programa en particular no valida datos típicos (por ejemplo: fechas). ( ) Faltas de ortografía.

PRUEBAS INTEGRALES

( ) No se hizo ninguna prueba integral. ( ) Las pruebas integrales no se hicieron con datos reales. ( ) No se hizo el manual de instalación ( ) No se probó el procedimiento de instalación. ( ) No se hizo el manual de usuario.

( ) La carga de datos se hizo manualmente, lo cual implica volver a repetirla manualmente en el futuro.

( ) No se probó el procedimiento de instalación.

Programación básica en C y Java (elaboró: José Luis López Goytia) 16 / 141

MANTENIMIENTO

( ) No se actualizó la documentación. ( ) No se hicieron rutinas para conservar la coherencia de datos históricos. ( ) No hay ningún soporte documental. ( ) Se "traspapeló" la documentación técnica y/o de usuario del sistema. ( ) Se "traspapelaron" los discos de instalación. ( ) No existen respaldos probados.

EJEMPLO REALES (Indice)

ENVÍO DE CORRESPONDENCIA Una empresa deseaba tener un listado de compradores potenciales, el cual capturó por delegación política. Su listado era similar al siguiente:

Cuando llevaban 5,500 registros decidieron enviarles correspondencia, el problema es que para enviar correspondencia se necesita siguiente formato.

Y la dirección se había capturado en un solo campo. ¿Que implicaba ello?

a) Crear nuevos campos en la base de datos. b) Modificar pantallas de captura y reportes. c) Recapturar la dirección de las 5,500 personas.

Calle y Número:

Colonia:

Código Postal Delegación

Delegación:

Fecha de contacto Nombre Dirección

Programación básica en C y Java (elaboró: José Luis López Goytia) 17 / 141

El error desde el punto de vista práctico fue no separar los campos. Desde el punto de vista conceptual fue mucho mayor: no se siguieron las etapas del ciclo de desarrollo de sistemas, por ello nunca se previeron necesidades futuras inmediatas. Una falla en el análisis provocara cambios posteriores en todas las demás etapas, con sus repercusiones anímicas y económicas.

En este ejemplo, la captura se hizo por segunda vez y tal vez eso consumió 2 meses. ¿Qué hubiera sucedido si un error de tal magnitud hubiera surgido en un sistema de $10 ,000 USD? ¿Es exageración? Tal vez, pero se dio el caso de una empresa mediana de la ciudad de México que compró un software a inicios de 1998 para darse cuenta 2 ó 3 meses después que no estaba preparado para el año 2000 y, peor aún, que nunca se lo habían preguntado al proveedor ni le habían pedido por escrito ese requisito. Definitivamente los errores cuestan. SISTEMA DE CONTROL ESCOLAR

En un sistema de control de asignaturas se observó un código parecido al siguiente. if materia = "ADMI" then nombre_materia = "administración" if materia = "PROG" then nombre_materia = "programación"

El listado seguía con 30 materias más.

Este tipo de código trae problemas futuros. ¿Es posible que en los próximos 10 años cambie la clave y/o el nombre de una asignatura? La probabilidad es casi del 100%. Entonces estos datos deben estar en un catálogo que el usuario pueda modificar. De lo contrario será necesario alterar el código fuente, probar, actualizar la documentación y poner al día todas las instalaciones en las que se encuentre el programa. El ahorro de unas 2 horas nos causará a corto o mediano plazo tener que invertir al menos un par de días, sobre todo si existen decenas o centenares de instalaciones. SISTEMA DE LA SECRETARÍA DE HACIENDA Y CRÉDITO PÚBLICO La Secretaría de Hacienda y Crédito Público publicó vía INTERNET EN 2001 el software para capturar los datos de la Declaración de Sueldos y Salarios. El programa fue publicado con una semana de anticipación; el dato que se capturaba en sueldo normal aparecía en el reporte como aguinaldo; las pantallas aparecían cortadas en monitores tipo VGA (en aquel entonces una cuarta parte de las PC’s no podía poner una resolución mayor) y los ejemplos en el manual no mostraban datos reales. Una situación así únicamente puede explicarse –entre otros muchos motivos- porque nunca se siguió una metodología para el desarrollo de este producto. Existieron errores en todas las etapas del desarrollo.

EJERCICIOS A NIVEL CÓNCEPTUAL: (Indice)

• Un líder de proyecto indicó capturar el nombre completo, dirección y teléfono de clientes potenciales en un archivo tipo texto; cada campo con una longitud fija. Ejemplos:

José Luis Huerta Jiménez Iris #38, col. Obrera 55-68-

84-27

Juan Hernández López Té 48, unidad FOVISSSTE Miramontes 56-91-

23-56

Programación básica en C y Java (elaboró: José Luis López Goytia) 18 / 141

El programador realizó el sistema conforme a los ejemplos señalados. Un mes después - cuando se quiso enviar correspondencia por correo- se detectó que debió capturarse la calle y número en un renglón, y en un otro renglón la colonia. Fue necesario reprogramar y corregir 5000 registros. ¿En qué etapa o etapas del desarrollo se generó el error? Argumente.

EJERCICIOS A NIVEL CÓDIGO: (Indice) • Un usuario acordó con usted realizar un programa que realizara la siguiente pantalla:

Este programa obtiene la división dos números sin utilizar el operador de división

Teclee el primer número: 13 Teclee el segundo número: 5 1) 13 - 5 = 8 2) 8 - 5 = 3 El resultado es: 2 Oprima cualquier tecla para continuar...

El programa, ya elaborado, tiene el siguiente código:

/* Autor: José Luis López Goytia; noviembre/2005; Compilador: Dev-C++ 4.9.8.0 */ #include <conio.h> #include <string.h> main() { int cantidad, divisor, sobrante, resultado; printf("Este programa obtiene la división dos números sin utilizar el operador de división\n\n"); printf("Teclee el primer número: "); scanf("%d", &cantidad); printf("Teclee el segundo número: "); scanf("%d", &divisor); if (divisor == 0) printf("No se puede realizar una división entre cero.\n\n"); else { // se realiza a través de restas sucesivas sobrante = cantidad; resultado = 0; while (sobrante >= divisor) { resultado++; sobrante -= divisor; printf("%d ) %d - %d = %d\n", resultado, sobrante + divisor, divisor, sobrante); } printf("El resultado es: %d\n", resultado); } printf("Gracias."); printf("\n\nOprima cualquier tecla para continuar..."); getch(); }

Suponga que se requiere un cambio a la pantalla como sigue:

Programación básica en C y Java (elaboró: José Luis López Goytia) 19 / 141

Este programa obtiene la división dos números sin utilizar el operador de división Teclee el primer número: 13 Teclee el segundo número: 5 El resultado es: 2 Demostración del resultado 1) 13 - 5 = 8 2) 8 - 5 = 3 Oprima cualquier tecla pra continuar...

¿Qué porcentaje de líneas tiene que cambiar?

BIBLIOGRAFÍA (Indice) El tema del método de cascada se encuentra prácticamente en cualquier libro sobre Ingeniería de Software. En muchos de ellos se refieren a ciclo de vida de un sistema. Recomendamos particularmente: McConnell, Steve; Desarrollo y Gestión de Proyectos Informáticos; McGraw-Hill; España, 1998. 691 páginas.

Programación básica en C y Java (elaboró: José Luis López Goytia) 20 / 141

CONCEPTO DE COMPILADOR CONTENIDO El concepto básico de compilador El problema de las versiones Librerías en C, C++ y Java Librerías de acceso dinámico La máquina virtual de Java Los compiladores en ambiente WEB La compilación en lenguaje de acceso a base de datos Bibliografía

EL CONCEPTO BASICO DE COMPILADOR Tradicionalmente, el compilador se juzga como un programa que traduce de un código fuente (realizado en un lenguaje de programación) a un código máquina (instrucciones en código binario, entendibles por la computadora).

El compilador intenta traducir todo el programa a código máquina. Si alguna línea está mal, indica el error y no realiza traducción alguna. El intérprete, traduce y ejecuta línea por línea, lo cual puede resultar una ventaja (al menos hizo algo) o una gran desventaja (lo peor que puede pasar es dejarlo a medias). C, C++ y Java trabajan con base en compiladores. Los intérpretes se encuentran en lenguajes como Basic y el lenguaje para manejo de base de datos (SQL). Este último se ejecuta instrucción por instrucción en todos sus comandos básicos.

EL PROBLEMA DE LAS VERSIONES

El lenguaje máquina depende de la arquitectura de la computadora. Dicho de otro modo: un código máquina producido para computadoras compatibles con IBM PC (que corren en ambiente Windows) no se podrá ejecutar con computadoras compatibles con Apple, máquinas PALM o celulares. Determinadas instrucciones también varían según el modelo de la computadora. Sobre todo, de la versión del procesador. Programas que se ejecutan correctamente en una computadora con procesador Intel 486 (de inicios de los 90’s) difícilmente correrán en un Pentium IV. Si se quiere ver de otro modo: es poco probable que un programa que corría bien sobre Windows 3.11 trabaje todavía en Windows XP. Entre más tiempo se alejen se aumenta el riesgo de la falta de compatibilidad. Este no es un fenómeno exclusivo de la computación ni de inicios del siglo XXI. Sucede en general en todas las ramas. Por citar un ejemplo: los rollos de una cámara fotográfica con sistema Advantix no funcionan en otro tipo de cámaras fotográficas. Claro está, se nota menos en las ramas cuyos cambios tecnológicos no son tan acelerados.

código fuente código máquina

Programación básica en C y Java (elaboró: José Luis López Goytia) 21 / 141

Sucede algo similar del lado del código fuente. En primer lugar, como el compilador traduce de un determinado lenguaje de programación a un determinado tipo de máquina, deberá existir un compilador distinto para cada lenguaje y tipo de máquina. Por ejemplo: habrá uno compilador específico para lenguaje C que convierta a código máquina para computadores personales compatibles con IBM PC (Windows); otro de Pascal para computadores personales compatibles con IBM PC; otro más de lenguaje C para computadoras personales marca Apple, etc. Por otro lado, puede haber varios fabricantes, cuyos compiladores presentan ligeras diferencias entre sí. Verbigracia: un programa escrito en lenguaje C puede no marcar ningún error con el compilador Dev C++ y marcar errores si se compila con Borland C. A pesar de que ambos estén intentando traducir de lenguaje C a código máquina para computadoras compatibles con una IBM PC (Windows). Si una instrucción fue incorporada en una versión no será reconocida por una versión anterior. Incluso, pueden darse diferencias entre compiladores de la misma versión pero idiomas diferentes. No debemos asustarnos tanto. En términos generales las diferencias entre compiladores son mínimas. Tip: si va a comenzar a programar use el compilador y la versión que le recomiende su instructor y no la cambie hasta que haya ejecutado en él al menos media docena de programas. Tip: la gran mayoría de las diferencias puede preverse. Si usted considera que un programa debe ejecutarse correctamente en dos o más ambientes distintos deberá atacar el problema de dos formas: a) usar sólo instrucciones que estén en la definición general del lenguaje. De esta manera evitará emplear sentencias que sólo obedezca determinado fabricante; B) probar las instrucciones que va a utilizar centenares de veces en ambas herramientas. Así garantiza escribir de tal forma que trabaje bien en todos los ambientes. Si toma en cuenta estos dos aspectos, las correcciones que tenga que hacer al cambiar de herramienta se reducirán en más del 90%. LIBRERIAS EN C, C++ Y JAVA Desde hace unos 30 años existe la posibilidad de codificar y compilar subprogramas que realizan una labor específica y que después pueden ser llamados por otro programa. Estos subprogramas no pueden ejecutarse por sí solos porque no son un programa completo, pero ya fueron traducidos por el compilador. Al código producido de esta manera se le conoce como código objeto. En algunas ocasiones, se publica el código fuente de estas subrutinas. Estos subprogramas o subrutinas se agrupan, según su tarea, en librerías. De esta forma, existe una librería con las subrutinas matemáticas, otra para manejo de textos, etc. Al comenzar el programa principal se indican las librerías que se van a utilizar (en lenguaje C se hace con la instrucción #include; para Java se emplea import). Los programas en C, C++ y Java hacen uso intensivo de las librerías. Conviene conocer las posibilidades que se tienen. Su desconocimiento nos puede llevar a “reinventar el hilo negro”. Normalmente las librerías se incorporan al tiempo de compilar y quedan incluidas en el código máquina.

Programación básica en C y Java (elaboró: José Luis López Goytia) 22 / 141

LIBRERIAS DE ACCESO DINAMICO Los programas realizados para ambientes visuales –entre los que destaca Visual Basic – consumen una gran cantidad de recursos. Si se creara un ejecutable con todas las librerías necesarias el código máquina producido sería de 10 ó 20 megabytes. Para ahorrar espacio, se crearon las librerías de acceso dinámico (DLL’s), las cuales se mandan llamar en tiempo de ejecución. De esta forma, el ejecutable disminuye en más de un 90% su tamaño. La situación quedó como sigue:

Las librerías de acceso dinámico solucionaron un problema a costa de causar otro. Imagine que existe una librería ejemplo.dll hecha en el año 2003, y otra ejemplo.dll para el año 2004, ambas ubicadas en el mismo directorio. Lógicamente, no pueden estar ambas simultáneamente. Si un programa se realizó con la ejemplo.dll del 2003 y otro con ejemplo.dll del 2004 se corre el riesgo de que corra uno u otro. Esta situación se llegó a dar entre las versiones 4.5 y 5.0 de Visual Basic. Aunque se ha ido solucionando, todavía persisten algunos problemas de incompatibilidad. Tips:

1) Si desinstala una aplicación y hay un mensaje de que las librerías pudieran están compartidas, nunca las elimine, pues podría ocasionar problemas con otra aplicación. Al dejarla tal vez desperdicie espacio en disco duro, pero todos sus programas seguirán trabajando.

2) Cuando existan dos versiones deje la más reciente. En teoría las librerías de acceso dinámico deben satisfacer los requerimientos de las versiones anteriores.

Lógicamente, si se desea instalar un programa con librerías de acceso dinámico en otra máquina, se tiene que copiar el ejecutable más todas las librerías que ocupa. Esto se realiza a través de las opciones que producen los discos de instalación. Estas opciones crean automáticamente el programa de instalación, que incluye todas las librerías necesarias. Si después de instalarlo falta alguna intente copiarla manualmente de la otra máquina. Tal vez resulte. Lamentablemente, no existe ninguna relación fácil de localizar indicando la lista de librerías que ocupa cada componente de programación visual.

código fuente código máquina

librerías de acceso dinámico (DLL)

código fuente código máquina

librerías

Programación básica en C y Java (elaboró: José Luis López Goytia) 23 / 141

LA MAQUINA VIRTUAL DE JAVA Java se basa en librerías al igual que el lenguaje C. Sin embargo, incorpora un concepto nuevo: la máquina virtual. El compilador no produce directamente el código ejecutable. En su lugar deja un código de bytes que –en un segundo paso- un intérprete transformará al código máquina de la computadora. Por eso se dice que la compilación es hacia una “máquina virtual”. En otras palabras, compilamos para un intérprete que aún no se conoce.

Esta forma de trabajo tiene grandes ventajas. Por un lado, ni el programa fuente ni el código compilado dependen de la computadora en específico. Por otro, es mucho más difícil vulnerar la seguridad en Java. Pero tiene costos: se requiere un intérprete que realice el paso final y hace que los programas sean menos eficiente por ese último paso de traducción. La idea no era nueva y había fracasado en intentos anteriores. Sin embargo, la situación técnica de la computación hacia finales de los 90’s y la aplicación masiva de INTERNET hicieron que Java tuviera una difusión que ningún otro lenguaje había logrado. LOS COMPILADORES EN AMBIENTE WEB HTML no es un lenguaje de programación como tal. En su caso la traducción la realiza un intérprete que se encuentra en el navegador de la computadora cliente, es decir, en la computadora que está visualizando la página WEB. Presenta una peculiaridad: si hay una instrucción errónea, hace caso omiso de la parte equivocada y ejecuta la parte de la instrucción que sí se escribió de manera correcta. Por lo regular, las páginas no mandan un error. Pero los errores pueden ocasionar que el despliegue no sea como se había pensado. El navegador también interpreta código JavaScript. Este lenguaje tiene muchas instrucciones comunes con C y Java, pero conceptualmente no tiene que ver directamente con Java. No tiene un compilador como tal ni emplea una máquina virtual. Lo interpreta el propio navegador. Si existe un error, detiene la ejecución de la parte correspondiente a Java Script y despliega un mensaje de error (aunque puede configurarse el navegador para que no lo despliegue). Existen lenguajes para controlar a las sentencias de acceso a base de datos. Los más comunes son Active Server Pages (ASP) y PHP. ASP –de tecnología Microsoft- es un Basic adaptado para ambiente WEB. En ambos casos se manejan mediante un intérprete situado en el servidor WEB, es decir, en la máquina que tiene alojado el sitio WEB. Para el caso de ASP el intérprete es Internet Information Server; para el caso de PHP, el intérprete es Apache.

código fuente código de bytes

librerías

ejecución

Programación básica en C y Java (elaboró: José Luis López Goytia) 24 / 141

LA COMPILACION EN LENGUAJE DE ACCESO A BASE DE DATOS El lenguaje para acceder bases de datos relacionales es SQL (Standard Query Lenguaje). Estas sentencias son traducidas por un intérprete contenido en el Sistema Manejador de Bases de Datos (SMBD). Los SMBD también permiten la creación de programas (disparadores, transacciones, procedimientos almacenados). En este caso, cada SMBD tiene su propio compilador. BIBLIOGRAFIA No conocemos ninguna bibliografía que abarque las diferentes formas prácticas en que trabaja un compilador. Se tendría que buscar en libros de programación estructurada, programación visual, programación para INTERNET y programación para base de datos. Para quien desee ahondar sobre el tema de compiladores se recomienda: Aho, Alfred V.; SEIT, Ravi; Ullman, Jeffrey D. Compiladores. Principios, técnicas y herramientas; Addison Wesley Longman; México, 1998; 820 páginas.

Programación básica en C y Java (elaboró: José Luis López Goytia) 25 / 141

Capítulo 5

UN PRIMER ACERCAMIENTO AL DESARROLLO DE SOFTWARE

5.1. Los criterios de calidad del software Desde hace décadas se habla de la “crisis del software”, referencia obligada en prácticamente todos los cursos de Ingeniería de Software y tema de múltiples chascarrillos con cierta dosis de verdad. Un estudio realizado en 2001 señala que sólo el 28% de proyectos de software son exitosos, contra 23% cancelados y 49% excedidos en tiempo o presupuesto o con características faltantes2; investigaciones más recientes muestran que la situación no ha cambiado; entre 40% y 50% del software nunca es empleado por el usuario final. En las aulas se gesta parte del problema y en ellas está en gran medida la solución. El estudiante y el docente deben estar concientes que el propósito no es hacer un programa conforme el maestro lo dice para obtener la calificación máxima o al menos para no reprobar; la finalidad principal es aprender a crear un software de calidad, conforme a criterios técnicos específicos. La siguiente lista fue tomada y enriquecida de un libro clásico realizado por Bertrand Meyer3. Cualidades que rodean al software: coherencia entre el software y los objetivos de la empresa, costo de compra-venta razonable y garantía de soporte y actualización. Corrección: “es la capacidad de los productos software para realizar con exactitud sus tareas [y sin errores], tal y como se definen en las especificaciones”. Funcionalidad: “es el conjunto de posibilidades que proporciona un sistema”. Facilidad de uso: “es la facilidad con la cual personas con diferentes formaciones y aptitudes pueden aprender a usar los productos software y aplicarlos a la resolución de problemas. También cubre la facilidad de instalación, de operación y de supervisión”. Atractivo: el software, además de ser correcto y fácil de usar, debe ser visualmente atractivo, pues de esta manera contribuirá a que el usuario se sienta motivado a usarlo, independientemente de que lo haga por iniciativa propia o por necesidad laboral. Robustez: “es la capacidad de los sistemas de software de reaccionar apropiadamente ante condiciones excepcionales”. Eficiencia: “es la capacidad de un sistema software para exigir la menor cantidad posible de recursos hardware, tales como tiempo del procesador, espacio ocupado de memoria interna y externa o ancho de banda utilizado en los dispositivos de comunicación”. Compatibilidad: “es la facilidad de combinar unos elementos de software con otros”. Portabilidad: “es la facilidad de transferir los productos software a diferentes entornos hardware y software”. Seguridad: es la capacidad de los sistemas software para proteger sus diversos componentes (programas, datos, etc.) contra modificaciones y accesos no autorizados. 2 Estudio de Johnson et. al. en 2001, citado en Schach, Stephen. Ingeniería de Software Clásica y Orientada a Objetos. Mc Graw Hill, 6ª. edición. México, 2006. pág. 6. 3 Meyer, Bertrand. Construcción de software Orientado a Objetos. Prentice-Hall. Segunda edición. Madrid, 1999.

págs. 3-13.

Programación básica en C y Java (elaboró: José Luis López Goytia) 26 / 141

Oportunidad: “es la capacidad de un sistema de software de ser lanzado cuando los usuarios lo desean, o antes”. Acorde al presupuesto: junto con la oportunidad, es la capacidad que un sistema tiene de completarse con el presupuesto asignado o por debajo del mismo. Facilidad de mantenimiento: que el software realizado pueda adaptarse con relativa facilidad a nuevos requerimientos. Desde un primer curso se debe avanzar en el logro de esas características, expresando de manera explícita los puntos que faltarían para llegar a la calidad deseada. Los siguientes pueden ser criterios generales de un curso introductorio de programación: � Es conveniente fomentar una gama amplia de ejercicios de diversa índole e incorporar todos aquéllos

propuestos por los estudiantes, aunque adaptados al avance del curso. � Los ejercicios deben ser acordes al avance temático y deben poder resolverse con los conceptos

explicados hasta ese momento. Aunque puede darse el caso que los estudiantes tengan que investigar instrucciones por su cuenta.

� Los requerimientos deben darse por escrito y resolver cualquier ambigüedad antes de pasar al diseño

del algoritmo. Una persona externa o el propio docente harán el rol del usuario, evitando que el estudiante defina los requerimientos. Desde luego, pueden aceptarse mejoras propuesta por el alumno.

� Los programas deben ser realizados conforme a las especificaciones, considerando los casos

especiales que puedan darse, entregados a tiempo y debidamente documentados. � Las pantallas deben ser claras para el usuario y sin faltas de ortografía. � Ante varias posibilidades de sintaxis, se preferirá aquélla aceptada por la mayoría de los

compiladores o bien por reglas estándares. � La aplicación de subrutinas debe hacerse atendiendo a criterios técnicos de modularidad y facilidad

de mantenimiento (que se comentarán en el capítulo correspondiente). 5.2. El método de cascada aplicado a un curso introductorio de programación

Quizá la primer forma en que se desarrolló un programa es la de tener una idea general de lo que se hace y programarlo. Cuando al fin hace lo que deseamos –y después de unas pruebas muy generales- se presenta al profesor, quien detecta errores y nos pide modificaciones. A la desvelada de sábado y domingo se añade la del miércoles para, al fin, presentarlo correctamente (ver figura 5-1).

Programación básica en C y Java (elaboró: José Luis López Goytia) 27 / 141

Figura 5-1. . La programación sin aplicar metodologías de desarrollo.

Ahora cambiemos un poco los sustantivos y observemos el resultado.

Quizá la primer forma en que se desarrolló un sistema es la de tener una idea muy general de lo que

hace y desarrollarlo. Cuando al fin se hace lo que deseamos –y después de unas pruebas muy generales- se presenta a un directivo de la empresa, quien detecta errores y nos pide modificaciones. A los seis meses de trabajo se añaden otros tres para, al fin presentarlo correctamente.

Definitivamente, trabajar sin aspectos metodológicos adecuados difícilmente puede llevar a buen término un desarrollo de software. Solamente una labor realizada con calidad en cada uno de sus pasos y con base en una metodología acorde al proyecto –y seguida en forma disciplinada- puede dar un sistema confiable y correcto. En caso contrario, las quejas de los usuarios serán frecuentes y será conveniente tener siempre nuestro curriculum vitae bien preparado, por si es necesario buscar otro trabajo.

Algunas de las frases más escuchadas en el área de desarrollo de software: “ni les creas; nunca entregan las cosas a tiempo” (usuarios refiriéndose al área de informática); “ni saben lo que quieren ni te dan información completa” (informática refiriéndose a usuarios); “dejó el sistema echo un desmadre” (desarrolladores refiriéndose a los desarrolladores que trabajaron antes en el sistema); “dice una cosa y luego se echa para atrás” (todos refiriéndose a todos). Una metodología de trabajo trata de garantizar un software de calidad. Lo que sirva para ese propósito debe fomentarse. Si algún paso o documentación no contribuye a esa meta, debe adecuarse o eliminarse totalmente. La metodología vigente más conocida es el método de cascada, la cual consta de varios pasos que deben ejecutarse en forma secuencial (ver cuadro 5-1). Tomamos las etapas de uno de los mejores libros sobre gestión de proyectos informáticos que hemos conocido4. El método de cascada ha recibido cuestionamientos serios. Entre los más significativos: la falta de una etapa previa al análisis en la cual se autoriza el proyecto y que el software se pruebe hasta el final. Sin embargo, sigue siendo vigente para proyectos de corta duración y cuyos requerimientos no cambian a lo largo del mismo. De hecho, todas las metodologías actuales lo retoman en gran medida, haciéndole modificaciones prácticas y conceptuales.

4 McConnell, Steve. Desarrollo y Gestión de Proyectos Informáticos. McGraw-Hill. España, 1998. Pág. 158-159.

Programación básica en C y Java (elaboró: José Luis López Goytia) 28 / 141

En nuestro caso, será nuestra base, aunque agregaremos algunos elementos de otras metodologías, como el diseño guiado por pruebas de Programación Extrema5. Para metodologías de mayor alcance pueden consultarse Proceso Unificado, Scrum o Programación Extrema.

Cuadro 5-1. Las etapas del método de cascada Etapa Objetivo Análisis de requerimientos

Establecer sin ambigüedades los requerimientos del sistema a realizar.

Diseño Diseño general del sistema a nivel interno: estructura de bloques y base de datos. Codificación y depuración

Realización del software en el lenguaje de programación elegido.

Pruebas Pruebas del software para constatar que funciona correctamente. Mantenimiento Modificaciones al software cuando ya está en funcionamiento.

Reflexión 5-1. ¿Qué estrategia utilizar en la enseñanza de la programación?

Existen distintos puntos de vista para la enseñanza de la programación. El primero propone que el estudiante trate a los lenguajes de programación como conceptos algorítmicos, por lo cual sus ejemplos sólo los da en pseudocódigo. El segundo intenta ir al código inmediatamente, dejando de lado los ejercicios centrados en el diseño de la solución. Ambos tienen su razón de ser y sus riesgos. No puede lograrse la solución de problemas de mediana complejidad sin el planteamiento abstracto de la solución, expresado con algún tiempo de diagrama o pseudocódigo. Por otra parte, si no se lleva la solución planteada a código, no hay aplicación concreta y no podemos estar totalmente seguros de que nuestros algoritmos realmente funcionan. Nosotros nos inclinamos por un método mixto: llevar a los estudiantes a un primer ejemplo que involucre un pequeño código tan pronto como sea posible, a fin de que los estudiantes perciban mejor el contexto de trabajo. Posteriormente, en cada rubro combinar ejercicios de codificación con otros sobre la lógica del algoritmo y pruebas de escritorio para tratar de que el alumno pueda visualizar los conceptos independientemente del lenguaje en que se codifique finalmente. Esta propuesta reconoce implícitamente que deben diversificarse las estrategias de enseñanza. No existe un único método para aprender.

A continuación describiremos brevemente nuestra forma de trabajo y brindaremos un ejemplo sencillo (no comenzaremos con “hola mundo”). La intención es que desde el inicio usted se familiarice con la forma de trabajo a fin de que siga este método desde su primer trabajo ( ver figura 5-2). Sería recomendable que reprodujera el ejemplo en el equipo de cómputo con ayuda de un profesor o un amigo. Al principio, podrá sentirse desorientado. No se preocupe, tendrá varias formas para no perderse: 1.- La descripción general que se brindará para los distintos elementos en esta introducción. 2.- La explicación detallada en el momento de abordar cada tema en los siguientes capítulos. 3.- La guía del profesor. 5 Para metodologías de mayor alcance pueden consultarse Proceso Unificado, Programación Extrema o Scrum.

Programación básica en C y Java (elaboró: José Luis López Goytia) 29 / 141

Figura 5-2. El trabajo paso por paso para un curso inicial de lenguajes de programación.

El cuadro 5.2 muestra las etapas del método de cascada y la forma en que se reflejan en nuestro curso:

Cuadro 5-2. Adaptación del método de cascada a un curso introductorio de programación Análisis Requerimiento del problema

Diseño de tabla de pruebas. Diseño Diseño de la pantalla con ejemplos reales

Pseudocódigo o equivalente Codificación Codificación en el lenguaje de programación con buenas prácticas de codificación. Pruebas Aplicación del lote de pruebas. Documentación a entregar

Requerimiento, código, tabla de pruebas aplicadas y la pantalla del programa ejecutándose.

Paso 1. Especificación de requerimientos del usuario: en este paso el estudiante debe aclarar cualquier duda del requerimiento incluyendo la realización de cálculos, la delimitación del problema, la aclaración de ambigüedades y la ubicación de casos especiales. De preferencia, deben ser explícitas las validaciones que el programa debe realizar (por ejemplo: que exista la fecha indicada) y aquéllas que por ser un curso introductorio pueden omitirse (como la validación del tipo de dato al capturar).

Reflexión 5-2. Nunca deje que el estudiante sea su propio usuario

Una de las prácticas más comunes en los cursos de programación es que el estudiante define los requerimientos a partir de una idea general. ¡No lo permita! Es primordial que el desarrollar tenga la perspectiva de que trabaja para un usuario final (o para un conjunto de usuarios finales en caso de un software de uso general). Lo más probable es que no convenga recurrir a un usuario final real en un curso introductorio, pero el profesor u otro compañero puede hacer las veces de usuario final. Lo más importante es que quien codifique no defina los requerimientos y el programa terminado sea sometido a pruebas por otro estudiante o el profesor mismo.

Paso 2: Diseño preliminar de la pantalla que se obtendrá al finalizar el programa. Esta pantalla tiene dos finalidades: verificar que no existen dudas del requerimiento y tener una visión del resultado final esperado. Siempre debe hacerse con datos de ejemplo que corresponden a posibles datos reales del usuario. Los datos que provengan de operaciones deben ser calculados a partir de los datos

Programación básica en C y Java (elaboró: José Luis López Goytia) 30 / 141

proporcionados por el usuario. Una recomendación final: utilizar una forma visual que se asemeje lo más posible a la forma en que se verá el programa terminado.

Reflexión 5-3. Sobre la importancia de los requerimientos

No deben dejarse ambigüedades en los requerimientos al empezar la parte del diseño del algoritmo, pues normalmente eso traerá como consecuencia una gran cantidad de reprocesos innecesarios. Prácticamente la mitad del software creado nunca es utilizado por el usuario final y esto se debe en gran parte a errores al establecer los requerimientos. A un grupo de estudiantes se les planteó: “Realice un programa que reciba los tres lados de un triángulo y despliegue su área”. El 45% lo hizo con (base * altura) / 2, lo cual no correspondía a la especificación solicitada. Ese porcentaje bajó a 8% en otro grupo al cual se les dio la fórmula y un ejemplo de cálculo desde el inicio.

Paso 3. Diseño del lote de pruebas que se aplicará al terminar el programa. Este lote de pruebas debe cubrir los diferentes casos típicos y especiales a los cuales se puede enfrentar el programa. Debe de establecerse antes de comenzar el diseño del algoritmo.

Reflexión 5-4. Sobre la consistencia de datos en el lote de pruebas

Las pruebas de un programa deben incluir consistencia de tipos de datos. Por ejemplo: avisar que el usuario tecleó una letra cuando se solicitó un número. En un curso introductorio como éste, se puede suponer que el usuario capturará adecuadamente el tipo de información requerida. Sin embargo, en asignaturas posteriores deberá llenarse tal vacío. A partir del tema de condicionales, conviene que el estudiante también valide la coherencia de los datos. Por ejemplo: antes de obtener el factorial de un número que se verifique que éste no sea negativo (no existen factoriales de números negativos).

Paso 4. Elaborar el algoritmo. Conviene que el estudiante elabore el bosquejo de la solución bajo alguna modalidad (pseudocódigo, diagrama de flujo, etc.). El propósito es que se centre en la lógica del algoritmo y por el momento no piense en la sintaxis. El pseudocódigo se construye con las palabras elegidas por el estudiante. Por ejemplo: leer, desplegar, si, etc. No debieran establecerse reglas demasiado rígidas, aunque sí tiene que reflejar las estructuras de condicionales y ciclos que maneja la programación estructurada. En cuanto al diagrama de flujo, éste puede ser realizado “a mano alzada” pero conforme a las reglas que rigen al mismo. Debe cuidarse en que no consuma demasiado tiempo.

Reflexión 5-5. Sobre el pseudocódigo y los diagramas de flujo

El pseudocódigo es muy útil para representar al algoritmo, pues refleja con cierta libertad al lenguaje en que se codificará. No obstante, puede darse el caso que el estudiante se aleje demasiado de las posibilidades de la programación estructurada, a tal punto que sea imposible codificar lo escrito. Por otra parte, ¿cómo evaluarlo si no

Programación básica en C y Java (elaboró: José Luis López Goytia) 31 / 141

existen reglas formales para su manejo? Por su parte, el diagrama de flujo sigue reglas claras y por lo mismo es más útil desde el punto de vista pedagógico. Aunque consume más tiempo hacer el diagrama de flujo que el mismo código y por ello prácticamente no se emplea a nivel profesional. No existe solución idónea. Cada docente debe tratar de aprovechar las ventajas de cada opción tratando al mismo tiempo de minimizar sus inconvenientes.

Paso 5: Elaborar el código. Se realizará la codificación tomando como base el algoritmo diseñado y buenas prácticas de programación (alineación del código, uso de comentarios, etc.). Al terminar, se aplicará el lote de pruebas que se determinó en el paso 3. Recuerde: el programa no está terminado hasta no haber pasado todas las pruebas (y aún así, pudiera haber errores no descubiertos).

Reflexión 5-6. ¡Desde el inicio, las buenas prácticas de programación!

El curso introductorio de programación es el comienzo para formar un arquitecto de software. Así que desde el inicio se tiene que insistir en un desarrollo de calidad, que incluya la parte metodológica (trabajar en base a requerimientos, pruebas al código, documentación, etc.) como la codificación (nombres de variables, alineación, etc.). No debemos dejar para después las buenas prácticas de programación. Muchos hábitos que no se forman desde un inicio ya nunca se pueden recuperar.

Paso 6: Conjuntar la documentación. Se conjunta la documentación del programa que se entregará: requerimiento, código, tabla de pruebas y pantalla final. Conviene aclarar que algunas actividades no se reflejan en la documentación final del sistema, sólo ayudan a avanzar más rápido y evitar reprocesos. En nuestro caso, el diseño preliminar de la pantalla y el diseño del algoritmo no se incorporarán a la documentación final.

Reflexión 5-7. ¿Qué documentación se pide en los programas?

Una de las carencias más fuertes en el entorno docente es un análisis de la documentación a pedir en los cursos introductorios de programación. Por lo común se solicita únicamente el código fuente y con ello se pierde implícitamente la liga entre los requerimientos, el código fuente y las pruebas. Desde el inicio debe acostumbrarse al estudiante a documentar de forma completa un programa: cuando menos el requerimiento, el código y las pruebas a que fue sometido.

5.3. Nuestro primer ejemplo: el promedio de dos números Aquí va nuestro primer ejemplo. Muy probablemente usted sienta que es un problema relativamente artificial y que ningún usuario real solicitaría algo tan sencillo. Tiene razón, pero es un buen ejemplo para efectos didácticos. Paso 1: requerimientos del usuario:

Hacer un programa que reciba dos números y despliegue su promedio.

Programación básica en C y Java (elaboró: José Luis López Goytia) 32 / 141

Paso 2: diseño preliminar de la pantalla que se obtendrá al finalizar el programa.

Bienvenido. Este programa obtiene el promedio de dos números. Teclee sus datos separados por un espacio.

6 9 El promedio es 7.5 Oprima cualquier tecla para terminar…

Paso 3: diseño del lote de pruebas que se aplicará al terminar el programa.

Datos del usuario Resultado esperado 6 9 El promedio es 7.5 6 m En nuestro caso, el programa “tronará”. En cursos posteriores deberá validarse

que el tipo de dato sea correcto. Paso 4: elaborar el algoritmo.

comentario: pseudocódigo para obtener el promedio de dos números desplegar el texto “Bienvenido” solicitar los 2 datos

promedio = (dato1 + dato2) / 2 desplegar promedio

despliega “Oprima cualquier tecla para terminar…”

Paso 5: elaborar el código.

// Programa que recibe 2 datos y devuelve su promedio. #include <conio.h> #include <stdio.h> main() { float dato1, dato2, promedio; printf("Bienvenido.\n\n"); printf("Este programa obtiene el promedio de dos numeros.\n"); printf("Teclee sus datos separados por un espacio.\n"); scanf("%f %f", &dato1, &dato2); promedio = (dato1 + dato2) / 2; printf("El promedio es%4.1f", promedio); printf("\n\n Oprima cualquier tecla para terminar..."); getch(); }

Paso 6: conjuntar la documentación a entregar.

Requerimiento: Hacer un programa que reciba dos números y despliegue su promedio.

Código: // Programa que recibe 2 datos y devuelve su promedio. #include <conio.h> #include <stdio.h> main() { float dato1, dato2, promedio;

Programación básica en C y Java (elaboró: José Luis López Goytia) 33 / 141

printf("Bienvenido.\n\n"); printf("Este programa obtiene el promedio de dos numeros.\n"); printf("Teclee sus datos separados por un espacio.\n"); scanf("%f %f", &dato1, &dato2); promedio = (dato1 + dato2) / 2; printf("El promedio es %4.1f", promedio); printf("\n\n Oprima cualquier tecla para terminar..."); getch(); }

Pruebas aplicadas: Datos del usuario Resultado esperado

6 9 El área del triángulo es de 7.5

Pantalla final:

5.4. Un primer acercamiento a la codificación Desmenucemos el código de nuestro primer ejemplo, con la advertencia que se dará únicamente una breve explicación introductoria de cada tema. Esperamos que sea suficiente para que el lector no se sienta completamente perdido; conforme se avance en el libro se ahondará en cada uno de los conceptos. Un programa (código fuente) está escrito en un lenguaje de programación. Dicho código fuente se traduce a un lenguaje entendible para la computadora (código máquina) a través de un software de propósito específico llamado compilador. En la gran mayoría de ocasiones se incorporan fragmentos de código (subrutinas) previamente escritos y compilados por otros compiladores (ver diagrama 5-3). Todo programa debe ser compilado antes de poder ejecutarse.

Figura 5-3. El propósito de un compilador

En nuestro caso, emplearemos el compilador Dev C++ por ser gratuito y de fácil manejo. Este software puede bajarse del sitio Web http://www.bloodshed.net/dev/devcpp.html. En enero de 2011 se encontraba disponible la versión 4.9.9.2 en versión beta. Todos los ejemplos fueron probados en la versión 4.9.8.0.

código fuente código máquina

librerías

Programación básica en C y Java (elaboró: José Luis López Goytia) 34 / 141

Para observar los resultados de un programa debe compilarse (Compile) y posteriormente ejecutarse (Run) desde la opción Execute del propio compilador, como se muestra en el diagrama 1.2.

Figura 5.4. Compilación y ejecución en Dev C++.

El código del programa se explica de manera general en las siguientes líneas:

// Programa que recibe 2 datos y devuelve su promedio. Esta línea es un comentario que describe el propósito del programa. Los comentarios no son tomados en cuenta por el compilador. Puede utilizarse el operador // al inicio de cada línea o bien los operadores /* y */ para iniciar y finalizar los comentarios, respectivamente. #include <conio.h> #include <stdio.h>

Indican las librerías que se utilizarán en el programa. Las instrucciones scanf y getch se encuentra en la librería <conio.h>. En sentido estricto, la librería <stdio.h> es innecesaria en este código. No obstante, en algunos compiladores scanf o getch están en <stdio.h>, por lo cual se mantiene la costumbre de poner siempre ambas librerías. main() {....}

Enmarca a todas las instrucciones del programa. float dato1, dato2, promedio;

Es una declaración de 3 variables de tipo decimal (flotante), llamadas dato1, dato2 y promedio. Las variables pueden cambiar su valor a lo largo del programa y en la mayoría de los casos se recomienda que sólo almacenen datos del tipo indicado. printf("Bienvenido.\n\n"); printf("El promedio es %4.1f", promedio);

Son instrucciones para desplegar. \n equivale a un salto de línea. %f señala que se desplegará el valor de una variable de tipo flotante. Al poner .1 entre el % y la f se está indicando que el valor se redondeará a un decimal. El 4 significa que se reservan cuatro espacios para desplegar el valor de la variable. scanf("%f %f", &dato1, &dato2);

Permite leer datos del teclado. %f señala que es información de tipo flotante (decimal). Observe que el nombre de cada variable está antecedido por un &.

Programación básica en C y Java (elaboró: José Luis López Goytia) 35 / 141

promedio = (dato1 + dato2) / 2;

Asigna realiza la operación mostrada y el resultado lo almacena en promedio. Los paréntesis son indispensables, como en álgebra, aunque en programación no se utilizan los corchetes para este tipo de instrucciones. getch()

Permite detener la pantalla hasta que se oprima cualquier tecla. Si no se pone en el programa la pantalla desaparecerá tan rápido que no se podrá ver el resultado. Debemos aclarar que no es la única forma de solucionar este problema.

5.5. ¿Por qué lenguaje C para un primer curso de programación? Existe discrepancia acerca del lenguaje más adecuado para empezar a programar. Las propuestas abarcan C, Pascal y Java, entre otras. La decisión se vuelve más difícil porque no es predecible hacia donde se dirigen los lenguajes de programación (ver figura 5-5). Java y C conservan el más alto nivel de penetración, aunque Java ha ido disminuyendo su participación. Lenguajes relativamente nuevos como Python van ganando popularidad, mientras Microsoft –con C# y Visual Basic-, así como PHP para ambientes Web conservan un nicho significativo. Conviene aclarar que SQL predomina en el campo de base de datos a pesar de no figurar en la imagen. Pascal tiene su ventaja en ser un lenguaje muy enfocado a los cimientos pedagógicos, aunque casi no es empleado en el campo profesional. Java es muy utilizado, pero su orientación a objetos prácticamente no se explotaría poco en un curso introductorio. Lenguaje C tiene un sitio envidiable en mercado, particularmente en código embebido; no obstante, su sintaxis en muchas ocasiones confunde a los estudiantes. Nos inclinamos hacia lenguaje C, sin dejar de reconocer que también Pascal o Java podrían ser opciones viables. Sin importar la elección, hay que hacer hincapié en la lógica de programación, la metodología de trabajo y los principios básicos de la programación estructurada. Curiosamente, rubros que se suelen descuidar en gran parte en cursos introductorios, los cuales se centran casi siempre en la sintaxis del lenguaje.

Figura 5.5. Tendencias de los lenguajes de programación

6.

6 Tomado de www.tiobe.com [accesado el 14 de enero de 2011].

Programación básica en C y Java (elaboró: José Luis López Goytia) 36 / 141

Por otra parte, no es fácil para una persona o una institución establecer un conjunto de asignaturas ligadas coherentemente con el objetivo de aprender software a nivel profesional ni crear las condiciones adecuadas para ello, aunque ya existen planteamientos preliminares interesantes7. En términos generales, se pueden señalar las siguientes recomendaciones: 1.- Debe integrarse en forma coherente y natural con los demás conceptos manejados, pues el conocimiento es acumulativo. 2.- Debe crear un ambiente de trabajo lo más cercano posible al campo laboral o de investigación, pues allí se reflejará el conocimiento (¡El alumno aprende de lo que vive!). 3.- Debe ser viable en las condiciones existentes, sobre todo en lo que respecta a la infraestructura existente. Si se desea aprender programación Web, una posible liga de un curso de lenguaje C con posteriores asignaturas sería la siguiente:

5.6. Hacia el enfoque por competencias… y más allá Uno de los cambios más significativos a nivel educación superior es el enfoque basado en competencias. Las competencias engloban el saber qué (conocimiento), saber hacer (habilidad), saber ser (valores) y saber convivir (trabajo colaborativo). Vistas en ese contexto, las competencias representan un gran avance frente a una transmisión pasiva del conocimiento. Las competencias específicas que el estudiante puede cubrir con este material son acordes con el planteamiento de muy diversas escuelas. A manera de ejemplo, transcribimos las que se indican en la unidad de aprendizaje de Lógica de Programación de la UPIICSA (IPN)8:

o “Analiza el planteamiento de un problema específico para llegar a un requerimiento preciso, delimitado y sin ambigüedades.”

o “Bosqueja, valida y depura el algoritmo de solución para el requerimiento especificado.”

o “Codifica y prueba el algoritmo propuesto, basado en estructuras de control de lenguaje C.”

o “Modela, codifica y prueba un diseño modular que resuelva el requerimiento especificado.”

o “Codifica y prueba el algoritmo propuesto, basado en tipos de datos compuestos de lenguaje.”

Esas competencias se reflejan a lo largo del texto en el conocimiento de las estructuras de la programación estructurada y su codificación (saber conocer); la resolución práctica de algoritmos y su

7 Ver López Goytia, José Luis; Oviedo Galdeano, Mario; Hacia un replanteamiento de la enseñanza de la programación. 3er. Congreso Internacional de Educación Media Superior y Superior 2010. Gobierrno del Distrito Federal. México, 2010. 8 Programa analítico de la unidad de aprendizaje de Lógica de Programación, de la UPIICSA del IPN. Junio de 2010.

Lenguaje C

Java básico

(POO)

Servlets y

JSP

Framework

de Java

Programación

para móviles

Diagrama 1.4. Una posible liga del curso de C con el aprendizaje del desarrollo de software.

Programación básica en C y Java (elaboró: José Luis López Goytia) 37 / 141

traslado a su correspondiente codificación, incluyendo pruebas de escritorio y de usuario final (saber hacer); la comprensión crítica del porqué es necesario buenas prácticas de programación y el seguimiento de normas metodológicas (saber ser) y la ejecución de ejercicios en equipos de trabajo (saber convivir). Se da como premisa que actualmente la creación de programas es una labor de un equipo interdisciplinario y no el producto de un programador talentoso y solitario. Partimos de una supuesto que tiene que ver con el enfoque constructivista de la educación y que coincide con algunos estudios sobre la formación de los conceptos en el cerebro humano: el estudiante formará su aprendizaje significativo a partir de la interacción cotidiana con el medio, es decir, con base en sus vivencias y sus utopías9 (reiteramos: ¡el estudiante aprende de lo que vive!). Por ello, los conceptos de calidad de software no deben ser un tema aislado; tienen que reflejarse en la construcción de cada programa. Por otra parte, el estudiante y el docente deben tomar en cuenta que la parte racional de toda persona es inseparable de su parte emocional10. Difícilmente un alumno aprenderá programación sino siente emoción por la asignatura, y esa búsqueda del gusto por el desarrollo de software depende del docente, el entorno escolar y social, y el propio estudiante. Finalmente, es sumamente interesante mostrar un diagrama en torno a los niveles de proximidad al conocimiento11. El material de este libro es el comienzo para aprender desarrollo de software. A este curso seguirán otros de la propia carrera para cubrir el primer nivel (Nivel I: la carrera). No obstante, esas asignaturas son sólo un subconjunto del conocimiento que ya existe sobre esta la programación (Nivel II: conocimiento conocido). Dicho conocimiento se enriquecerá con las investigaciones actuales (Nivel III: la investigación actual) y en un futuro no tan inmediato con paradigmas y enfoques que aún no han nacido (Nivel IV: El imaginario del porvenir).

I. Carrera

II. Conocimiento conocido

III. La investigación actual

IV. El imaginario del porvenir

material base

fijo

ilimitado y disperso

NIVELES DE PROXIMIDAD AL CONOCIMIENTO

¿el docente conoce las respuestas?

parcialmente

no

¿se evalúa

en la escuela?sí no

¿quién lo hace?

consultorías

empresas

tecnológicas

universidades

¿se conoce

la respuesta?

síno

marco conceptual y

aplicación inmediata

no

parcialmente

escuelas

Figura 5-6. Los niveles de proximidad al conocimiento

9 Hofstadter, D. (2009). Yo soy un extraño bucle. México. Edit. Tusquets. y Hofstadeter, D.. Gödel, Escher, Bach: un eterno y grácil bucle. Edit. Tusquets-CONACyT. México, 1987. 10 Damasio, Antonio. El error de Descartes. Drakontos Bolsillo. España, 2006. 11 López Goytia, José Luis. Prospectiva de los lenguajes de programación. Xxxx Congreso . México, 2010.

Programación básica en C y Java (elaboró: José Luis López Goytia) 38 / 141

El estudiante que sólo se concrete a sus cursos, sin buscar por él mismo el conocimiento, renuncia a la mayor parte del saber que necesitará en su vida profesional y personal. Por ello en muchos ejercicios propuestos se tendrá que buscar información adicional a la presentada en el texto, aunque cuidando que esté al alcance del estudiante por medios relativamente sencillos. En muchos casos se presentarán ejercicios avanzados que pueden representar un reto para los alumnos más aventajados (a juicio del profesor, bien pudieran valer puntos extras en el curso). Por otra parte, es necesario inculcar en los estudiantes un espíritu crítico frente a la información que reciben, sobre todo porque gran parte de ella viene de Internet: un abanico gigantesco que está lleno de verdaderas joyas, sucesos triviales y mentiras. Una de las estrategias que pueden dar mejor resultado es que el estudiante compruebe la veracidad de la información e incluso haga sus propios experimentos. Por citar un ejemplo, no se alinea al código porque sí, sino porque facilita el mantenimiento. Un ejercicio que casi nunca se realiza es poner a un estudiante a modificar el código realizado por otros alumnos: uno con código alineado y otro sin alinear. ¡Comprobemos en la práctica lo que la teoría dicta! Pero eso tiene una implicación muy interesante: los docentes tenemos que entender que nuestras afirmaciones pueden someterse a crítica y a pruebas. Un estudiante puede venir, diccionario en mano, a demostrarnos una falta de ortografía a pesar de que nosotros afirmáramos un día antes que la una palabra estaba escrita correctamente. ¿Eso debe ser motivo de burla? Bajo ninguna circunstancia. Simplemente es reconocernos iguales como seres humanos. ¿Cómo reenfocar la educación para que tanto alumnos como maestros vayan hacia la profundización del conocimiento como un concepto de vida? ¿Qué hacer para que ello les cause placer, cuándo muchísimas personas no suele comprar libros y las actividades culturales no se integran a su vida cotidiana?12 El enfoque por competencias no aborda la complejidad de esos cuestionamientos, quizá los más difíciles que la educación debe resolver.

5.7 Los primeros ejercicios He aquí algunos ejercicios sugeridos, que deben ser realizados con un proceso de entrada, cálculo y salida sencillos (sin condicionales ni ciclos). Lo más importante: debe seguirse el método de trabajo sugerido.

o Realice un programa que reciba el lado de un cuadrado y calcule su área. o Realice un programa que reciba el diámetro de un círculo y calcula su área.

o Realice un programa que reciba un número y despliegue su raíz cuadrada.

o Una tienda departamental promueve descuento sobre descuento en algunas temporadas.

Calcula el primer precio y, al monto con ese descuento, le aplica un segundo descuento. Por ejemplo: si a una prenda cuyo costo original es de $100.00 le colocara un 40% más 20% adicional, su precio final sería $48.00. Realice un programa que permita ingresar el monto original y ambos descuentos. Como resultado arroje el precio final.

12 Para mayor información en el caso de México, puede verse: Conaculta. Encuesta Nacional de hábitos, prácticas y consumo culturales. México, 2010.

Programación básica en C y Java (elaboró: José Luis López Goytia) 39 / 141

Reflexión 5.8 ¿Cómo saber si el método de trabajo funciona? En diferentes casos, hemos pedido a los estudiantes que dibujen la pantalla de salida a partir del requerimiento. Entre un 50% y un 75% lo hacen diferente a como lo habíamos imaginado. A su vez, ese porcentaje puede dividirse en dos vertientes: dan una interpretación diferente al problema porque su redacción es ambigua y no revisan adecuadamente la redacción. Por citar un ejemplo: se les pide recibir el diámetro de un círculo y calcular su área (área=π*radio2). Los estudiantes toman directamente el dato sin considerar que le piden el diámetro al usuario y la fórmula utiliza el radio. Las evaluaciones no deben considerar únicamente la codificación; deben validar también si el software se realizó conforme a las especificaciones establecidas.

Programación básica en C y Java (elaboró: José Luis López Goytia) 40 / 141

Capítulo 6. EL PARADIGMA DE LA PROGRAMACIÓN ESTRUCTURADA El desarrollo de software tiene poco más de seis décadas, tomando como referencia el nacimiento de la ENIAC, en 1946. Se trata de un área joven si la comparamos con ciencias como la física, química o matemáticas, que adquirieron una madurez desde hace siglos. En sus primeros años, la programación se basaba en instrucciones muy cercanas al código máquina y necesitaba un conocimiento del hardware sobre el cual se trabajaba. Realizar una multiplicación –o alguna instrucción de complejidad similar- requería de al menos una docena de instrucciones. Era la época del lenguaje ensamblador, que hoy se sigue empleando en microprocesadores y código embebido. Posteriormente se agruparon instrucciones y se inventaron programas que traducían estos comandos a lenguaje ensamblador. Nacieron de esta forma COBOL (para aplicaciones administrativas), Fortran (para aplicaciones científicas) y BASIC como lenguaje de uso general. Sin embargo, el estilo de programar en estos lenguajes presentaba un problema: el salto incondicional, representado sobre todo por la instrucción goto de BASIC, la cual permitía ir directamente a cualquier línea de código. El empleo continuo del salto incondicional se convirtió en un gran dolor de cabeza para dar mantenimiento a los programas. Para solucionar ese problema nació la programación estructurada, cuyos representantes más notorios fueron Pascal y C. La programación estructurada propugnaba porque todos los programas se basaran en tres estructuras básicas:

a) Secuencia.- el código se ejecutaba de arriba hacia abajo. La secuencia queda implícita a la hora de leer, compilar y ejecutar los programas.

b) Condicionales- elementos de decisión que permitían realizar un bloque de instrucción si se cumplía una condición y, opcionalmente, llevar a cabo otro conjunto de comandos si no se cumplía.

c) Ciclos.- repetir una secuencia de instrucciones mientra se cumpliera una condición.

Aunque conservaban el salto incondicional hacían hincapié en que éste no se empleara. El avance natural en esta línea fue el nacimiento de la Programación Orientada a Objetos (POO), cuyo representante más famoso es Java. La POO retoma los tipos de datos y las rutinas de la programación estructurada y crea con ellos una estructura de mayor potencia: las clases. Este breve recorrido intenta contextualizar a la programación estructurada, aunque resulta demasiado simplificado y deja fuera de manera injusta a lenguajes de propósito específico como el ya mencionado COBOL y a otros paradigmas, entre ellos los dedicados al campo de Inteligencia Artificial. Tampoco describe lo sucedido con lenguajes para modo gráfico como Visual Basic (basado en la programación estructurada), que posteriormente se transformaría en Visual .NET (basado en la Programación Orienta a Objetos - POO). En cuanto a la programación WEB, ésta se basa parcialmente en la programación estructurada (ASP clásico, PHP, JavaScript, etc.) y en la Programación Orientada a Objetos (J2EE, tecnología .NET, etc). En síntesis, la programación estructurada sigue siendo vigente en dos sentidos: varios lenguajes todavía la aplican y su conocimiento es base para el aprendizaje de la Programación Orientada a Objetos.

Programación básica en C y Java (elaboró: José Luis López Goytia) 41 / 141

6.1. ¿Qué es un algoritmo? Como ya se mencionó, los ciclos y las condicionales son las estructuras básicas de la programación estructurada y sobre éstas deben fincarse la creación de algoritmos básicos. Un algoritmo es un conjunto de pasos debidamente ordenados y sin ambigüedades, que en un tiempo finito dan la solución a un problema claramente planteado. Un algoritmo puede plantearse de diversas formas, desde la palabra escrita hasta mecanismos formales. Entre los más conocidos están: Pseudocódigo: se escriben en el idioma nativo (el español, en nuestro caso) palabras cercanas a las instrucciones de un lenguaje de programación. Es muy recomendable como paso intermedio entre el problema y la codificación de la solución en un lenguaje de programación (Pascal, C, Java, etc.). Diagrama de flujo: establece de manera gráfica la solución del problema, utilizando íconos para cada estructura de programación (ciclos, decisiones, etc.). Sumamente utilizado para aspectos didácticos. UML (Unified Modeling Languaje): la forma de diagramación utilizada para programación orientada a objetos. Su conjunto de símbolos se aplica para todas etapas del proceso de desarrollo de software. 6.2. ELEMENTOS BÁSICOS EN LA LÓGICA DE PROGRAMACIÓN La gran ventaja y, al mismo tiempo, la gran desventaja del pseudocódigo es que no existen reglas formales para escribirlo. Cada persona puede establecer sus propios criterios. Ciertamente, esto puede dar lugar a ambigüedades. Para evitarlo, deberá orientarse al alumno hacia las estructuras básicas de control y establecer claramente los pasos a seguir. Sugerimos al inicio limitar el pseudocódigo a las siguientes convenciones. Variables. Una variable es un lugar de memoria que puede guardar un valor, el cual puede cambiar a lo largo del programa. Cuando se asigna un nuevo valor, el valor anterior se pierde. Debe ser identificado por un nombre determinado, el cual sólo se utilizará para esa variable. Todas las variables a utilizar deben ser declaradas al inicio del programa. Nombres de identificadores. Los identificadores son nombres que ubican a los diferentes elementos de los programas: el nombre del propio, programa, las variables, etc. Reglas de prioridad. La ejecución de los operadores aritméticos se realiza con las mismas reglas de álgebra. Primero se harán las multiplicaciones y divisiones, y posteriormente las sumas y restas. De esta forma 8 + 3 * 4 será igual a 20. Igual que en matemáticas, se pueden utilizar paréntesis para forzar a que en primer lugar se haga lo que esté dentro de ellos. Cabe aclarar que en programación sólo se usan los paréntesis circulares. Leer se utilizará para recibir un dato del teclado. Por ejemplo: leer x significará que se recibirá el valor de la variable x del teclado. Desplegar se manejará para mostrar un mensaje textual o el valor de una variable en la pantalla. Condicionales. Indican una decisión. Ciclos. Indica que una acción se realizará mientras se cumpla la instrucción señalada.

Programación básica en C y Java (elaboró: José Luis López Goytia) 42 / 141

6.3. CONDICIONALES Las condicionales establecen una decisión con la estructura siguiente:

si (condición) bloque 1 de instrucciones en caso contrario bloque 2 de instrucciones termina si

En diagrama de flujo se identificaría como sigue: sí no (opcional)

Diagrama 6-1. La representación de condicionales en diagrama de flujo. En prácticamente todos los lenguajes de programación el “si” se identifica con un if y “en caso contrario” con un else. El si (condición) es obligatorio, mientras el en caso contrario (bloque 2 de instrucciones) es opcional. Existen diversas formas para indicar sin ambigüedades hasta donde abarca cada bloque de instrucciones: llaves en lenguaje C, begin-end en Pascal, endif en SQL, etc. A manera de ejemplo, suponga que se desea recibir tres calificaciones, desplegar el promedio e indicar si la calificación es o no es aprobatoria. La calificación mínima aprobatoria es 8. El pseudocódigo quedaría como sigue: declarar a, b,c y promedio como decimales desplegar “Por favor, teclee sus tres calificaciones” leer a, b y c promedio = (a + b + c) / 3 desplegar “El promedio es “ desplegar promedio si promedio >= 8 desplegar “APROBADO” en caso contrario desplegar “REPROBADO” termina si

instrucciones instrucciones

Programación básica en C y Java (elaboró: José Luis López Goytia) 43 / 141

6.4. CICLOS Los ciclos Indican que una acción se realizará mientras se cumpla la instrucción señalada. Tendrá la siguiente estructura: mientras (condición) instrucciones termina mientras Hay que hacer hincapié que la condición significa mientras que. Una condición que siempre se cumpla generaría un ciclo infinito. Por el contrario, una condición que nunca se cumpla implicaría que no se ejecutaran las instrucciones del cuerpo del ciclo ni una sola vez. Un error muy frecuente es no identificar claramente aquéllo que es repetitivo (va a ir dentro del ciclo) con lo que debe hacerse una sola vez antes o después del ciclo (debe ir fuera del ciclo). El resultado de este error suele dar resultados equivocados o generar ciclos infinitos. En diagrama de flujo, los ciclos se representan de la siguiente manera: Su diagrama es como sigue: Sí no

Diagrama 6-2. La representación de ciclos en diagrama de flujo. La condición mientras que se identifica con la palabra while en casi todos los lenguajes.

Cuadro 2-1. Los ciclos en lenguaje C y Java while Mientras que, se valida al inicio por lo cual el bloque de instrucciones puede no

ejecutarse ni una sola vez. do-while Mientras que, se valida al final por lo cual el bloque de instrucciones se ejecuta al

menos una vez. Una instrucción muy similar en el lenguaje Pascal es el repeat. for Por lo general se aplica cuando se conoce de antemano las veces que se repetirá

un conjunto de instrucciones. Aunque en lenguaje C tiene la misma potencialidad que el while.

instrucciones

Programación básica en C y Java (elaboró: José Luis López Goytia) 44 / 141

Al igual que en condicionales, existen diversas formas para indicar sin ambigüedades hasta donde abarca cada bloque de instrucciones: llaves, begin-end, endWhile, etc., según el lenguaje de programación. Aparte del ciclo mencionado existen otras variantes, cuya conceptualización varía un poco según el lenguaje de programación. En lenguaje C y Java se manejan tres posibilidades: A manera de ejemplo, suponga que se desea recibir tres calificaciones y desplegar el promedio.. El pseudocódigo quedaría como sigue: declarar dato, suma y promedio como decimales declarar i como entera suma = 0 desplegar “Por favor, teclee sus tres calificaciones” mientras (i < 3) leer dato suma = suma + dato termina mientras promedio = suma / 3 desplegar “El promedio es “ desplegar promedio

6.5. EJERCICIOS DE CONSTRUCCIÓN DE LÓGICA A PARTIR DEL PROBLEMA

Reflexión 2-1. Sobre los ejercicios de construcción de lógica

Algunos docentes suelen comenzar con ejercicios de lógica del tipo: “¿cómo se hacen huevos con jamón?”. Consideramos que una primera analogía de este tipo es útil para resaltar su parecido con algunos elementos de un algoritmo, pero sin ir más allá, pues son actividades lejanas a la formalidad de un lenguaje de programación. ¿Qué es válido y qué no en ejemplos como éste? ¿Con qué criterios establecer esta diferenciación? Existe un riesgo latente de que el estudiante quede con la impresión de que se trabajará “a contentillo del profesor”.

Con las descripciones vistas hasta este punto tenemos los elementos suficientes para iniciar ejercicios de construcción de lógica. Un primer bloque de ejercicios puede partir de una descripción general de un requerimiento que debe ser llevado a detalle. En este bloque pueden incorporarse todas las sugerencias de los estudiantes que sean viables con la aplicación de secuencias y ciclos. Se recomienda la siguiente estrategia de trabajo:

1) En la primera etapa los estudiantes buscarán la forma de cálculo y se pondrán de acuerdo sobre la interpretación del requerimiento. El “usuario final” para definir cualquier ambigüedad podrá ser el profesor o algún estudiante familiarizado con el problema. Por cuestión formativa, el estudiante que actúe como usuario final deberá diseñar el lote de pruebas y aplicarlo al programa final, pero él no será el que realice la codificación. Esta etapa abarcará los primeros tres pasos del método de trabajo expuesto: especificación de requerimientos del usuario, diseño preliminar de la pantalla y diseño del lote de pruebas.

Pudiera darse la pantalla desde un inicio o que el mismo grupo la definiera.

2) En la siguiente etapa se tiene que elaborar el algoritmo que dé solución al problema a través de

pseudocódigo o diagrama de flujo. Este algoritmo será realizado por un estudiante y verificado por

Programación básica en C y Java (elaboró: José Luis López Goytia) 45 / 141

otro; sólo podrán usar operadores, condicionales y ciclos (omitir por el momento, arreglos, archivos y subrutinas). Los estudiantes que ya tengan familiaridad con un lenguaje de programación puedan codificar dicho algoritmo para confirmar su validez.

La siguiente es una lista de ejercicios propuestos, con los dos primeros elementos: especificación de requerimientos del usuario y diseño preliminar de la pantalla. Por razones de espacio, se omitió en la pantalla las palabras de bienvenida y despedida, que sí deberían estar en el programa definitivo.

o Una librería ofrece descuentos por volumen: 3% a partir de tres libros; 5% si son más de 3

libros y 10% si son más de 10. Los descuentos no se acumulan. Realice un programa que reciba el costo del libro, el número de libros y despliegue el total a pagar.

Señale el costo unitario del libro: 120 Indique el número de libros: 3 El total a pagar es 349.20

o Realice un programa que calcule el promedio de varias calificaciones redondeado a un

decimal. Al inicio se le preguntará al usuario cuantos números va a capturar (suponga que el usuario capturará los datos adecuadamente).

¿Cuántas calificaciones se van a capturar? 3 Captúrelas: 7 6 4 El promedio es 5.7

o Realice un programa que calcule el promedio final de tres calificaciones redondeado a un entero. Si el promedio es mayor o igual a 6 el resultado se redondeará al entero más cercano; en caso contrario, no se tomarán en cuenta los decimales.

Indique las tres calificaciones a promediar: 6 2 9 El promedio final es 5

o Realice un programa que calcule el promedio de varios números. El usuario capturará datos y al final pondrá un -1 para señalar que ya no existen más datos (suponga que el usuario capturará los datos adecuadamente).

Capture las calificaciones (indique un -1 para finalizar): 7 6 4 -1 El promedio es 5.7

o Un trabajador tiene un salario por hora (el salario diario supone 8 horas laboradas). Si que trabaja más de 8 horas recibe pago por horas extras. De la novena a la undécima percibe el doble; de la décimo segunda en adelante es el triple. Las horas pueden ser fraccionadas. Realice un programa que reciba el salario diario y las horas trabajadas; a partir de esos datos señale el monto a recibir por el salario normal, las horas extras y el total.

Indique el sueldo diario: 200 Indique las horas trabajadas: 9.5 Sus percepciones en el día son: 275.00

Programación básica en C y Java (elaboró: José Luis López Goytia) 46 / 141

o Un apostador asiduo tiene la costumbre de apostar si atina al número que resulta al tirar un dado. Si lo logra gana $5.000; en caso contrario, pierde $1.00. Él comienza con $7.00 y el juego termina cuando gana $6.00 o pierde todo su capital.

¿Qué número saldrá en el dado? 5 El dado arrojó un 4. Acaba de perder $1.00 Su saldo es $6.00 ¿Qué número saldrá en el dado? 5

o En una feria había un kiosco llamado “menor-7-mayor”, que se refería a un juego con dos dados. Quien deseaba participar apostaba $1.00 a alguna de tres opciones: menor: 2-6; b) 7 exacto; c) mayor: 8-12. Si apostaba a menor y resultaba un valor entre 2 y 6, ganaba $1.00. De forma similar, si apostaba a mayor y resultaba un valor entre 8 y 12 ganaba $1.00. Si apostaba al 7 y salía exactamente ese valor, ganaba $5.00. Si no atinaba en su apuesta, perdía $1.00 en cualquiera de los tres casos. Iniciará con $5.00 y el juego termina cuando llega a $10.00 o pierde todo su capital.

A) Menor B) 7 C) Mayor 2-6 8-12 ¿Cuál es su apuesta? A Lo sentimos, el número fue 9 (mayor) Su saldo es de $4.00 A) Menor B) 7 C) Mayor 2-6 8-12 ¿Cuál es su apuesta?

A continuación se varios ejercicios sencillos en donde los estudiantes tienen que iniciar el trabajo desde la elaboración de las pantallas.

o Recibir los tres lados de un triángulo y desplegar su área. o Capturar los tres lados de un triángulo y desplegar si es isósceles, escaleno o equilátero. o Capturar 3 números y desplegar el mayor de ellos. o Recibir “n” datos y calcular su promedio y su desviación estándar.

6.6. PRUEBA DE ESCRITORIO La “prueba de escritorio” consiste en tratar de seguir paso a paso lo que hace el algoritmo. En otras palabras, tratar de actuar como si uno fuera el equipo de cómputo. Hay que hacer hincapié en ello: no debe pensarse “lógicamente” ni como “se supone que debe ser”. Es menester “desprenderse de la condición humana” y tratar de actuar como máquina, siguiendo instrucción por instrucción lo que sucede en el código. No hay una representación formal de la prueba de escritorio. Sugerimos poner una casilla por cada variable e ir anotando su valor. En el caso de ciclos, realizar un cuadrado y utilizar una columna por cada iteración. Para ejemplificar, suponga que se tiene la siguiente definición del problema:

Programación básica en C y Java (elaboró: José Luis López Goytia) 47 / 141

o Realizar un programa que lea un número y despliegue su factorial. El factorial de un número n está dada por la siguiente serie: 1 * 2 * 3 * … * (n-1) * n. El factorial de 0 es 1 y no existen factoriales de números negativo.

Este programa obtendrá el factorial de un número. Teclee el número, por favor 5 Su sumatoria es 120

El lote de pruebas es el siguiente:

valores resultados ¿Pasó la prueba? 5 120 0 1 -3 No existen factoriales de números negativos

El pseudocódigo que se presenta está descrito a continuación.

variables a utilizar: i, suma, despliegue “Bienvenido” despliegue “Este programa obtendrá el factorial de un número.” despliegue “Teclee el número, por favor” leer dato si dato < 0

despliega “No existen factoriales de números negativos” en caso contrario i = 1 acumula = 1 mientras i <= dato acumula = acumula * i i = i + 1 despliegue “Su factorial es” despliegue acumula despliegue “Oprima cualquier tecla para continuar…”

Y la prueba de escritorio se coloca a continuación: Antes del ciclo i ___1___ acumula ___1___ dato ___5___ Durante el ciclo Número de repetición 1 2 3 4 5

Valor de acumula 1 2 6 24 120

Valor de i 2 3 4 5 6

Observe que se sale del ciclo cuando ya no se cumple la condición. El valor final de acumula fue 120, que era el resultado esperado.

Programación básica en C y Java (elaboró: José Luis López Goytia) 48 / 141

6.7. EJERCICIOS PROPUESTOS PARA PRUEBAS DE ESCRITORIO A continuación se señalan varios ejercicios para realizar la prueba de escritorio. Observará que muchos de ellos se refieren a calcular un promedio, aunque con diferentes variantes. La intención es que el estudiante visualice que un problema puede solucionarse de diferentes formas y que existen errores clásicos “escondidos”, independientemente del procedimiento utilizado. • Indique el resultado del siguiente pseudocódigo tal y como está escrito. Suponga que los valores de

a, b y c son 8 9 y 10, respectivamente

1 numdatos = 1 2 leer a 3 numdatos = numdatos + 1 4 leer b 5 numdatos = numdatos + 1 6 leer c 7 numdatos = numdatos + 1 8 promedio = a + b + c / numdatos 9 desplegar promedio

Reescriba la(s) línea(s) que están mal escritas.

# de línea Corrección

• Dado el siguiente código:

mayor = b si (b > a) y (b > c) mayor = b if (c > a) y (c > b) mayor = c despliega "El resultado es:” despliega mayor

Indique el resultado de la tríadas señaladas a continuación, tal y como está

Datos de prueba Resultado 7 8 9 8 9 8 8 9 9 9 8 7

o ¿Qué mensaje desplegará el siguiente pseudocódigo tal y como está escrito suponiendo que el usuario responde 5.5 cuando se le pide el dato?

x = calificación proporcionada por el usuario si (x > 5) Desplegar “aprobado” termina si si (x < 5) Desplegar “reprobado” termina si

Programación básica en C y Java (elaboró: José Luis López Goytia) 49 / 141

o Ordene el siguiente pseudocódigo para obtener el promedio de 3 números

declarar dato, suma y promedio como decimales declarar i como entera desplegar “El promedio es “ desplegar “Por favor, teclee sus tres calificaciones” desplegar promedio i = 0 i = i + 1 leer dato mientras (i < 3) promedio = suma / 3 suma = 0 suma = suma + dato termina mientras

• ¿Qué desplegará en pantalla el siguiente pseudocódigo tal y como está escrito? Suponga que el usuario teclea: 5 6 7 8

suma = 0 n = 4 i = 1 mientras i <= n despliega “Teclee los 4 datos: “ leer dato suma = suma + dato i = i + 1 fin de mientras despliega “El promedio es: despliega suma / i

o El siguiente pseudocódigo pretende obtener el promedio de 3 números. Reescríbalo correctamente sin cambiar el nombre de las variables.

definir suma, dato y i como entero i = 1 leer dato mientras i < 3 suma = suma + dato i = i + 1 termina mientas promedio = suma / i

desplegar promedio

• Este programa pretende obtener el promedio de 3 números. ¿Qué valor tendrá promedio al final del

siguiente pseudocódigo, suponiendo que se ejecuta sin problemas? 1 define promedio como entero 2 define dato1 = 9, dato2 = 6, dato3 = 8 3 promedio = dato1 + dato2 + dato3 / 3 Reescriba la(s) línea(s) que están mal escritas.

Programación básica en C y Java (elaboró: José Luis López Goytia) 50 / 141

# de línea Corrección

• ¿Qué valor tendrá x y w después de las siguientes instrucciones? x = 1

w = x mientras (x <=5) w = w * x x = x + 1 termina mientras

o ¿Qué valor tendrá x después de las siguientes instrucciones (cada inciso es independiente)?

a) x = 8 x = x + 2 b) x = 8 x = x + 2 x = 5 x = x * x c) w = 8 t = 5 x = w * t d) a = 8 b = 10 c = 9 x = a + b + c / 3

e) x = 8 * 6 + 2 * 6 / 2 + 1

Programación básica en C y Java (elaboró: José Luis López Goytia) 51 / 141

Capítulo 7. Los primeros elementos para codificar en lenguaje C

7.1. Un programa para calcular descuentos Como base para una explicación posterior, presentamos la documentación de un programa sencillo para calcular descuentos Requerimiento:

Hacer un programa que reciba el precio normal de un producto y su correspondiente descuento. Como salida, entregue el precio final (con el descuento incluido).

Código: // Programa que calcula el descuento de un producto. #include <conio.h> #include <stdio.h> main() { float precio, descuento, preciofinal; printf("Bienvenido.\n\n"); printf("Este programa le ayuda a calcular el precio "); printf("con descuento de un producto.\n"); printf("Teclee el precio normal y su porcentaje de descuento.\n"); scanf("%f %f", &precio, &descuento); preciofinal = (precio - precio * descuento / 100); printf("El precio final es %4.1f", preciofinal); printf("\n\n Oprima cualquier tecla para terminar..."); getch(); }

Pruebas aplicadas:

Datos del usuario Resultado esperado 100 40 El precio final es 60.0 100 0 El precio final es 100.0

100 100 El precio final es 0.0 100 110 El precio final es -10.0

Este resultado, aunque correcto desde el punto de vista aritmético, no tiene sentido en el “mundo real”. En una versión posterior del programa (cuando ya se haya visto el tema de condicionales) deberá validarse que el descuento capturado esté entre 0 y 100.

Pantalla final:

7.2. La labor del compilador y el uso de librerías En el capítulo 1 se introdujo el primer ejemplo del código y la forma general de trabajo. En el capítulo 2 se trabajó sobre la lógica de programación “en abstracto” (sin pensar en el código). En este capítulo abordaremos las reglas que debe cubrir la codificación. ¿Por qué estamos trabajando en la forma descrita? En algunos sentidos, codificar se asemeja a jugar un deporte. Se deben conocer las reglas que rigen el juego. No obstante, eso sería insuficiente sin

Programación básica en C y Java (elaboró: José Luis López Goytia) 52 / 141

estrategias para ganar el partido y “jugadas prefabricadas”. La codificación son las reglas; la lógica de programación conforma la estrategia. Prosiguiendo con esta analogía, prácticamente nadie esperaría poder jugar bien un deporte sin practicar cotidianamente. No obstante, un gran número de estudiantes aspira a aprender a programar estudiando dos días antes del examen. Adentrémonos, pues, en la lógica del compilador. Como ya se mencionó, un programa (código fuente) está escrito en un lenguaje de programación que el compilador traducirá a código. Para lograr esa labor el compilador realiza algunas tareas:

1) Revisa que no se introduzcan elementos incorrectos en el programa. Por ejemplo: variables que no fueron declaradas previamente.

2) Revisa que las sentencias escritas estén construidas conforma a las reglas establecidas por el

compilador.

3) Convierte el código fuente a lenguaje máquina, enlazándolo previamente con las rutinas que se elaboraron por otros programadores y están contenidas en las librerías correspondientes.

Cada rutina es un subprograma que realiza una función específica, puede o no recibir datos desde fuera de la rutina (llamados parámetros) y devolver o no algún. Cada librería reúne rutinas de con un propósito en común. Para usar estas rutinas se le debe avisar al compilador a través de la palabra include, al inicio del programa . En la siguiente tabla se muestra una selección de algunas de las subrutinas precompiladas más usuales en lenguaje C: Algunas subrutinas se encuentran en diferentes librerías, según el compilador y la versión. Por lo común basta poner stdio.h y conio.h para acceder a las rutinas de entrada-salida más comunes (scanf, printf, getch). Existen rutinas que sólo obedecen a determinados compiladores. Cabe destacar gotoxy y clrscr, que funcionan para Turbo C, de Borland, y no están incluidos en Dev C++.

Reflexión 7-1. La frecuente confusión entre los compiladores de C y C++

Los compiladores de C++ están preparados para programación orientada a objetos, aunque pueden ejecutar los códigos de lenguaje C. Las instrucciones cin y cout únicamente las tomará un compilador de C++. Por ello, muchas personas creen que al trabajar en un compilador de C++ están utilizando programación orientada a objetos. Estrictamente, se utiliza programación orientada a objetos al emplear clases, encapsulamiento, herencia, polimorfismo y/o sobrecarga. Si sólo se cambia el printf y scanf por cout y cin, respectivamente, se sigue en el paradigma de programación estructurada.

La rutina principal: main

Cabe aclarar que todo programa que se desee ejecutar de manera independiente debe tener al menos una rutina principal, que lleva el nombre de main. Suele variar el requerimiento en cuanto a la rutina

Programación básica en C y Java (elaboró: José Luis López Goytia) 53 / 141

principal: main. Los siguientes casos cubren los compiladores que hemos tenido la oportunidad de probar.

main() { // sin return (usada en Dev C++) } void main() { // sin return } main() { return 0; // en realidad puede ser cualquier valor entero }

Reglas para los nombres de los identificadores Toda subrutina, variable y constante debe llevar un nombre irrepetible a lo largo del programa. Dicho nombre –conocido como identificador- debe ser declarado antes de poder emplearse y es la forma en que el compilador ubica el elemento del cual se trata.

• Deben comenzar con una letra • No deben tener espacios, guiones ni caracteres especiales (ñ, acentos, etc.). Se admite el

carácter de subrayado, aunque ya no es algo usual. • Algunos lenguajes (C y Java, entre otros) hacen distinción de mayúsculas y minúsculas, mientras

que otros (Basic y SQL, entre otros) no lo toman en cuenta. • Deben de ayudar a identificar el propósito de la variable o subrutina. • En lenguaje C permanece la costumbre de manejar todo en minúsculas. No obstante, en Java y

tecnología .NET se acostumbra la “notación de camello”: la primera letra de cada palabra comienza con mayúscula (excepto la primera). Por ejemplo: promedioGeneral.

En nuestro programa tenemos los siguientes identificadores: precio, descuento y preciofinal. Comentarios Los comentarios son fragmentos del código que orientan sobre aspectos que deben ser tomados en cuenta a futuro por el propio programador u otros programadores. También sirven para dar mayor claridad al código, orientar sobre la forma en que éste enlaza con los requerimientos y brindar información del contexto de desarrollo (Vg. versión del compilador empleado). En lenguaje C existen dos formas de comentarios: // a partir de aquí el resto de la línea es un comentario /* esto es un comentario que puede abarcar varias líneas */ Un ejemplo de un comentario útil podría ser el siguiente: /* el siguiente código responde a modificaciones en las prestaciones de la empresa a partir del 1 de enero de 2011 */ Procure no emplear comentarios para situaciones que resultan obvias para quien maneja el lenguaje. El siguiente sería un comentario innecesario: s = ( a + b ) / 2; // s es el promedio de a y b

Programación básica en C y Java (elaboró: José Luis López Goytia) 54 / 141

7.3 TIPOS DE DATOS Todas las variables y constantes deben ser de un determinado tipo de datos. Estas consideraciones abarcan subrutinas, constantes y variables. Los más usuales son: entero, decimal y carácter, que se identifican por int, float y char, respectivamente. En lenguaje C no existen directamente datos lógicos ni cadenas. Un tipo de datos define: a) el tipo de valores que se puede almacenar; b) el espacio y forma de almacenamiento; c) el tipo de operaciones que se pueden aplicar. En lenguaje C y Java, una declaración especifica un tipo de dato y a continuación una lista de una o más variables de ese tipo. Opcionalmente, a cada una de ellas puede asignársele un valor inicial. Por ejemplo: float suma = 0.0, promedio; En algunos casos es mejor dejar una variable por renglón para colocar comentarios pertinentes.

float suma = 0.0; /* suma de las calificaciones semestrales */ float promedio = 0.0; /* promedio general del alumno */

En lenguaje C existen los siguientes tipos de datos básicos int entero normal float decimal normal char carácter de un solo byte double decimal de doble precisión

En lenguaje C –y en todos los lenguajes de programación– cada constante y cada variable tiene un espacio físico asignado dentro de la memoria temporal con un determinado número de bits, el cual queda distribuido en ciertos términos prefijados. Rebasa los límites del presente libro tratar la forma en que se almacenan los diferentes tipos de datos. No obstante, quien codifique debe tener en cuenta los límites de las variables manejadas a fin de utilizar el formato adecuado.

Reflexión 7-2. Un nombre que no podía existir por un tipo de dato inadecuado

En los primeros años de este siglo los padres de una niña mexicana quisieron ponerle un nombre náhuatl (el náhuatl es el dialecto más hablado en el país, con antecedentes desde la época prehispánica). La respuesta de las autoridades fue que escogieran otro nombre, pues el sistema no manejaba esos caracteres (por cierto, una de tantas formas de discriminación que existen hacia los indígenas de México). Los padres, en una mezcla de valentía y fueron apelando la decisión hasta llegar a la Suprema Corte de Justicia de la Nación, quien por fin les dio la razón: debía modificarse el sistema. Ese caso se dio en un Sistema Manejador de Base de Datos, pero suelen darse situaciones semejantes en todos los lenguajes de programación.

Programación básica en C y Java (elaboró: José Luis López Goytia) 55 / 141

A manera de ejemplo, explicaremos lo que sucede con el tipo de datos entero (int). En la mayoría de los compiladores el tipo entero queda almacenado en 2 bytes o, lo que es lo mismo, 16 btis. Con 16 bits se pueden formar 216 combinaciones = 65536 combinaciones. Si esas combinaciones se dividen entre 2 quedan 32,768 negativos, el cero y 32,767 números positivos. No puede haber número entero que salga de esos límites si fue declarado de tipo int13. Aunque lenguaje C conserva la posibilidad de utilizar modificadores para ampliar o reducir el número de bytes asignados. Hay modificadores que se aplican a todos los tipos básicos. Pueden combinarse los modificadores referentes al espacio con los referentes al signo.

short disminuye el espacio asignado al tipo de dato long aumenta el espacio asignado al tipo de dato unsigned el tipo de dato trabajará únicamente con valores positivos signed el tipo de dato trabajará con valores positivos y negativos

Los modificadores signed y unsigned no cambian el espacio asignado. Los tipos de datos son signed por omisión. Los modificadores se pueden anteponer al tipo de dato (Vg.: un entero corto se indicará como short int). Si se utilizan para enteros, puede omitirse la palabra int. El tamaño en bytes para short, normal y long varía de compilador a compilador. Lo único seguro es que

tamaño de short <= tamaño normal <= tamaño long A continuación se muestra una tabla donde se señala el número de bytes para cada tipo de dato, con base en el estándar ANSI C 14:

Cuadro 7-1. Los tipos de datos en ANSI C

Tipo Tamaño aproximado en

bits Rango mínimo

Char 8 -128 a 127 unsigned char 8 0 a 255 Int 16 -32768 a 32767 unsigned int 16 0 a 65535 short int 16 Igual que int long int 32 -2147483648 a 2147483647 unsigned long int 32 0 a 4294967295 Float 32 6 dígitos de precisión Double 64 10 dígitos de precisión long double 128 10 dígitos de precisión

Los datos de tipo float y double se pueden manejar mediante notación científica. Es válido asignar un valor como 123.456e-7 o bien 0.12E3 “Las constantes long se escriben según la forma 123L. Cualquier constante entera cuyo tamaño se demasiado grande en una variable int se toma como long”.15

13 Valide si esta situación se cumple en su compilador. Puede darse que ocupa 4 bytes en lugar de 2, como en Dev

C++. 14 Adaptado de: Schildt, Herbert; C. Manual de bolsillo. McGrawHill. Segunda edición. España, 1992.

15 Kernighan, Brian W.; Ritchie, Dennos M.; El lenguaje de programación C; Prentice Hall; México, 1986.

Programación básica en C y Java (elaboró: José Luis López Goytia) 56 / 141

Para especificar un valor hexadecimal se comienza con 0x; para un valor octal, con cero. Como en el siguiente ejemplo: int dec = 243; /* 243 en decimal. La notación común y corriente */ int hex = 0x80; /* 128 en decimal */ int oct = 012 ; /* 10 en decimal */

C no tiene algunos tipos de datos que sí existen en otros lenguajes (como datos lógicos y cadenas), pero ofrece alternativas que pueden suplir estas carencias, las cuales se explicarán en su momento. A partir de los tipos de datos que el lenguaje proporciona se pueden hacer estructuras que los agrupan o combinan. Estas posibilidades se verán en los temas referentes a arreglos, registros (estructuras), uniones y apuntadores. Entrada y salida de datos Las entradas y salidas de datos se hacen a través de scanf y printf, respectivamente. El formato es similar al siguiente ejemplo: printf("El precio final es %4.1f", preciofinal); El %f señala que allí se mostrará un valor, el cual se indicará después del cierre de las comillas. .1 se refiere al número de decimales y 4 a los lugares que se reservarán para el despliegue el dato (incluyendo el punto decimal y la parte fraccionaria). Se utiliza una d para enteros, una c para carácter y una f para tipo flotante. Para leer la sintaxis es similar al ejemplo siguiente. Observe que en este caso el nombre de la variable va precedida por un amperson scanf("%f %f", &precio, &descuento); Es muy común equivocarse en la sintaxis, sobre todo en el cierre de las comillas y el empleo de amperson. Las consecuencias en estos casos son impredecibles. Conversiones de tipo

En sentido estricto los tipos de datos de C lo que indican es el espacio que reservarán en la memoria, no un tipo de dato funcional. Dicho de otra forma, un char no es un caracter propiamente, sino un byte; puede ser desplegado como un caracter o como un dato numérico. Esta posibilidad es uno de los mayores atractivos de C -y uno de los mayores dolores de cabeza. Es responsabilidad del programador indicar adecuadamente los tipos de datos en las entradas y salidas.

El programa siguiente maneja una variable de tipo caracter y la despliega como un entero. El programa se ejecuta y muestra el valor que corresponde a ese caracter, conforme el código ASCII (para la A es 65).

#include <conio.h> main() { char letra; letra = 'A'; printf("Desplegaré la <A>: %6d", letra); printf("\n\nOprima cualquier tecla para continuar..."); getch(); }

Programación básica en C y Java (elaboró: José Luis López Goytia) 57 / 141

Los lenguajes de programación hacen conversiones automáticas de tipos de datos bajo reglas predeterminadas. Cuando se combinan diferentes tipos de datos en una expresión numérica, el de tipo “inferior” es ascendido al de tipo “superior” y el resultado se deposita internamente en un tipo “superior”. Por ejemplo: la suma de un número entero y un número decimal se almacenará automáticamente en la memoria de la máquina como un número decimal; char y short se convierten en int, int se convierte en long y float se convierte en double. A manera de ejemplo, el resultado del siguiente programa es 2.0, debido a que el resultado de 7/3 es almacenado internamente en una variable de tipo entero (un tipo entero entre un tipo entero se almacena en un tipo entero). Esa variable interna de tipo entero –que ya no tiene decimales- es asignada a aux.

#include <conio.h> main() { float aux = 7/3; printf("El resultado de 7/3 es %f", aux); printf("\n\n Oprima cualquier tecla para terminar..."); getch(); }

La solución más sencilla es que alguno de los números se expresa como variable de tipo decimal, puesto que un número entero entre un decimal se almacenará internamente en una variable decimal. Es decir: aux = 7 / 3.0. Claro está, esta solución no aplicaría si en lugar de expresiones indicadas directamente se tuvieran variables. En este caso se aplicaría una coerción de tipos, cuya sintaxis es

(tipoDeDato) (expresión a convertir). La línea en cuestión quedaría de la siguiente forma: aux = (float) a / b; /* a y b son variables de tipo entero */

Reflexión 7-3. Hacia la portabilidad del código

Nunca asuma que el lenguaje hará las conversiones necesarias entre los tipos de datos manejados, incluso en los casos en que no marque ningún error. Asegúrese que así sea y –en caso necesario- hágalo de manera explícita.

Tipos de datos en otros lenguajes de programación

Los tipos de datos más comunes en los lenguajes de programación son entero, decimal, carácter, cadena de caracteres y lógico. Otros tipos de datos se fueron incorporando conforme surgían nuevas necesidades, sobre todo en relación a lenguajes de programación para ambientes visuales y sistemas manejadores de bases de datos: tiempo, fecha, gráfico, video y musical, entre otros.

Un lenguaje de programación o un Sistema Manejador de Base de Datos permiten variantes entre los tipos de datos, que afectan al rango de valores que se pueden guardar o a la precisión de éstos. Por ejemplo: un entero normal en muchos compiladores abarca del -32768 al +32767 y ocupa 2 bytes de memoria, mientras un entero corto va del -128 al +127 y abarca un solo byte. En otros casos estas diferencias se deben a formatos manejados por diferentes proveedores o diseños más eficientes, como el caso de los distintos formatos para guardar imágenes (BMP, GIF, etc.).

Programación básica en C y Java (elaboró: José Luis López Goytia) 58 / 141

Declaración implícita y explícita En algunos lenguajes (como C o Java) tienen que declararse antes de ser usadas; en otros, como BASIC, el compilador detecta a una nueva variable y la declara por si misma. En apariencia, pareciera que la segunda opción es menos engorrosa, pero en realidad trae más trabajo. Imagine la siguiente instrucción: numeroDeAlumnoos = numeroDeAlumnos + 1

Casi es seguro que el programador se refiere a la misma variable, pero la escribió mal. Si fuera BASIC, asumiría que es una nueva variable y las consecuencias serían impredecibles. Para evitar errores como el anterior se prefiere siempre que el compilador obligue a declarar las variables e indique un error cuando se intenten utilizar una variable no declarada.

3.4 Sentencias y operadores Todos los lenguajes de programación manejan operadores de tipo numérico, lógicos, para manejo de cadena de caracteres y, muy posiblemente de otro tipo, cada uno de ellos con una función específica. Algunos son operadores nativos del lenguaje y otros forman parte de sus bibliotecas.

Todos los operadores se rigen por reglas de prioridad. De hecho, por las reglas de prioridad matemáticas que conocemos desde siempre, aplicables también en álgebra y hojas de cálculo. Cabe aclarar que en programación la multiplicación se identifica a través de un asterisco (*). La expresión 3 + 4 * 2 dará como resultado 11, porque por regla de prioridad la multiplicación se debe hacer primero. Cuando dos operadores tienen igual prioridad, las operaciones se ejecutan de izquierda a derecha en el caso de operadores numéricos.

En el ejemplo de este capítulo está una expresión basada en reglas de prioridad: preciofinal = (precio - precio * descuento / 100);

El orden de evaluación es el siguiente:

a) Primero se ejecuta precio * descuento b) El resultado se divide entre 100 c) Se realiza precio menos lo obtenido de los dos incisos anteriores d) El valor de los tres pasos se asigna a preciofinal

Reflexión 7-4. Reglas de prioridad en la calculadora de Windows

La calculadora de Windows en versión científica respeta las reglas de prioridad, mientras que en modo estándar no las toma en cuenta.

La multiplicación se indica por el operador *, el cual es de uso obligado. La expresión 4ac ó 4(a)(c) no son válidas en programación. Lo correcto es: 4 * a * c.

Los paréntesis permiten agrupar operaciones que deben hacerse primero –igual que en matemáticas. En ocasiones se colocan por otros dos motivos: a) mejoran la claridad del código; b) el programador no se acordaba de las reglas de prioridad y para asegurarse los puso. Son motivos válidos. Sin embargo, no abuse del uso de paréntesis, porque su instrucción puede hacerse más difícil de entender.

Programación básica en C y Java (elaboró: José Luis López Goytia) 59 / 141

El uso de espacios entre datos y operadores es optativo. El programa ejecutará correctamente 4*a*c ó 4 * a * c. Recomendamos dejar un espacio entre cada operador y dato. En general, el programa se hace más sencillo de leer y la vista se cansa menos.

Al usar operadores debe tenerse cuidado con la combinación de tipos de datos. Sería ilógico aplicar una operación de multiplicación entre un caracter y un entero. La mayoría de lenguajes marcará un error al compilar. No obstante, algunos –como lenguaje C- sí realizarán la operación. El resultado por lo común será absurdo.

En cuanto a los operadores de condición, no existe una regla que señale el orden de evaluación y eso en ocasiones trae errores de programación. Imagine la siguiente condición:

si (no se ha llegado al final del archivo) y (el empleado está activo)

En este caso basta con que una de las dos condiciones sea falsa para que toda la operación sea falsa. De hecho, si la primera es falsa no es posible evaluar la segunda. Pero no podemos dar por sentado que el compilador es “inteligente”. En términos prácticos: no ponga dos condiciones si, cuando una de ellas es falsa, ya no es posible valuar la segunda. La solución al problema anterior consiste en separar las condiciones:

si (no se ha llegado al final del archivo) si (el empleado está activo)

C dispone de los operadores típicos de un lenguaje de programación: suma, resta, multiplicación, división, etc. Adicionalmente posee dos operadores: incremento en uno (++) y decremento en uno (--). Estos operadores pueden emplearse como prefijos (antes de la variable) o como sufijos (después de la variable), según si su valor se incremente antes o después de usarse. Cuando la instrucción está sola no hay diferencia, pero en combinación con otras instrucciones puede dar diferentes resultados. Por ejemplo: suponga que n vale 5. x = n++; pone un 5 en x, pero x = ++n; coloca un 6 en x. En ambos casos, n vale finalmente 6.

Las expresiones de asignación abreviadas de C son muy útiles. En estos casos debe tenerse presente que la asignación relaciona a la variable con toda la parte derecha de la expresión.

x *= y + 1 es equivalente a x = x * ( y + 1) y no a x = x * y + 1 Este tipo de operadores son más fáciles de entender si se “leen coloquialmente”. x += 2; debe interpretarse como “súmale 2 a x”.

Lista de operadores en C

C tiene una gama de operadores bastante grande y proporciona una gran libertad al programador. Por lo mismo, es indispensable tener un cuidado especial con la prioridad y significado de los operadores. La lista completa de los operadores de C (sin funciones de biblioteca) es la siguiente:

Cuadro 7-2. Los operadores en ANSI C y su priorodad

Tipo Operador Significado Prioridad campos de registros -> campo de un registro 14 campos de . campo de un registro 14

Programación básica en C y Java (elaboró: José Luis López Goytia) 60 / 141

registros índice de arreglos [ ] índice de un arreglo 14 Paréntesis ( ) agrupa expresiones que deben valuarse primero 14 a nivel de bits ~ complemento a uno 13 Apuntadores & envía la dirección que apunta a una variable 13 Apuntadores * usa la dirección que apunta a una variable 13 Aritmético -- decremento en 1 de una variable 13 Aritmético ++ incremento en 1 de una variable 13 conversión de tipos (tipo) conversión de tipos 13 espacio en bytes sizeof cálculo del espacio necesario en bytes 13 lógico ! negación (NOT) 13 aritmético / división 12 aritmético * multiplicación 12 aritmético % residuo de una división entera 12 aritmético - Resta 11 aritmético + Suma 11 a nivel de bits >> desplazamiento a la derecha 10 a nivel de bits << desplazamiento a la izquierda 10 de comparación <= mayor o igual que 9 de comparación > mayor que 9 de comparación <= menor o igual que 9 de comparación < menor que 9 de comparación != ¿es diferente a? 8 de comparación == ¿es igual que? 8

a nivel de bits & y (AND) a nivel de bits 7

a nivel de bits ^ O exclusiva (XOR) a nivel de bits 6

a nivel de bits | O (OR) a nivel de bits 5

lógico && y lógico (AND) 4

lógico || ó lógico (OR) 3

de asignación ?: asignación condicional 2

de asignación %= asigna a la variable el residuo de su valor actual con la expresión indicada 1

de asignación &= asigna a la variable su valor actual con un AND a nivel bits de la expresión indicada 1

de asignación >>=

asigna a la variable su valor actual con un desplazamiento a la derecha de los lugares que señala la expresión indicada 1

de asignación <<=

asigna a la variable su valor actual con un desplazamiento a la izquierda de los lugares que señala la expresión indicada 1

de asignación |= asigna a la variable su valor actual con un OR a nivel bits de la expresión indicada 1

de asignación ^= asigna a la variable su valor actual con un XOR a nivel bits de la expresión indicada 1

de asignación /= asigna a la variable su valor actual dividido con la expresión indicada 1

de asignación *= asigna a la variable su valor actual multiplicado con la expresión indicada 1

Programación básica en C y Java (elaboró: José Luis López Goytia) 61 / 141

de asignación -= asigna a la variable su valor actual restado con la expresión indicada 1

de asignación += asigna a la variable su valor actual sumado con la expresión indicada 1

de asignación = Asignación 1 En su momento, se verán a detalle la mayoría de los operadores aquí expresados. El siguiente programa ejemplifica el empleo de operadores aritméticos: #include <conio.h> main() { int r = 8, s = 3; printf("Partimos de r = 8 y s = 5\n\n"); r += s + 7 * 2; printf("Aplicamos r += s + 7 * 2. Ahora r = %d\n\n", r); s = r % 8; printf("Dividimos r entre 8. El residuo lo ponemos en s. Ahora s = %d\n\n", s); s++; printf("Sumamos 1 a s. Ahora s = %d\n\n", s); printf("La división entera entre r y s es... %d\n\n", r/s); printf("Preguntamos si r >= s... %d\n", r >= s); printf(" (recuerde que si el resultado es verdadero devuelve el valor de 1)"); printf("\n\nOprima cualquier tecla para continuar..."); getch(); }

Existen subrutinas que están en las bibliotecas de lenguaje C y que –en la práctica- actúan como si fueran operadores, entre ellas la raíz cuadrada. Para emplear estas subrutinas es necesario revisar su sintaxis y la biblioteca a la cual pertenecen. La raíz cuadrada (sqrt) devuelve la raíz cuadrada de un número mayor o igual que cero. Tiene la siguiente cabecera:

#include “maht.h” double sqrt (double num);

A continuación un programa que ejemplifica su uso:

#include <conio.h> #include <math.h> main() { double x = 10.0; printf("La raíz cuadrada de 10 es %6.2f\n", sqrt(x)); printf("\n\nOprima cualquier tecla para continuar..."); getch(); }

3.5 Sala de código en primeros auxilios Una persona transcribió los siguientes programas de una fuente fidedigna y pudo comprobar que corrían adecuadamente: cumplen con el requerimiento y la lógica de programación es adecuada. No obstante, cometió varios errores al transcribirlos: errores “de dedo”, alguna línea omitida o la modificación inadvertida de algún. ¿Podría ayudarlo a que corrieran adecuadamente? (seguramente todos ellos le resultarán conocidos). Sugerencia: primero trate de ubicar las equivocaciones en papel. Posteriormente, transcriba el código y verifique si logró ubicar todas las fallas.

Programación básica en C y Java (elaboró: José Luis López Goytia) 62 / 141

// Programa que calcula el descuento de un producto. #include <conio.h> #include <studio.h> main() { float precio, descuento, preciofinal; printf("Bienvenido.\n\n"); printf("Este programa le ayuda a calcular el precio "); printf("con descuento de un producto.\n"); printf("Teclee el precio normal y su porcentaje de descuento.\n"); scanf("%f %f", precio, descuento); preciofinal = (precio - precio * descuento / 100); printf("El precio final es %4.1f", preciofinal); printf("\n\n Oprima cualquier tecla para terminar..."); getch(); }

#include <conio.h> main() { float aux = 7/3; printf("El resultado de 7/3 a un decimal es %5.1f", aux); printf("\n\n Oprima cualquier tecla para terminar..."); getch(); }

/* Programa que recibe 2 datos y devuelve su promedio. #include <conio.h> #include <stdio.h> main() { float dato1, dato2, prommedio; printf("Bienvenido.\n\n"); printf("Este programa obtiene el promedio de dos numeros.\n"); printf("Teclee sus datos separados por un espacio.\n"); scanf("%f %f", &dato1, &dato2); promedio = dato1 + dato2 / 2; printf("El promedio es%4.1f", promedio); }

include <conio.h> include <stdio.h> Main() { Printf("Hola mundo."); // y nos volvemos a ver Getch(); }

7.5. Ejercicios para practicar codificación A continuación, algunos ejercicios para practicar la codificación, aún sin utilizar condicionales ni ciclos.

Programación básica en C y Java (elaboró: José Luis López Goytia) 63 / 141

o Hacer un programa que despliegue al azar un número del 1 al 6, simulando la tirada de un dado.

o Hacer un programa que despliegue al azar un número del 2 al 12, simulando la tirada de dos dados.

o Hacer un programa que capture el monto a entregar por un “cajero automático”, que tiene billetes

de 500, 100 y 20 pesos, además de monedas de 5 y 1 (las denominaciones no cambian). El “cajero” debe determinar las cantidades a entregar de cada denominación, conforme la pantalla siguiente:

Bienvenido a su cajero “La amabilidad ante todo”. ¿Qué cantidad desea recibir? 528 Le entregamos billetes:

1 de 500 0 de 100 1 de 20

y monedas: 1 de 5 3 de 1

¡Gracias! Oprima cualquier tecla para salir…

o Hacer un programa que lea una letra y despliegue aquélla que se encuentra tres lugares adelante en el alfabeto (según el código ASCII).

o Hacer un programa que lea un número entero y entregue ese número elevado a la cuarta

potencia. El programa debe admitir como resultado cifras que pueden llegar hasta mil millones.

o Cuando se llega a este código a, b y c están definidos como enteros. Antes de la línea 1 las variables a, b y c tienen los valores de 7, 8 y 9, respectivamente:

1 mayor = a; 2 if (b > a) && (b > c) 3 mayor = a; 4 if (c > a) && (c > b) 5 mayor = c; 6 printf("El resultado es: %d\n", mayor);

a) Indique el resultado de la siguiente tríada según la lógica del algoritmo: Datos de prueba Resultado 7 8 9 8 9 8 8 9 9

b) Realice los cambios que juzgue pertinentes para que el programa corra correctamente. También corrija posibles errores de sintaxis (sólo hay errores en algunas líneas):

Número de línea Corrección

o Realizar un programa que lea tres calificaciones, despliegue el promedio final y diga si el alumno

aprobó o no. La calificación final será el promedio ponderado de las 3 calificaciones, las cuales valen 20%, 30% y 50%, respectivamente. La calificación mínima aprobatoria es 8.

Programación básica en C y Java (elaboró: José Luis López Goytia) 64 / 141

CONDICIONALES EN LENGUAJE C

CONTENIDO

El concepto de condicional Los errores más comunes en el uso de if El uso de condiciones múltiples con base en un valor (case) Ejercicios de condicionales en lenguaje C EL CONCEPTO DE CONDICIONAL (Indice) Todas las condiciones preguntan acerca de una condición (if). Una respuesta afirmativa provocará que se realice el bloque de instrucciones indicada; en caso contrario se realiza un segundo bloque de instrucciones. El primer bloque de instrucciones es obligatorio, mientras el segundo es opcional. Para indicar el inicio y final de cada bloque se emplean llaves; dichas llaves pueden omitirse si el bloque está compuesto por una sola instrucción. En pseudocódigo se expresaría de la siguiente forma:

si (condición) bloque 1 de instrucciones en caso contrario bloque 2 de instrucciones termina si

Un diagrama de flujo los identificaría como sigue: sí no (opcional)

A manera de ejemplo, suponga que se desea recibir tres calificaciones, desplegar el promedio e indicar si la calificación es o no es aprobatoria. La calificación mínima aprobatoria es 8. El pseudocódigo quedaría como sigue: declarar a, b,c y promedio como decimales desplegar “Por favor, teclee sus tres calificaciones” leer a, b y c promedio = (a + b + c) / 3 desplegar “El promedio es “

instrucciones instrucciones

Programación básica en C y Java (elaboró: José Luis López Goytia) 65 / 141

desplegar promedio si promedio >= 8 desplegar “APROBADO” en caso contrario desplegar “REPROBADO” termina si El código quedaría como sigue (es obligatorio que la condición vaya entre paréntesis):

#include <conio.h> main(void) { int a, b, c; float promedio; printf("Por favor, teclee sus tres calificaciones: "); scanf("%d %d %d", &a, &b, &c); promedio = (a + b + c) / 3; printf("El promedio es: %6.1f", promedio); if (promedio >=8) printf(" APROBADO"); else printf(" REPROBADO"); printf("\nOprime cualquier tecla.."); getch(); }

Las condicionales se pueden escribir de manera anidada, como en el siguiente ejemplo (hay que tener especial cuidado con la anidación):

#include <conio.h> main(void) { int a, b, c; float promedio; printf("Por favor, teclee sus tres calificaciones: "); scanf("%d %d %d", &a, &b, &c); promedio = (a + b + c) / 3; printf("El promedio es: %6.1f", promedio); if (promedio == 10) printf(" EXCELENTE"); else if (promedio >= 8) { printf(" MUY BIEN. "); printf("FELICITACIONES."); } else printf(" REPROBADO"); printf("\nOprime cualquier tecla.."); getch(); }

En estos casos debe tenerse especial cuidado en la alineación del código.

Programación básica en C y Java (elaboró: José Luis López Goytia) 66 / 141

LOS ERRORES MÁS COMUNES EN EL USO DEL IF (Indice) El uso de condicionales es sencillo. Sin embargo, existen errores relativamente comunes que conviene prevenir: Cuidar el alcance de los bloques En todo momento se debe tener presente que los bloques quedan delimitados por las llaves. Si éstas no se colocan se asume el bloque abarca una sola instrucción. Como ejemplo, observe el siguiente código:

#include <conio.h> #include <stdio.h> main () { int x; x = 8; if (x >= 6) printf("Aprobado.\n"); else printf("Reprobado.\n"); printf("A estudiar más.\n"); printf("\nOprime cualquier tecla para continuar..."); getch(); }

La frase A estudiar más se desplegará siempre. El programa asume –a falta de llaves- que el else abarca sólo a una instrucción. La corrección sería como sigue:

else { printf("Reprobado.\n"); printf("A estudiar más.\n"); }

Utilizar el operador de asignación (=) en lugar del de comparación (==) Es muy común que en las condiciones se requiera comparar una variable o una operación con un valor determinado, Por ejemplo: si x es igual a 8. En este caso hay que recordar que el operador de comparación es ==. Observe el siguiente código:

#include <stdio.h> #include <conio.h> main () { int opcion; printf("Bienvenido al cine.\n\n"); printf("1) Amores Perros\n"); printf("2) Babel\n"); printf("\nElija una opción: "); scanf("%d", &opcion);

Programación básica en C y Java (elaboró: José Luis López Goytia) 67 / 141

if (opcion = 1) printf("\nUsted desea ver Amores Perros"); else printf("\nUsted desea ver Babel"); printf("\n\nOprima cualquier tecla para continuar..."); getch(); }

En este programa siempre aparecerá el letrero Usted desea ver Amores Perros. La razón es la siguiente: la instrucción if (opcion = 1) indica que se asigne un 1 a la variable opción, si esto es posible (lo cual es obvio en este caso), se desplegará Usted desea ver Amores Perros. La instrucción en realidad se debió haber manejado como if (opcion == 1). Este error es tan común y tan difícil de rastrear que el lenguaje Java (basado en la sintaxis de C) ya no permite la instrucción if (opcion = 1).

EL USO DE CONDICIONES MÚLTIPLES CON BASE EN UN VALOR (CASE) (Indice)

Es muy común que en diversas ocasiones se tenga que seleccionar alguna opción con base en un valor determinado. Por ejemplo, desplegar el nombre del mes. Esto podría realizarse a través de condicionales anidados, como en el siguiente programa, que despliega el número de días que tiene un mes determinado (recuerde que febrero es bisiesto si el año es divisible entre 4 excepto aquéllos que sean divisibles entre 100; pero si es divisible entre 400 sí se trata de un año bisiesto).

#include <conio.h> main(void) { int ano,mes; printf("Programa que dependiendo del día y mes despliega cuantods días tiene el mes.\n"); printf("Dame el número del año: \n"); scanf("%d",&ano); printf("Dame el número del mes: \n"); scanf("%d", &mes); if ((mes==1)||(mes==3)||(mes==5)||(mes==7)||(mes==8)||(mes==10)||(mes==12)) printf("El mes tiene 31 días."); else if (mes==2) { if ( (ano%4==0) && ( (ano%400==0) || !(ano%100==0) ) ) if ((ano%100==0) && !(ano%400==0)) printf("El mes tiene 28 días."); else printf("El mes tiene 29 días."); else printf("El mes tiene 28 días."); } else if ((mes==4)||(mes==6)||(mes==9)||(mes==11)) printf("\nEl mes tiene 30 días."); printf("\nOprime cualquier tecla..");

Programación básica en C y Java (elaboró: José Luis López Goytia) 68 / 141

getch(); }

Como se puede observar, los días del mes dependen del valor de la variable mes y, en el caso de febrero, del año. Aunque el programa trabaja correctamente resulta confuso de leer. Por ello en este tipo de casos, se prefiere la instrucción switch, que es una forma de if abreviado. Su sintaxis es la siguiente:

switch (variable) case valor: {bloque de instrucciones} break; // el break es opcional /* pueden repetirse tantos case como se deseen */ default: {bloque de instrucciones}

El break indica que ya no siga explorando los siguientes casos. En la mayoría de los casos se desea un break para cada opción, pero en otras situaciones es deseable que –además de lo realizado en el caso anterior- se realicen otras instrucciones, en cuyo caso no se coloca ningún break en la opción que está finalizando. El programa finalmente, quedaría como sigue:

#include <conio.h> main(void) { int ano,mes; printf("Programa que despliega cuantos días tiene un mes.\n"); printf("Dame el año: \n"); scanf("%d",&ano); printf("Dame el mes: \n"); scanf("%d", &mes); switch (mes) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: printf("El mes tiene 31 días"); break; case 4: case 6: case 9: case 11: printf("El mes tiene 30 días"); break; case 2: if (ano%4==0) if ((ano%100==0) && !(ano%400==0)) printf("El mes tiene 28 días"); else printf("El mes tiene 29 días"); else printf("El mes tiene 28 días"); break;

Programación básica en C y Java (elaboró: José Luis López Goytia) 69 / 141

default: printf("Mes no válido.\n"); } printf("\n\nOprime cualquier tecla.."); getch(); }

EJERCICIOS DE CONDICIONALES EN LENGUAJE C (Indice)

• ¿Qué desplegaría el siguiente código tal y como está escrito?

#include <conio.h> #include <stdio.h> main () { int x; x = 8; if (x >= 6) printf("Aprobado.\n"); else printf("Reprobado.\n"); printf("A estudiar más.\n"); printf("\nOprime cualquier tecla para continuar..."); getch(); }

• Pruebe y corrija el siguiente programa:

#include <stdio.h> #include <conio.h> main () { int opcion; printf("Bienvenido al cine.\n\n"); printf("1) Amores Perros\n"); printf("2) Babel\n"); printf("\nElija una opción: "); scanf("%d", &opcion); if (opcion = 1) printf("\nUsted desea ver Amores Perros"); else printf("\nUsted desea ver Babel"); printf("\n\nOprima cualquier tecla para continuar..."); getch(); }

• Realice un programa que obtenga el promedio entero de 3 calificaciones. Se redondea al entero más cercano si el promedio es mínimo de 6. En caso contrario, la calificación bajará al entero inferior.

Programación básica en C y Java (elaboró: José Luis López Goytia) 70 / 141

• Un trabajador gana $30.00 por hora. Las horas extras en un día se pagan dobles hasta la tercera hora. A partir de allí se pagan triples. Realice un programa que lea el número de horas extras y despliegue el pago correspondiente a dichas horas.

• Dado el siguiente código:

1 mayor = b; 2 if ((b > a) && (b > c)) 3 mayor = b; 4 if ((c > a) && (c > b)) 5 mayor = c; 6 printf("El resultado es: %d\n", mayor);

a) Indique el resultado de la tríadas señaladas a continuación, tal y como está escrito (valor=2 puntos):

Datos de prueba Resultado 7 8 9 8 9 8 8 9 9 9 8 7

• Realice un programa que reciba los 3 lados de un triángulo e indique si es equilátero (tres lados iguales), isósceles (dos lados iguales) o escaleno (tres lados diferentes).

• Realice un programa que reciba dos datos enteros: el día y el mes. Con base en ellos despliegue el día y el mes con el formato: 19 de diciembre. Nota: requiere utilizar la sentencia switch.

Programación básica en C y Java (elaboró: José Luis López Goytia) 71 / 141

CICLOS EN LENGUAJE C CONTENIDO (Indice)

Tipos de ciclos El ciclo while El ciclo for El ciclo do-while Cuando usar cada tipo de ciclo Ejercicios de ciclos en lenguaje C TIPOS DE CICLOS (Indice)

En lenguaje C todos los ciclos indican que un determinado bloque de instrucciones se repita mientras se cumpla determinada condición. Existen tres tipos:

• while.- la condición se coloca al principio y se ejecuta el boque de instrucciones mientras se cumpla la condición.

• do-while.- la condición se coloca al final y se ejecuta el boque de instrucciones mientras se

cumpla la condición.

• for.- la condición se coloca al principio y se ejecuta el bloque de instrucciones mientras se cumpla la condición. Su sintaxis es diferente a la del while, pero su funcionalidad es equivalente.

EL CICLO WHILE (Indice) En el while se repite un bloque de instrucciones mientras se cumple una determinada condición. La condición se verifica al inicio. En resumen: mientras (condición) bloque de instrucciones termina mientras

Su diagrama es como sigue: Sí no

instrucciones

Programación básica en C y Java (elaboró: José Luis López Goytia) 72 / 141

Hay que hacer hincapié que la condición significa mientras que. Una condición que siempre se cumpla generaría un ciclo infinito. Por el contrario, una condición que nunca se cumpla implicaría que no se ejecutaran las instrucciones del cuerpo del ciclo ni una sola vez. Un error muy frecuente es no identificar claramente aquello que es repetitivo (va a ir dentro del ciclo) con lo que debe hacerse una sola vez antes o después del ciclo (debe ir fuera del ciclo). El resultado de este error suele dar resultados equivocados o generar ciclos infinitos. A manera de ejemplo, suponga que desea obtener el promedio de varios números proporcionados por el usuario. La pantalla que desea es similar a la siguiente.

Este programa obtiene el promedio de calificaciones. ¿Cuántas calificaciones se van a introducir? 3 Capture las calificaciones, por favor. 8 9 10 El promedio es 9.00 Oprima cualquier tecla para terminar...

¿Qué debe ir dentro del ciclo (color amarillo)? Resulta obvio que la lectura de las calificaciones. Como el valor de una variable se pierde al recibir un segundo valor, entonces se requiere ir sumando las calificaciones en otra variable. Las demás partes del programa irán fuera del ciclo. El código finalmente quedaría como sigue:

#include <conio.h> main() { int i, n; float suma = 0.0, promedio, dato; printf ("Este programa obtiene el promedio de calificaciones.\n"); printf ("¿Cuántas calificaciones se van a introducir?\n"); scanf("%d",&n); if (n > 0) { printf("Capture las calificaciones, por favor.\n"); i = 1; while (i <= n) { scanf("%f", &dato); suma += dato; i++; } promedio = suma / n; printf("El promedio es: %5.2f\n", promedio); } else printf("No puedo sacar el promedio de 0 calificaciones.\n"); printf("\nOprima cualquier tecla para terminar...\n"); getch(); }

Programación básica en C y Java (elaboró: José Luis López Goytia) 73 / 141

EL CICLO FOR (Indice)

En lenguaje C, en realidad el ciclo for es otra forma de expresar la misma funcionalidad que el ciclo while (por lo cual su diagrama es el mismo). Sin embargo, en otros lenguajes su sintaxis les permite únicamente hacer un ciclo cuando ya se conoce exactamente el número de veces que se repetirá algo. Su sintaxis es la siguiente: for (sentencias antes del ciclo; condición; últimas sentencias a repetir) Como ejemplo de for, un programa que despliegue 4 veces hola:

#include <conio.h> main() { int i; printf(“Este programa ejemplifica un for desplegando 4 veces hola”); for (i=0; i<4; i++) printf(“hola”); printf("\nOprima cualquier tecla para terminar...\n"); getch(); }

El ejemplo desarrollado anteriormente quedaría como sigue:

#include <conio.h> main() { int i, n; float suma = 0.0, promedio, dato; printf ("Este programa obtiene el promedio de calificaciones.\n"); printf ("¿Cuántas calificaciones se van a introducir?\n"); scanf("%d",&n); if (n > 0) { printf("Capture las calificaciones, por favor.\n"); for (i=1; i <= n; i++) { scanf("%f", &dato); suma += dato; } promedio = suma / n; printf("El promedio es: %5.2f\n", promedio); } else printf("No puedo sacar el promedio de 0 calificaciones.\n"); printf("\nOprima cualquier tecla para terminar...\n"); getch(); }

El siguiente cuadro resume las diferencias entre ambos programas: Caso while Caso for i = 1; while (i <= n) { scanf("%f", &dato);

for (i=1; i <= n; i++) { scanf("%f", &dato);

Programación básica en C y Java (elaboró: José Luis López Goytia) 74 / 141

suma += dato; i++; }

suma += dato; }

EL CICLO DO-WHILE (Indice) Tanto el while como el for validan la condición antes de ejecutar el bloque de instrucciones la primera vez, con lo cual abren la posibilidad de que dicho bloque de instrucciones no se ejecute ni una sola vez. El do-while valida la condición al final, por lo cual existe la garantía de que al menos se ejecuta una vez dicho bloque de instrucciones. En los tres casos, se seguirá repitiendo “mientras que” la condición se cumpla. La estructura del do-while queda como sigue: realiza bloque de instrucciones mientras (condición)

sí no Usando el ejemplo anterior, tendríamos:

#include <conio.h> main() { int i, n; float suma = 0.0, promedio, dato; printf ("Este programa obtiene el promedio de calificaciones.\n"); printf ("¿Cuántas calificaciones se van a introducir?\n"); scanf("%d",&n); if (n > 0) { printf("Capture las calificaciones, por favor.\n"); i=1; do { scanf("%f", &dato); suma += dato; i++; } while (i<=n); promedio = suma / n; printf("El promedio es: %5.2f\n", promedio); } else

instrucciones

Programación básica en C y Java (elaboró: José Luis López Goytia) 75 / 141

printf("No puedo sacar el promedio de 0 calificaciones.\n"); printf("\nOprima cualquier tecla para terminar...\n"); getch(); }

CUANDO USAR CADA TIPO DE CICLO (Indice) En muchas ocasiones un problema puede resolverse por cualquiera de los tres ciclos existentes y prácticamente es decisión del programador cual utilizar. Sin embargo, conviene recalcar algunos puntos para facilitar su selección:

• En todos los lenguajes, el while puede hacer lo que realice el for y el do-while. • Específicamente en lenguaje C y Java, el for tiene la potencialidad de un while. • Aunque el for es tan potente como el while, se recomienda usarlo solamente cuando se

conoce exactamente el número de veces que se va a repetir un bloque de instrucciones. Aplicarlo a otras situaciones traerá como consecuencia códigos confusos.

• En el do-while, el bloque de instrucciones al menos se ejecuta una vez. El ejemplo anterior se prestaba, de una u otra manera, para todos los tipos de ciclos. Ahora suponga que el requerimiento cambia al siguiente:

Este programa obtiene el promedio de calificaciones. Capture -1 para terminar. as calificaciones, por favor. 8 9 10 -1 El promedio es 9.00 Oprima cualquier tecla para terminar...

El código utilizando un while queda como sigue:

#include <conio.h> main() { int i; float suma = 0.0, promedio, dato; printf ("Este programa obtiene el promedio de calificaciones. Capture -1 para terminar.\n"); i = 0; scanf ("%f", &dato); while (dato >= 0) { suma+=dato; i++; scanf("%f",&dato); } if (i > 0) { promedio = suma / i; printf("El promedio es: %5.2f\n", promedio); } else

Programación básica en C y Java (elaboró: José Luis López Goytia) 76 / 141

printf("No es posible obtener el promedio si no teclea ningún número."); printf("\n\nOprima cualquier tecla para terminar...\n"); getch(); }

Como ya mencionó, se puede realizar ese mismo programa con un for, pero el código pierde claridad, independientemente de cómo quede. A continuación, una de las distintas posibilidades:

#include <conio.h> main() { float suma = 0.0, promedio, dato; int i; printf ("Este programa obtiene el promedio de calificaciones. Capture -1 para terminar.\n"); i = 0; for ( ; dato >= 0 ; ) { scanf("%f", &dato); if (dato >= 0) { suma += dato; i++; } } if (i > 0) { promedio = suma / i; printf("El promedio es: %5.2f\n", promedio); } else printf ("No se proporcionó ninguna calificación.\n"); printf ("\nOprima cualquier tecla para terminar...\n"); getch(); }

EJERCICIOS DE CICLOS EN LENGUAJE C (Indice) • Realice un programa que despliegue 4 veces hola utilizando: a) while; b) for; c) do-while. • ¿Cómo obtendría el siguiente despliegue?

¿Cuántas veces deseas desplegar hola? 3 hola hola hola

• ¿Cómo obtendría el siguiente despliegue? hola hola hola a todos a todos a todos

• ¿Cómo obtendría el siguiente despliegue? hola a todos a todos a todos hola a todos

Programación básica en C y Java (elaboró: José Luis López Goytia) 77 / 141

a todos a todos

• ¿Cómo obtendría el siguiente despliegue? ¿Cuántas veces deseas desplegar hola? 3 ¿Cuántas veces deseas a todos? 2 hola a todos a todos hola a todos a todos hola a todos a todos

• Transforme el siguiente código a un for (1 punto) i = 0; while (i<5) {

printf(“hola”); i++; }

• Corrija el siguiente programa sin tener a la vista el programa correcto. #include <stdio.h> #include <conio.h> main () { float suma, dato, promedio; int numDatos, i; printf("Este programa despliega el promedio de varios números.\n\n"); printf("Indique la cantidad de números: "); scanf("%d", &numDatos); i = 1; suma = 0.0; printf("Teclee los datos:\n "); while (i < numDatos) { scanf("%f", &dato); suma += dato; i++; promedio = suma / numDatos; printf("El promedio es: %6.1f\n", promedio); } printf("\n\nOprima cualquier tecla para continuar..."); getch(); }

• Corrija el siguiente programa sin tener a la vista el programa correcto #include <stdio.h> #include <conio.h> main () { float suma, dato, promedio; int numDatos, i; printf("Este programa despliega el promedio de varios números.\n\n"); printf("Indique la cantidad de números: ");

Programación básica en C y Java (elaboró: José Luis López Goytia) 78 / 141

scanf("%d", &numDatos); printf("Teclee los datos:\n "); while (i < numDatos) { scanf("%f", &dato); suma += dato; i++; } promedio = suma / numDatos; printf("El promedio es: %6.1f\n", promedio); printf("\n\nOprima cualquier tecla para continuar..."); getch(); }

• Corrija el siguiente programa sin tener a la vista el programa correcto #include <stdio.h> #include <conio.h> main () { float suma, dato, promedio; int numDatos, i; printf("Este programa despliega el promedio de varios números.\n\n"); printf("Indique la cantidad de números: "); scanf("%d", &numDatos); printf("Teclee los datos:\n "); for (i=1; i==numDatos; i++) { scanf("%f", &dato); suma += dato; } promedio = suma / numDatos; printf("El promedio es: %6.1f\n", promedio); printf("\n\nOprima cualquier tecla para continuar..."); getch(); }

• El siguiente programa pretende obtener el promedio de 4 números. Analícelo e indique lo que desplegaría en pantalla al ejecutarlo suponiendo que cuando el programa pide “Teclee los datos” el usuario responde 2 5 9 14 (2 puntos)

#include <stdio.h> #include <conio.h> main () { float suma, dato, promedio; int numDatos, i; printf("Este programa despliega el promedio de 4 números.\n\n"); numdatos = 4; i = 1; suma = 0.0; printf("Teclee los datos:\n "); while (i < numDatos) { scanf("%f", & dato); suma += dato; i++; promedio = suma / numDatos; printf("El promedio es: %6.1f\n", promedio); } printf("\n\nOprima cualquier tecla para continuar...");

Programación básica en C y Java (elaboró: José Luis López Goytia) 79 / 141

getch(); }

• ¿Cómo obtendría el siguiente despliegue? Voy a contar las calificaciones aprobadas. Teclea las calificaciones (termina con -1) 7 4 8 10 -1 Obtuviste 3 calificación(es) aprobatoria(s) y 1 calificación(es) reprobatoria(s). Tu promedio fue: 7.25

• Desea obtener la siguiente pantalla: Este programa calcula el promedio de varias calificaciones: ¿Cuántas calificaciones va a capturar? 3 Teclee las calificaciones 6.6 7.2 9.9 El promedio es 7.9 Oprima cualquier tecla para continuar...

Elija las siguientes instrucciones en el orden correcto para llegar al resultado deseado. Las instrucciones pueden utilizarse más de una vez, sobran algunas y usted debe darles la sangría adecuada. Hay más de una solución correcta. i++; while (i < n) { float i, n; i = 0; getch(); printf(“Oprima cualquier tecla para continuar...”); i = 1; } while (i <= n) scanf(“%d”, &n); suma = 0; promedio = suma / n; float suma, promedio; int i, n; float suma = 0, promedio; #include <conio.h> main() #include <stdio.h> printf(“Este programa calcula...”); float dato; printf(“Teclea las calificaciones”); suma = suma + dato; suma += dato;

Programación básica en C y Java (elaboró: José Luis López Goytia) 80 / 141

scanf(“%f%, &dato); printf(“¿Cuántas calificaciones va a capturar”); printf(“El promedio es %5.1f”, promedio);

• El siguiente programa debe obtener la multiplicación de x * n. Codifique la parte que haga falta para obtener el resultado sin emplear la multiplicación, es decir, con base en sumas sucesivas (2 puntos):

main() { float x, resultado; int n, i; scanf(“%f”, x); scanf(“%d”, n); /* poner código */ printf(“Resultado=%f“, resultado);

}

• Realice un programa que calcule el factorial de un número indicado por el usuario. La pantalla será la siguiente:

Bienvenido. Este programa calcula el factorial de un número: Indique el número: El factorial es: 120

Notas: No existen factoriales de números negativos; el factorial de 0 es uno. Para guardar el factorial se requiere de un tipo de dato que guarde rango de valores mayores que el int.

• Realice un programa que calcule el factorial de un número indicado por el usuario. La pantalla

será similar a la siguiente (valor 3 puntos) Bienvenido. Este programa calcula el factorial de un número. ¿Qué número es? 5 Resultado: 1 * 2 * 3 * 4 * 5 = 120

• Realice un programa que calcule la sumatoria de un número indicado por el usuario. La pantalla será similar a la siguiente.

Bienvenido. Este programa calcula la sumatoria de un número. ¿Qué número es? 5 Resultado: 1 + 2 + 3 + 4 + 5 = 15 • Partiendo del siguiente código:

#include <conio.h> #include <math.h> main() { // las iteraciones se declararan flotantes porque pueden exceder el rango de enteros float i, numiteraciones; double sumatoria=0.0, resultado;

Programación básica en C y Java (elaboró: José Luis López Goytia) 81 / 141

printf("Este programa obtendrá un valor muy cercano a PI aplicando "); printf("la fórmula\n PI = 1 / 2 * raíz cuadrada(sumatoria(1..n de 24/(i*i)))."); printf("\n\nTeclee el valor de n, por favor.\n"); scanf("%f", &numiteraciones); for (i = 1.0; i <= numiteraciones; i += 1.0) sumatoria += 24 / (1.0 * i * i); resultado = sqrt(sumatoria) / 2; printf("\nEl valor obtenido es: %8.4f", resultado); printf("\nEl error absoluto es: %8.4f", fabs(resultado-3.1416)); printf("\nEl error relativo es: %8.4f", fabs(resultado-3.1416) / 3.1416 * 100.0); printf ("\nOprima cualquier tecla para terminar...\n"); getch(); }

Programación básica en C y Java (elaboró: José Luis López Goytia) 82 / 141

ARREGLOS EN LENGUAJE C CONTENIDO

Concepto de arreglo Cálculo de la desviación estándar

CONCEPTO DE ARREGLO En el campo de la programación, en muchas ocasiones se van a manejar diversas variables del mismo tipo que recibirán el mismo tratamiento. Por ejemplo: para la reservación y venta de boletos de un autobús, para la frecuencia de calificaciones, para la multiplicación de matrices, etc. Se podrían definir “n” variables del mismo tipo, pero sería un método demasiado lento de programar y de modificar. Para estos casos se tienen los arreglos. Los arreglos son estructuras que contienen datos del mismo tipo. El arreglo recibe un nombre y los elementos se ubican a través de uno o más índices. Cuando el arreglo es de un solo índice se le conoce como arreglo unidimensional o vector; cuando es de dos índices, como arreglo bidimensional o matriz. En el caso de lenguaje Pascal se estipulan los dos límites del arreglo. Por costumbre se comienza del dato 1, pero técnicamente puede principiar en cualquier punto.

{ arreglo de 50 posiciones en Pascal. Cada elemento es de tipo carácter } arreglo : array [1..50] of char;

En Pascal, el índice puede ser también de tipo carácter.

{ arreglo de 26 posiciones en Pascal. Cada elemento es de tipo entero } frecuencia : array ['A'..'Z'] of integer;

En BASIC la dimensión del arreglo se estipula con un único dato. El arreglo comienza en la posición 1.

DIM arreglo(5) ' arreglo de 5 posiciones en BASIC: de la 1 a la 5

En los lenguajes C, C++, JavaScript y Java los arreglos también se indican con un único dato, pero inician en la posición cero.

char arreglo[5]; /* arreglo de 5 posiciones en lenguaje C: de la 0 a la 4 */

Un aspecto importante en los arreglos es si el tamaño de estos se establece en tiempo de compilación (como el caso de lenguaje Pascal y C) o en tiempo de ejecución (como en Java). Lógicamente, el segundo caso ofrece mayor versatilidad. En todos los lenguajes, cuando se quiere acceder a un elemento para modificarlo se escribe el nombre del arreglo y entre corchetes el índice correspondiente (en el caso de BASIC se usan paréntesis en lugar del corchete). Suponiendo las siguientes declaraciones en lenguaje C.

Programación básica en C y Java (elaboró: José Luis López Goytia) 83 / 141

int datos [5], i;

Después de aplicar las siguientes instrucciones: for (i=0; i < 5; i++) datos[i] = 0; datos [1] = 7; datos [4] = 12; datos [0] = datos [1]; datos [2] = datos [4] + 1;

El contenido del arreglo sería: 0 1 2 3 4 7 7 13 0 12 Siguiendo con el mismo ejemplo. La instrucción datos [5] = 0; sería inválida porque no existe la localidad 5. Se debe tener especial cuidado en no intentar acceder fuera de los límites del arreglo. CALCULO DE LA DESVIACION ESTANDAR (índice)

El cálculo de la desviación estándar es un ejemplo en el cual forzosamente se aplican arreglos. El cálculo se realiza de la siguiente forma16:

1) Suponga que se quiere obtener la desviación estándar de los siguientes números: 8, 9, 10, 5 , 7.

2) Se obtiene el promedio. En nuestro caso: (8 + 9 + 10 + 5 + 7) / 5 = 7.8

3) Se obtiene la sumatoria del cuadrado de las diferencias entre cada dato y el promedio

(8 – 7.8) 2 + (9 – 7.8) 2 + (10 – 7.8) 2 + (5 - 7.8) 2 + (7 – 7.8) 2 = 14.8

4) Se divide entre el número de datos y se extrae la raíz cuadrada. ________ √ (14.80 / 5) = 1.72

Como se observará, es necesario leer los números y obtener su promedio (paso 1 y 2). Esos datos volverán a ser requeridos. Como es ilógico pedirlos nuevamente al usuario, deberán ser almacenados bajo algún método. Al ser datos del mismo tipo, la forma más práctica es un arreglo. Ya en el arreglo, se hará un recorrido a través del arreglo para calcular la sumatoria de la diferencia entre cada dato y el promedio (paso 3). Finalmente, se hará la división y la raíz cuadrada (paso 4). El programa queda de la siguiente manera.

/* Programa que calcula la desviación estándar de un grupo de números Probado en Dev-C++ 4.9.8.0 Elaboró: José Luis López Goytia. */

16 La fórmula es distinta para una muestra y para la población total. En nuestro caso, asumiremos que esos valores son toda la

población existente.

Programación básica en C y Java (elaboró: José Luis López Goytia) 84 / 141

#include <conio.h> #include <math.h> main() { float datos[50]; /* arreglo para guardar los datos */ float dato; /* variable auxiliar para leer el dato del usuario */ float promedio, suma=0; /* promedio y suma de los datos del usuario */ float s=0; /* desviación estándar */ int numdatos; /* número de datos que proporcionará el usuario */ int i; /* variable auxiliar para controlar los ciclos */ printf("Programa para calcular la desviacion estándar.\n"); printf("¿Cuántos números va a ingresar (máximo 50)?\n"); scanf("%d", &numdatos); printf("\nIngrese los datos a calcular\n"); for (i=0; i<numdatos; i++) { scanf("%f", &dato); suma += dato; datos[i] = dato; } promedio = suma / numdatos; for (i=0; i<numdatos; i++) { /* suma el cuadrado de las diferencias */ s += (datos[i] - promedio) * (datos[i] - promedio); } s = sqrt(s/numdatos); printf("\n\nResultado = %6.2f \n", s); printf("\n\nOprima cualquier tecla para continuar\n"); getch(); }

El resultado sería como sigue:

Programa para calcular la desviación estándar. ¿Cuántos números va a ingresar (máximo 50)? 5 Ingrese los datos a calcular: 8 9 10 5 7 Resultado = 1.72 Oprima cualquier tecla para continuar...

EJERCICIOS (índice)

• Realice un programa que reciba n números enteros y despliegue cuantos de esos números son mayores al último número proporcionado. La pantalla sería similar a la siguiente (valor 4 puntos):

Programación básica en C y Java (elaboró: José Luis López Goytia) 85 / 141

Bienvenido. Este programa le dirá cuantos números son mayores al último número que capture. ¿Cuántos números va a capturar? 5 Indique los números: 6 7 9 10 8 Hay 2 números mayores al último número capturado.

Sugerencia: cree un arreglo que guarde los números capturados y después recorra ese arreglo con un ciclo contando los números mayores al último dato que se proporcionó.

• Suponga que hay un camión con 10 lugares. Todos están disponibles al principio. Realice un

programa que permita al usuario reservar "n" lugares, indicando cuales. Al final, despliegue los lugares aún disponibles (valor 5 puntos)

Este programa reserva lugares en camión. ¿Cuántos lugares desea reservar? 3 ¿Cuáles 4 7 9 Los lugares aún disponibles son: 1 2 3 5 6 8 10

Notas: si el usuario da un lugar mayor de 10 simplemente se hará caso omiso de este dato.

Variante. Cambie la pantalla por la siguiente:

Este programa reserva lugares en camión. ¿Cuántos lugares desea reservar? 3 ¿Cuáles 4 7 9 Situación al final: 1 2 3 4 5 6 7 8 9 10 D D D - D D - D - D

• Declare, llene y despliegue el arreglo utilizando el menor número de líneas de código posibles. La primera línea es el contenido y la segunda es el índice (2 puntos):

VALOR 0 1 4 9 16 25 36 49 64 59 60 61 62 63 64 65 INDICE 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

• Suponga que existe el siguiente arreglo:

0 1 2 3 4 5 6 7 8 9 10 8 9 1 6 7 12 10 3 4 13 0 Pida un número al usuario. Trate de ubicar ese número en el arreglo. Si existe, despliegue el primer lugar donde lo encontró. En caso contrario, señale que el número no existe. Por ejemplo: si el usuario da 9, su programa debe decir ubicado en el lugar 1.

Programación básica en C y Java (elaboró: José Luis López Goytia) 86 / 141

SUBRUTINAS EN LENGUAJE C

INDICE Concepto de modularidad Estructura básica de una subrutina Un primer ejemplo de subrutina Ocultamiento de la información

CONCEPTO DE MODULARIDAD (índice)

La idea básica de modularidad es la creación de módulos lo más independientes posibles, con entradas y salidas claramente definidas. “Un método de construcción de software es modular, por tanto, si ayuda a los diseñadores a producir sistemas de software a partir de elementos autónomos interconectados mediante una estructura simple y coherente”17. La idea de modularidad se puede encontrar en muy diversas áreas. Por ejemplo: los aparatos electrónicos se basan en componentes, cada uno de ellos con una entrada y una salida claramente definidas (bocinas, audífonos, etc.). Una pieza que cumpliera las especificaciones marcadas podría reemplazar a otra y el sistema en su conjunto seguiría funcionando. La modularidad facilita cubrir los criterios de calidad de software de extensibilidad y reutilización. En términos más prácticos:

• Permite el trabajo en paralelo de varios desarrolladores. • Simplifica el desarrollo de sistemas, pues es más fácil realizar una subrutina que el sistema

completo, tanto en lo referente al volumen como en la complejidad. • Simplifica el mantenimiento de sistemas, al hacer más fácil las modificaciones. • Permite el desarrollo por capas, en el cual solamente unas rutinas son dependientes del

hardware, con lo cual es más fácil caminar hacia la portabilidad. • Evita redundancia, pues evita repetir código que tiene el mismo propósito.

ESTRUCTURA BÁSICA DE UNA SUBRUTINA (índice) Una subrutina recibe uno o más valores (llamados parámetros), realiza una labor específica y devuelve, opcionalmente, un valor de un tipo específico.

17 Meyer, Bertrand; Construcción de software orientado a objetos; Prentice-Hall; 2ª. Edición; España, 1999; página

40.

SUBRUTINA

Programación básica en C y Java (elaboró: José Luis López Goytia) 87 / 141

Cada uno de los parámetros que recibe una rutina debe ser de un tipo específico y su nombre sólo tiene efectos para la propia subrutina. En otras palabras, es independiente de la subrutina que la llama. El orden con que se declaran y envían los parámetros debe ser el mismo, pues la rutina los identificará a través de su posición En forma similar, el valor que devuelve es de un determinado tipo. Si la subrutina no devolviese nada se debe indicar de manera explícita a través de la variable void. La palabra return sirve para retornar el valor desde la rutina hacia el módulo que la llamó. Cada rutina puede tener variables locales, las cuales sólo tiene efecto para la propia rutina. Se crean al comenzar ésta y se destruyen al terminar. Ninguna otra rutina las puede ver aparte de la propia subrutina. En lenguaje C las rutinas se suelen agrupar en librerías. Cada librería cubre cubre un área específica (por ejemplo: manejo de cadenas o funciones matemáticas). UN PRIMER EJEMPLO DE SUBRUTINA (índice) A manera de ejemplo, revise el siguiente programa que contiene dos rutinas: la rutina principal (main) y la subrutina de sumatoria.

#include <conio.h> int sumatoria (int a); main() { int dato, resultado; printf("Este programa obtiene la sumatoria de un número.\n"); printf("Por favor, teclee el número: "); scanf("%d", &dato); resultado = sumatoria(dato); printf("La sumatoria de %d es %d\n\n", dato, resultado); printf("Oprima cualquier tecla para continuar..."); getch(); } int sumatoria (int a) { int i, suma = 0; if (a == 0) return 0; else { for (i = a; i > 0; i--) suma += i; return(suma); } }

Cabe hacer hincapié en que las variables locales sólo pueden accesarse por la propia rutina. En nuestro caso: Rutina Variables locales que usa main dato, resultado sumatoria i, suma

El parámetro se recibe a partir de la variable a. Observe que, en este caso, la rutina principal es quien lee los datos del usuario, mientras que la rutina recibe su información a través de los parámetros y no

Programación básica en C y Java (elaboró: José Luis López Goytia) 88 / 141

realiza ningún proceso de entrada-salida. En términos generales, ésta es la estructura más recomendable para el manejo de rutinas. OCULTAMIENTO DE LA INFORMACIÓN (índice) El diseñador de cada módulo debe seleccionar un subconjunto de propiedades del módulo como información oficial sobre el módulo para ponerla a disposición de los autores de módulos clientes. Para entender los beneficios de la ocultación de la información parta del hecho de que un módulo es conocido a través de una descripción oficial que señala sus propiedades públicas. Todo lo demás se desconoce. Cualquier uso de este módulo y cualquier prueba de su funcionamiento deben basarse únicamente sobre estas propiedades públicas. Normalmente las propiedades se refieren a la función del módulo y los datos de entrada y salida que requiere. El proceso interno de su tarea (el “como” lo hace) debe quedar como parte privada y nadie debe hacer uso de ella directamente. Si se cumplen estas reglas se puede modificar el proceso interno (algoritmos, variables locales, etc.) sin que se afecte en modo alguno al sistema en su conjunto. Ejemplo: la rutina de raíz cuadrada en lenguaje C maneja la siguiente descripción oficial18:

#include “math.h” double sqrt (double num); La función sqrt() devuelve la raíz cuadrada de num. Si se llama a esta función con un argumento negativo, se producirá un error de dominio.

Indica que se encuentra en la librería math.h, que requiere un número de tipo double como entrada y devolverá un número también de tipo double. El parámetro de entrada tiene que ser mayor o igual a cero. Los demás detalles quedan ocultas: si usa variables locales, el algoritmo que emplea, etc. Esta parte privada no se dice ni tiene porque conocerla quien hace uso de este módulo. Observe otra variante de la rutina sumatoria. Como no se modifica ninguna de las partes que ligan con otras rutinas, no se tiene que cambiar ninguna línea del programa principal.

int sumatoria (int a) { return a * (a + 1) / 2; }

EJERCICIOS (índice) • Complete las cinco palabras faltantes. Cada inciso corresponde a una palabra (2 puntos)

_____(a)_____ mayor (float a, float b) { float ____(b)________; if (a > b) aux = ____(c)_______; _____(d) ______ aux = b; ____(e)________ aux; }

18 Schildt, Herbert; C. Manual de Bolsillo; McGraw-Hill; España, 1992; pág. 180.

Programación básica en C y Java (elaboró: José Luis López Goytia) 89 / 141

(a) (b) (c) (d) (e)

• Elabore la rutina sumatoria, que debe devolver la sumatoria de un número (1+2+3+…+n). Si se recibe un número negativo deberá devolver un -1. La rutina debe combinar correctamente con el siguiente programa principal (Valor=3 puntos).

int sumatoria (int a); main() { printf("La sumatoria de 3 es: %d \n", sumatoria(3)); }

• ¿Qué desplegará el siguiente programa? (Valor = 1 punto)

#include <conio.h> void incremento(); main() { int p = 3; incremento(); printf("El valor final de p es: %d \n", p); getch(); } void incremento () { int p = 5; }

• La rutina siguiente intenta intercambiar dos números, pero no funciona bien. Corríjala empleando

apuntadores correctamente:

#include <conio.h> void intercambio (int a, int b); main() { int cal1, cal2, cal3; printf("Teclea 2 números:\n"); scanf("%d %d", &cal1, &cal2); intercambio (cal1, cal2); printf("Los números intercambiados son: %d %d", cal1, cal2); printf("\n\nOprima cualquier tecla para continuar..."); getch(); } void intercambio (int a, int b) { int aux; aux = a; a = b; b = aux; }

• Elabore una subrutina que reciba un número entero y devuelva la sumatoria de ese número.

• Elabore una subrutina que reciba 3 números enteros y devuelva el promedio de esos 3 números.

• Complete el siguiente código:

Programación básica en C y Java (elaboró: José Luis López Goytia) 90 / 141

#include <conio.h> float promedio (int cal1, int cal2, int cal3); main() { int c1, c2, c3; _____indicar la palabra que falta______ x; printf("Introduce los numeros a promediar:\n"); scanf("%d" "%d" "%d", &c1, &c2, &c3); /* completar código, parte 1 */ printf("El promedio es: %6.2f\n", x); } float promedio (int cal1, int cal2, int cal3) { /* completar código, parte 2 */ }

• Realice una subrutina llamada cubo que reciba un dato de tipo entero y devuelva un dato de tipo

flotante. Esta subrutina elevará el número proporcionado al cubo (1 punto)

Programación básica en C y Java (elaboró: José Luis López Goytia) 91 / 141

APUNTADORES

INDICE

Concepto de apuntador Llamadas por valor y por referencia Manejo de cadenas Ejercicios

CONCEPTO DE APUNTADOR Indice

Los apuntadores son variables que guardan direcciones de memoria del tipo de dato que se le indique. Existen 2 operadores para el manejo de apuntadores: & indica la dirección de la variable; mientras * significa el lugar al cual señala el apuntador. Se utiliza NULL para indicar que el apuntador todavía no tiene asignada una dirección. Para ejemplificar el uso de apuntadores suponga la siguiente definición: int x; /* definir la variable x */ x = 5; /* asignar el valor 5 a la variable x */ int *apuntadorx; /* definir un apuntador con el nombre apuntadorx */ apuntadorx = &x; /* asignar a apuntadorx la dirección de memoria de la variable x */ después de las instrucciones siguientes, apuntadorx tendrá un valor similar al siguiente: 0012FF7C. se puede afectar a la variable a la cual señala el apuntador con la instrucción *apuntador. De esta forma, *apuntador = 8 es equivalente a decir x = 8. El siguiente esquema representa los conceptos manejados.

Los apuntadores tienen tres usos principales:

a) Permiten enviar direcciones de memoria para que una subrutina altere el valor de la variable original. A estos parámetros se les conoce como parámetros por referencia. Entre otros casos, se utilizan para la lectura de datos.

b) permiten alterar directamente algunas zonas de memoria, lo cual se aprovecha en

aplicaciones de software de bajo nivel, y c) permiten manejar estructuras de datos que basan su funcionamiento en una dirección inicial,

como es el caso de arreglos.

0012FF7C 8

Programación básica en C y Java (elaboró: José Luis López Goytia) 92 / 141

LLAMADAS POR VALOR Y POR REFERENCIA Indice Existen dos formas de enviar parámetros a una subrutina: por valor y por referencia. En el primer caso, se realiza en forma automática una copia de los parámetros; el segundo, se trabaja directamente sobre las direcciones, con lo cual se altera el valor de la variable original. El siguiente programa ilustra un caso que maneja parámetros por valor: /* Tomado de: Deitel; C/C++ Cómo programar y Java; Pearson; México, 2004; 1113 págs. Figura 7.6: fig07_06.c Eleva al cubo una variable mediante una llamada por valor */ #include <stdio.h> int cuboPorValor( int n ); /* prototipo */ int main() { int numero = 5; /* inicializa número */ printf( "El valor original de número es %d", numero ); /* pasa número por valor a cuboPorValor */ numero = cuboPorValor( numero ); printf( "\nEl nuevo valor de número es %d\n", numero ); printf("\n\nOprima cualquier tecla para continuar..."); getch(); } /* fin de main */ /* calcula y devuelve el cubo de un argumento entero */ int cuboPorValor( int n ) { return n * n * n; /* eleva al cubo la variable local n y devuelve el resultado */ } /* fin de la función cuboPorValor */

La salida del programa es la siguiente:

El valor original de número es 5 El nuevo valor de número es 125 Oprima cualquier tecla para continuar...

Este programa ilustra el caso de parámetros por valor: /* Tomado de: Deitel; C/C++ Cómo programar y Java; Pearson; México, 2004; 1113 págs. Figura 7.7: fig07_07.c Eleva al cubo una variable mediante el uso de una llamada por referencia con un apuntador como argumento */ #include <stdio.h> void cuboPorReferencia( int *ptrN ); /* prototipo */ int main() { int numero = 5; /* inicializa número */ printf( "El valor original de número es %d", numero ); /* pasa la dirección de número a cuboPorReferencia */ cuboPorReferencia( &numero ); printf( "\nEl nuevo valor de número es %d\n", numero ); printf("\n\nOprima cualquier tecla para continuar..."); getch(); } /* fin de main */

Programación básica en C y Java (elaboró: José Luis López Goytia) 93 / 141

/* calcula el cubo de *ptrN; modifica la variable número en main */ void cuboPorReferencia( int *ptrN ) { *ptrN = *ptrN * *ptrN * *ptrN; /* cubo de *ptrN */ } /* fin de la función cuboPorReferencia */

La salida del programa es la siguiente: El valor original de número es 5 El nuevo valor de número es 125 Oprima cualquier tecla para continuar...

MANEJO DE CADENAS Indice En lenguaje C prácticamente no existen operadores relativos al manejo de cadenas. Estas labores se realizan mediante subrutinas basadas en apuntadores que se encuentran en la biblioteca string.h. Recuerde que en lenguaje C una cadena es un arreglo de caracteres que termina con el carácter \0, también llamado nulo. Ejemplificaremos su modo de empleo con strlen y strcat. Su sintaxis es la siguiente: size_t strlen (char *cad) devuelve la longitud de la cadena finalizada con carácter nulo apuntado por cad. El carácter nulo no se cuenta

char *strcat(char *cad1, const char *cad2) concatena una copia de cad2 en cad1 y hace que cad1 finalice con un carácter nulo. El carácter nulo que tenía originalmente cad1 se sobrescribe con el primer carácter de cad2. La cadena cad2 no se toca en esta operación.

Para utilizar strcat es necesario que la primer cadena tenga espacio suficiente para recibir la concatenación. Esto se logra definiendo un arreglo de caracteres. A continuación un programa que ejemplifica su uso:

#include <conio.h> #include <string.h> main() { char cadena1[50] = "cadena", *cadena2 = "de ejemplo"; int longitud; strcat(cadena1, cadena2) ; longitud = strlen(cadena1); printf("La longitud de <cadena> y <de ejemplo> es: %6d", longitud); printf("\n\nOprima cualquier tecla para continuar..."); getch(); }

Programación básica en C y Java (elaboró: José Luis López Goytia) 94 / 141

EJERCICIOS Indice • ¿Qué arrojaría el siguiente programa?

#include <conio.h> main() { int a, b, c; // variables int *apuntador1, *apuntador2, *apuntador3; a = 5; b = 8; c = 10; printf("La dirección de la variable a es: %p\n", &a); printf("La dirección de la variable b es: %p\n", &b); printf("La dirección de la variable c es: %p\n", &c); printf("\n"); apuntador1 = &a; apuntador2 = &b; apuntador3 = &c; printf("El valor de apuntador 1 es: %p\n", apuntador1); printf("El valor de apuntador 2 es: %p\n", apuntador2); printf("El valor de apuntador 3 es: %p\n", apuntador3); printf("\n"); printf("El valor contenido en %p es: %d\n", apuntador1, *apuntador1); printf("El valor contenido en %p es: %d\n", apuntador2, *apuntador2); printf("El valor contenido en %p es: %d\n", apuntador3, *apuntador3); printf("\n"); // haciendo que apuntador 3 tome la dirección de apuntador1 apuntador3 = apuntador2; *apuntador3 = 4; printf("El valor contenido en %p es: %d\n", apuntador1, *apuntador1); printf("El valor contenido en %p es: %d\n", apuntador2, *apuntador2); printf("El valor contenido en %p es: %d\n", apuntador3, *apuntador3); printf("\n"); printf("\nOprima cualquier tecla para terminar...\n"); getch(); }

Respuesta:

La dirección de la variable a es: 0022FF6C La dirección de la variable a es: 0022FF68 La dirección de la variable a es: 0022FF64 El valor del apuntador 1 es: 0022FF6C El valor del apuntador 1 es: 0022FF68 El valor del apuntador 1 es: 0022FF64 El valor contenido en 0022FF6C es: 5 El valor contenido en 0022FF68 es: 8 El valor contenido en 0022FF64 es: 10 El valor contenido en 0022FF6C es: 5 El valor contenido en 0022FF68 es: 4 El valor contenido en 0022FF64 es: 4 Oprima cualquier tecla para terminar...

Programación básica en C y Java (elaboró: José Luis López Goytia) 95 / 141

• Realice la prueba de escritorio al siguiente código:

#include <conio.h> void menorMayor (float cal1, float cal2, float cal3, float *minimo, float *maximo); main() { float c1, c2, c3, menor, mayor; printf("Este programa indicará el número menor y mayor de 3 cantidades que proporciones:\n"); scanf("%f %f %f", &c1, &c2, &c3); menorMayor(c1, c2, c3, &menor, &mayor); printf("El menor es: %6.1f\n", menor); printf("El mayor es: %6.1f\n", mayor); printf("Oprime cualquier tecla para continuar..."); getch(); } void menorMayor (float cal1, float cal2, float cal3, float *minimo, float *maximo) { float men = cal1, max = cal1; if (cal2 < men) men = cal2; if (cal2 > max) max = cal2; if (cal3 < men) men = cal3; if (cal2 > max) max = cal3; *minimo = men; *maximo = max; }

• ¿Qué desplegará el siguiente programa? (Valor = 2 puntos) #include <conio.h> void cuadrado (int p); void decremento (int *w); main() { int p = 3; cuadrado(p); decremento(&p); printf("El valor final de p es: %d \n", p); getch(); } void cuadrado (int p) { p = p * p; } void decremento (int *w) { *w = *w - 1; }

Programación básica en C y Java (elaboró: José Luis López Goytia) 96 / 141

ENFOQUE DE LA PROGRAMACION ORIENTADA A OBJETOS (POO)

CONTENIDO Conocimientos previos Enfoque de la POO Diagramas de clase Ejercicios sugeridos Bibliografía Con que proseguir

CONOCIMIENTOS PREVIOS (Indice)

Conocimientos básicos de algún (tipos de datos y subrutinas) de algún lenguaje de programación, preferentemente de lenguaje C.

ENFOQUE DE LA PROGRAMACIÓN ORIENTADA A OBJETOS (Indice)

Bruce Eckel19 define el enfoque orientado a objetos bajo las siguientes bases:

• “Todo es un objeto.” La realidad (perros, edificios, servicios, etc.) será representada a través de objetos dentro de un programa.

Las posibles características (atributos) de un objeto y su comportamiento (definido por los métodos) quedan definidos por la clase a la cual pertenece. Suponga que existen dos objetos de la clase Foco, llamados foco1 y foco2. Ambos tendrán los mismos atributos y métodos, aunque cada uno tendrá sus propios valores para los distintos atributos.

Figura 1. Una clase Foco a partir de la cual se definieron 2 objetos. La clase define los atributos que pueden tener los objetos y su comportamiento (métodos que se le pueden aplicar).

• “Un programa es un cúmulo de objetos que se dicen entre sí lo que tienen que hacer

mediante el envío de mensajes”. Cada objeto puede recibir peticiones y, en razón de ellas, realizar una operación determinada. Esas peticiones sólo pueden hacerse por la interfase que el mismo objeto ha diseñado.

19 Tomado de: Eckel, Bruce; Piensa en Java; Pearson – Prentice Hall; segunda edición; España, 2002; pág. 3.

Foco estado: String cambiarEstado()

foco1: Foco estado=”encendido”

foco2: Foco estado=”apagado”

Programación básica en C y Java (elaboró: José Luis López Goytia) 97 / 141

En las clases existen partes públicas y privadas (y algunas variaciones). Normalmente los datos son de naturaleza privada y los métodos son públicos. Las partes privadas sólo pueden ser accesadas a través de los propios métodos de las clases. Con ello se impide que se modifique esa información desde fuera del objeto.

Encapsulamiento es la capacidad de ocultar algunos miembros de la clase, pero proporcionando una interfase pública para acceder a dichos miembros de la clase. Esa interfaz fija una serie de reglas que no se pueden brincar.

Figura 2. Un objeto elevador y su interfase externa para el usuario. A través de esta interfase sólo se puede indicar: a) que se desea subir o b) que se desea bajar.

• “Cada objeto tiene su propia memoria, constituida por otros objetos.” Los objetos pueden

contener atributos (datos), métodos (rutinas) o bien otros objetos.

Se pueden crear objetos a partir de otros objetos. El nuevo objeto tendrá los datos y mensajes de la clase padre, más los datos y mensajes que desee agregar. También existe la posibilidad de redefinir un mensaje. Este mecanismo se conoce como herencia.

Profesor nivel superior

Profesor

Figura 3. Una clase puede heredar atributos y métodos de otra clase. Sobre esa base puede añadir sus propios atributos y métodos. También puede sobreescribir los métodos recibidos.

• “Todo objeto es de algún tipo. Cada objeto es un elemento de una clase, entendiendo por

clase un sinónimo de tipo. La característica más relevante de una clase la constituyen “el conjunto de mensajes que se le pueden enviar”.”

• “Todos los objetos de determinado tipo pueden recibir los mismos mensajes. Esta es una

afirmación de enorme trascendencia como se verá más tarde. Dado que un objeto de tipo triángulo es también un objeto de tipo polígono, se garantiza que todos los objetos triángulo acepten mensajes propios de polígono. Esto permite la escritura de código que haga referencia

Elevador +subir() +bajar()

Profesor

ProfesorNivelSuperior

atributos

métodos

Programación básica en C y Java (elaboró: José Luis López Goytia) 98 / 141

a polígonos, y que de manera automática puede manejar cualquier elemento que encaje con la descripción de triángulo. Esta capacidad de suplantación es uno de los conceptos más potentes de la POO “. Se conoce como polimorfismo.

Polimorfismo es la capacidad de que una referencia pueda apuntar a objetos de diferente tipo.

Debe recordarse que una clase tiene los datos y mensajes que heredó de la clase padre, más los datos y métodos que desee agregar. Si hay dos clases que heredaron de la misma clase padre y no se hizo ninguna redefinición, al menos tendrán en común los datos que heredaron.

• Existe un método especial en las clases que permite crear al objeto y asignar valores iniciales a

sus datos. A este método se le conoce como constructor. El constructor tiene el mismo nombre que la propia clase.

• Puede haber varios métodos con el mismo nombre en la misma clase. Se distinguirá entre ellas

porque reciben diferentes parámetros, ya sea en número o tipo. A esto se le conoce como sobrecarga.

• Al método contrario, que realiza algunas tareas a la hora de eliminar ese objeto de memoria, se le

conoce como destructor. El destructor no existe como tal en todos los lenguajes orientados a objetos.

Tip de portabilidad: en Java no existe concepto de destructor. El recolector de basura (Garbage Collection) se encarga de liberar la memoria de los objetos que ya no se usan.

DIAGRAMAS DE CLASE (Indice) Como se puede notar, todo se basa en objetos y clases. La forma de representar las clases empleando la notación de UML (Lenguaje Unificado de Modelado – Unified Modeling Language) es mediante un rectángulo con secciones. La primera sección (el nombre de clase) es forzosa. Los demás son opcionales, pero debe respetarse el orden indicado. La segunda parte indica los atributos; la tercera, los métodos; en la cuarta se colocan comentarios. En este tipo de diagramas la parte privada se maneja como – y la parte pública con +. El diagrama será similar al siguiente20:

Nombre de la clase atributo:Tipo = ValorInicial

operación (lista argumentos): tipo de devolución comentarios

El mecanismo de herencia se señala mediante una flecha que va de la clase hija a la clase padre.

Clase padre

Clase hija

20 Fowler, Martin; UML Gota a gota; Pearson; México, 1999.

Programación básica en C y Java (elaboró: José Luis López Goytia) 99 / 141

A manera de ejemplo, suponga que se requiere una clase que simule una tarjeta de débito. Esta tarjeta tendrá un saldo. Las operaciones que se pueden hacer con ella son: meter dinero, sacar dinero y consultar saldo. El saldo nunca puede ser negativo. Adicionalmente suponga que habrá una tarjeta de crédito, con una línea de crédito. La opción de sacar dinero variará porque, además de sacar su propio dinero, puede sacar dinero hasta su línea de crédito disponible. El diagrama de clases quedaría como sigue:

+ TarjetaDebito - saldo : double +TarjetaDebito(saldoInicial : double) + getSaldo(): double + meterDinero (cantidad : double) : void + sacarDinero (cantidad : double) : boolean

TarjetaCredito

- lineaDeCredito : double + TarjetaCredito (saldo : double) + TarjetaCredito (saldo : double, lineaCredito : double) + getLineaDeCredito() : double + setLineaDeCredito(cantidad: double) + sacarDinero (cantidad : double) : boolean

EJERCICIOS SUGERIDOS (Indice) GRUPO 1:

• ¿Qué diferencia hay entre partes privadas, públicas y protegidas? • ¿Por qué no existe un método setSaldo? • ¿En dónde existe una situación de sobrecarga? • ¿Cuántos atributos tiene la clase TarjetaDebito? • ¿Cuántos métodos tiene la clase TarjetaDebito? • ¿Cuántos atributos tiene la clase TarjetaCredito? • ¿Cuántos métodos tiene la clase TarjetaCredito?

GRUPO 2:

• Realice un diagrama de clase para una clase Cuadrado, con dos métodos: área y perímetro.

GRUPO 3: • ¿Qué desplegaría el siguiente pseudocódigo?

clase Ejemplo método bienvenida despliega “hola”

Programación básica en C y Java (elaboró: José Luis López Goytia) 100 / 141

clase Ejemplo2 hereda Ejemplo método bienvenida despliega “buenos días” Ejemplo2 objeto; objeto.bienvenida();

Respuesta: __________________________

• Elija, de entre los enunciados siguientes, el que corresponde más al término de encapsulamiento.

a) Que una clase tenga atributos y métodos. b) Que no tengamos acceso al código en un archivo .class c) Que un atributo privado no pueda ser accesado desde fuera de la clase. Respuesta: __________________________

• ¿Son ventajas de la POO frente a la programación estructurada?

a) La POO siempre es de tipo gráfico. b) La POO corre en cualquier plataforma. c) Las clases tienen atributos y métodos. d) Hay herencia. e) Un método puede llamar a otro método. f) Pueden repetirse nombres de métodos en un sistema. g) Es posible la sobrecarga de métodos. Respuesta: __________________________

BIBLIOGRAFIA (Indice) • Eckel, Bruce; Piensa en Java; Pearson – Prentice Hall; segunda edición; España, 2002; 906 págs. • Fowler, Martin; UML Gota a gota; Pearson; México, 1999; 203 págs.

CON QUE PROSEGUIR (Indice)

• Algunas otras bases conceptuales antes de entrar al código, por ejemplo: la forma de almacenamiento de objetos en Java.

• Ejercicios didácticos que refuercen los conceptos utilizando únicamente diagramas UML. Este enfoque es recomendado para alumnos que se acercan por vez primera a programación orientada a objetos.

• Ejercicios de código que muestren clases en código, comenzado con una clases sencilla (sin herencia ni sobrecarga) e incorporando poco a poco un mayor grado de dificultad.

Programación básica en C y Java (elaboró: José Luis López Goytia) 101 / 141

¿CÓMO FUNCIONA JAVA? CONTENIDO Conocimientos previos La máquina virtual de Java El manejo de memoria en Java El recolector de basura de Java (Garbage Collection) Las características de Java Las versiones de Java Los productos de Java Los entornos de desarrollo de Java Ejercicios sugeridos Bibliografía Con que proseguir CONOCIMIENTOS PREVIOS (Indice)

Conocimientos básicos (tipos de datos y subrutinas) de algún lenguaje de programación, preferentemente de lenguaje C o Java. LA MÁQUINA VIRTUAL DE JAVA (Indice) Java se basa en librerías al igual que el lenguaje C. Sin embargo, incorpora un concepto nuevo: la máquina virtual. El compilador no produce directamente el código ejecutable. En su lugar deja un código de bytes que –en un segundo paso- un intérprete transformará al código máquina de la computadora. Por eso se dice que la compilación es hacia una “máquina virtual”. En otras palabras, compilamos para un intérprete que aún no se conoce. La idea no era nueva y había fracasado en intentos anteriores. Sin embargo, la situación técnica de la computación hacia finales de los 90’s y la aplicación masiva de INTERNET hicieron que Java tuviera una difusión que ningún otro lenguaje había logrado.

Figura 1. La máquina Virtual de Java Esta forma de trabajo tiene grandes ventajas. Por un lado, ni el programa fuente ni el código compilado dependen de la computadora en específico. Por otro, es mucho más difícil vulnerar la seguridad en Java. Pero tiene costos: se requiere un intérprete que realice el paso final y hace que los programas sean menos eficiente por ese último paso de traducción. Sin embargo, con la tecnología actual de Java, ese costo se ha reducido cada vez más.

código fuente (.java)

código de bytes (.class)

librerías (import)

ejecución

Programación básica en C y Java (elaboró: José Luis López Goytia) 102 / 141

EL MANEJO DE MEMORIA EN JAVA (Indice) En Java, todo se maneja a través de referencias (apuntadores). Cuando se crea un objeto, el nombre de éste queda en un espacio de memoria llamado stack. Esta variable, a su vez, señala al objeto, el cual queda alojado en otro espacio de memoria llamado heap.

Stack Memory Heap Memory

Clase objeto; objeto = new Clase(); Figura 2. El manejo de memoria en Java. Cuando se declara la variable objeto, éste se da de alta en el stack. Esta variable almacena la dirección de memoria del objeto. El objeto se crea en el heap cuando se da de alta explícitamente mediante la palabra new. EL RECOLECTOR DE BASURA DE JAVA (GARBAGE COLLECTION)) (Indice) Suponga que se define y crea un objeto. ¿Qué sucedería si el objeto se crea nuevamente sin ser eliminado el primero? Se pierde la primera referencia del primer objeto, el cual ya no es accesible por ninguna vía. En otros lenguajes (como lenguaje C) este objeto seguiría consumiendo memoria hasta que se apague la máquina. En el caso de Java, la memoria se liberará posteriormente a través del recolector de basura (Garbage Collection). El objetivo del recolector de basura es eliminar de la memoria las referencias y objetos que ya no se usan.

Stack Memory Heap Memory objeto del cual ya no se tiene referencia

Clase objeto; objeto = new Clase(); objeto = new Clase(); Figura 3. El objeto que ya no tiene referencia es eliminado en forma automática por el recolector de basura (Garbage Collection).

Programación básica en C y Java (elaboró: José Luis López Goytia) 103 / 141

LAS CARACTERÍSTICAS DE JAVA21 (Indice) “Los autores de Java han escrito un influyente Libro Blanco que explica sus metas de diseño y conclusiones. El libro está organizado en los siguientes once clichés:

• Simple • Orientado a objetos • Distribuido • Robusto • Seguro • Arquitectura Neutral • Portable • Interpretado • Alto rendimiento • Multithreaded

• Dinámico

“En esta sección vamos a… resumir algunos extractos del Libro Blanco con lo que los diseñadores de Java dicen de cada cliché, … “

Simple

“Quisimos hacer un sistema que pudiera ser programado fácilmente sin mucho aprendizaje esotérico y que mejorara los estándares actuales. Aunque vimos que C++ no era apropiado, diseñamos Java lo más parecido a C++ para hacerlo más entendible. Java omite las características de C++ que rara vez se utilizan, que no se entienden y que causan confusión que, por nuestra experiencia, dan más quebradero de cabeza que beneficios.

Orientado a objetos

“Podemos afirmar que el diseño orientado a objetos es una técnica de programación que hace énfasis en los datos (=objetos) y en las relaciones con esos objetos. Haciendo una analogía con una carpintería, un carpintero “orientado a objetos” estaría más preocupado por la silla que está haciendo y, en segundo lugar por las herramientas utilizadas para hacerla; un carpintero “no orientado a objetos” daría más prioridad a sus herramientas. Las utilidades de Java orientadas a objetos son básicamente las mismas que las de C++.

Distribuido “Java tiene una extensa biblioteca de rutinas para realizar copias con los protocolos de TCP/IP como HTTP y FTP. Las aplicaciones de Java pueden abrir y acceder a objetos a través de la Red vía URL con la misma facilidad con la que se accede al sistema local de ficheros.

Robusto

“Java está hecho para escribir programas que deben ser fiables en varios aspectos. Java pone énfasis en la pronta comprobación de posibles problemas, la comprobación dinámica (en tiempo de ejecución) posterior, eliminando situaciones propensas a errores… La diferencia más significativa entre Java y C/C++ es que Java tiene un modelo de punteros que elimina la posibilidad de sobrescribir la memoria y corromper los datos.

Seguro “Java está pensado para ser usado en entornos distribuidos o en red. Con ese fin, se ha hecho mucho énfasis en la seguridad. Java permite crear sistemas libres de virus y falsificaciones.

21 Tomado de: Horstmannn, Cay S.; Cornell, Gary; Java 2 Fundamentos; Prentice Hall; España, 2003; págs. 6-13. Los autores lo sintetizaron a su vez del “Libro Blanco” en http://java.sun.com/doc/language_environment.

Programación básica en C y Java (elaboró: José Luis López Goytia) 104 / 141

Arquitectura neutral “El compilador genera un fichero objeto cuyo formato es independiente de la arquitectura (el código compilado se ejecuta en muchos procesadores, en los que haya un sistema de ejecución Java). El compilador Java hace esto al generar instrucciones bytecode que no están relacionadas con una arquitectura de computadora en particular. Más bien, las instrucciones se hacen para que sean fáciles de interpretar en cualquier máquina y fácilmente traducibles al código máquina nativo en tiempo de ejecución.

Portable “A diferencia de C y C++ no hay aspectos de la especificación “dependientes de la implementación”. Están especificados los tamaños de los datos básicos, así como su comportamiento aritmético.

Interpretado

“El intérprete Java puede ejecutar bytecodes de Java directamente en cualquier máquina a la que se haya trasladado el intérprete. Puesto que el enlace (linking) es un proceso más incremental y ligero, el proceso de desarrollo es mucho más rápido.

Alto rendimiento “Mientras que el rendimiento de los bytecodes interpretados normalmente es más que adecuado, hay situaciones en las que se requiere un mejor rendimiento. Los bytecodes se pueden traducir en tiempo de ejecución a código máquina para la CPU de la máquina en la que se están ejecutando.

Multithreaded “Las ventajas del multithreaded son una mayor sensación de interactividad y un mejor comportamiento en tiempo real.

Dinámico “En varios aspectos Java es un lenguaje más dinámico que C o C++. Se diseñó para adaptarse a un entorno en evaluación. Las bibliotecas pueden añadir métodos nuevos e instanciar variables sin que afecte a los clientes. En Java, descubrir información en tiempo de ejecución es sencillo.

Java e Internet “La idea en este punto es sencilla: los usuarios descargan los bytecodes de Java desde Internet y los ejecutan en sus propias máquinas. Los programas Java que se ejecutan en paginas web se llaman applets. Para utilizar un applet, necesita un navegador que tenga la capacidad de ejecutar Java, el cual interpretará los bytecodes.

LAS VERSIONES DE JAVA (Indice) Se suele hablar de Java I, Java 2 y Java 3D. En realidad, la numeración tiene que ver más con una cuestión comercial que técnica. El nombre de Java 2 se emplea para hacer hincapié en el crecimiento de Java como una plataforma amplia y probada a partir de la versión 1.2 del compilador. Java 3D, por su parte, contiene una serie de clases para creación de imágenes gráficas. Se puede decir que es totalmente independiente de Java 2. La tabla 1 indica el crecimiento de Java a lo largo del tiempo. A continuación se muestra una tabla con la versión del compilador de Java y su crecimiento22.

Versión Número de clases e interfaces

Número de métodos y campos

22 Ibid; pág. 17.

Programación básica en C y Java (elaboró: José Luis López Goytia) 105 / 141

1.0 212 2125 1.1 504 5478 1.2 (Java 2) 1781 20935 1.3 2130 23901 1.4 3020 32138

Tabla 1. El crecimiento de Java a lo largo del tiempo.

“Sun desarrolló la primera versión de Java a principios de 1996. La gente se dio cuenta rápidamente de que Java 1.0 no iba a servir para desarrollar aplicaciones serias. Es verdad que se podía utilizar Java 1.0 para hacer un applet en el que apareciese el texto moviéndose de forma temblorosa de acá para allá en un lienzo. Pero ni siquiera se podía imprimir en Java 1.0. Para ser francos, Java 1.0 no estaba listo para distribuirse masivamente. Su sucesor, la versión 1.1, arregló la mayor parte de los defectos obvios, mejoró de manera notable la capacidad de reflexión, y añadió un modelo nuevo de eventos para la programación de la GUI (Interfaz gráfica de usuario). Aún así, todavía tenía muchas limitaciones.” “La gran noticia de la conferencia JavaOne de 1998 fue la inminente versión 1.2 de Java, que reemplazaba esa especie de juguete que era la GUI y las herramientas gráficas con versiones sofisticadas y escalables que se acercaban más a la promesa de “Escribir el código una sola vez, ejecutarlo en cualquier sitio” (Write Once, Run Anywhere) que lo logrado por sus predecesores. Tres días más tarde (!), esto ocurría en diciembre de 1998, el departamento de marketing de Sun cambió el nombre al término pegadizo Java 2 Standard Edition Software Development Kit Versión 1.2” 23 LOS PRODUCTOS DE JAVA (Indice) La tecnología de Java vigente a mediados de 2006 –incluida la Máquina Virtual de Java (Java Virtual Machine)- está incluida en tres grupos diferentes de productos, cada uno diseñado para las necesidades de un sector de mercado distinto: JavaTM 2 Plataform, Standard Edition (J2SE TM).- desarrollo de applets y aplicaciones que corren dentro de navegadores de WEB y computadoras personales, respectivamente. JavaTM 2 Plataform, Enterprise Edition (J2EE TM).- aplicaciones empresariales, aplicaciones distribuidas cliente-servidor. JavaTM 2 Plataform, Micro Edition (J2EE TM).- aplicaciones para dispositivos del consumidor, como teléfonos celulares. LOS ENTORNOS DE DESARROLLO PARA JAVA (Indice) Los programas de Java quedan grabados en archivos tipo ASCII (TXT). Este archivo puede crearse desde cualquier editor (como el bloc de notas de Windows). Sin embargo, el uso de un entorno integrado de desarrollo facilita en gran medida la escritura de código. Java puede combinarse con diferentes entornos de desarrollo, pues desde un inicio separó el ambiente de desarrollo del compilador. Entre los más comunes se encuentran: IDE Requerimientos en

RAM Productos de Java

Costo

JCreator, BlueJ, JGrasp, freeJ 64 MB JSE libre Netbeans IDE (SUN free) 256 MB JSE, JEE, JME libre

23 Idem.

Programación básica en C y Java (elaboró: José Luis López Goytia) 106 / 141

JDeveloper (Oracle) 256 MB JSE, JEE, JME pagado JBuilder (Borland) 256 MB JSE, JEE, JME pagado Bea – weblogic (Java Workshop)

256 MB JSE, JEE, JME pagado

WebSphere Studio (IBM) 256 MB JSE, JEE, JME pagado Eclipse (IBM free) 256 MB JSE, JEE, JME Libre Java Studio Enterprise / Java Studio Creador (SUN)

256 MB JSE, JEE, JME Pagado (tiende a ser libre)

EJERCICIOS SUGERIDOS (Indice) • Instalar el compilador de Java ubicando la versión del compilador, el producto del cual se trata y si

viene acompañado por algún entorno de desarrollo.

• De las siguientes características de software, ¿en cuál contribuye más Java? a) Eficiencia b) Portabilidad c) Facilidad de uso d) Funcionalidad Respuesta: _____ Fundamente su respuesta: _________________________________________________________________________ _________________________________________________________________________

• ¿Qué pasa en el siguiente código?

Cuadrado ejemplo1; ejemplo1 = new Cuadrado(6.5); ejemplo1 = new Cuadrado(8.1); a) Marca error de sintaxis. b) Se crea un solo objeto en memoria con el último dato. c) El compilador detecta redundancia y hace caso omiso de la segunda instrucción. d) Se crean dos objetos en memoria pero sólo mantiene el direccionamiento del último; Respuesta: __________________________

BIBLIOGRAFIA (Indice) • Eckel, Bruce; Piensa en Java; Pearson – Prentice Hall; segunda edición; España, 2002; 906 págs. • Horstmannn, Cay S.; Cornell, Gary; Java 2 Fundamentos; Prentice Hall; España, 2003. CON QUE PROSEGUIR (Indice)

• Ejercicios de código que muestren clases en código, comenzado con una clases sencilla (sin herencia ni sobrecarga) e incorporando poco a poco un mayor grado de dificultad.

• Un panorama general de los tipos de datos y las estructuras de control de Java.

Programación básica en C y Java (elaboró: José Luis López Goytia) 107 / 141

CREACIÓN DE UNA CLASE SENCILLA EN JAVA

CONTENIDO Conocimientos previos Creación de una clase sencilla en Java Compilando un programa en Java desde comandos Reglas para el nombre de identificadores en Java Ejercicios sugeridos Bibliografía

CONOCIMIENTOS PREVIOS (Indice)

Conocimientos de algún lenguaje de programación –de preferencia lenguaje C- y de conceptos básicos de programación orientada a objetos. Se supone que ya se tiene un compilador de Java instalado.

CREACIÓN DE UNA CLASE SENCILLA EN JAVA (Indice) La programación de una clase parte del diagrama de clases, muy posiblemente complementada con otro tipo de información. Para este momento, ya se realizó el requerimiento, análisis y diseño24. Ahora lo que debe hacerse es transferir a código los diagramas entregados. La primera clase a crear será la de un cuadrado. El diagrama de clases es el siguiente:

+ Cuadrado - lado: double + Cuadrado(dato: double) + perimetro(): double + area (): double + getLado (): double + setLado (lado: double)

Repasemos las secciones del diagrama de clase:

NombreDeLaClase atributos métodos comentarios

De esta forma:

• + señala que su acceso es público, mientras que – indica acceso de tipo privado y # se refiere a un dato protegido.

• La clase Cuadrado será de naturaleza pública. Esto implica que debe existir un archivo Cuadrado.java,

• Hay un constructor Cuadrado (dato: double). Se identifica porque lleva el mismo nombre que la clase.

24 Muchos cursos combinan el curso de programación con las fases previas, comenzado por el levantamiento de

requerimientos. A nuestro juicio, esta costumbre rompe la idea de desarrollo por etapas de cualquier metodología y dispersa la atención del alumno.

Programación básica en C y Java (elaboró: José Luis López Goytia) 108 / 141

• Hay un único atributo llamado lado, de naturaleza privada. Este atributo será accesado a través de los métodos getSaldo y setSaldo.

• Hay métodos de naturaleza pública que arrojan el área y el perímetro. Se llaman area y perimetro, respectivamente.

Para efectos de pruebas, se hará una rutina principal que creará un objeto de tipo Cuadrado e invocará a sus métodos. La creación del objeto se hace utilizando la palabra new, considerando los parámetros que espera el constructor. La llamada a métodos y atributos se realiza con la sintaxis objeto.atributo u objeto.método (parámetros). El código quedaría como sigue: /* Descripción: programa que crea una clase Cuadrado con sus respectivas instrucciones de prueba. Probado con j2sdk1.4.2_05 / NetBeansIDE3.6 Elaboración: José Luis López Goytia */ public class Cuadrado { private double lado; public Cuadrado(double dato) { lado = dato; } public double area() { return lado * lado; } public double perimetro() { return lado * 4; } public double getLado() { return lado; } public void setLado(double dato) { lado = dato; } public static void main (String [] args) { Cuadrado mosaico; mosaico = new Cuadrado(6.0); System.out.println("El lado mide " + mosaico.getLado() + ". El perímetro es " + mosaico.perimetro() + " y el área es " + mosaico.area()); mosaico.setLado(5.0); System.out.println("El lado mide " + mosaico.getLado() + ". El perímetro es " + mosaico.perimetro() + " y el área es " + mosaico.area()); } }

El resultado del programa es: Lado= 6.0 El lado mide 6.0. El perímetro es 24.0 y el área es 36.0 Lado= 5.0 El lado mide 5.0. El perímetro es 20.0 y el área es 25.0

Observaciones acerca del código:

• La palabra class se utiliza para crear la clase. • Los modificadores + y – se transforman en public y private. • En Java existe el tipo de datos String, que no se encuentra en lenguaje C. • La rutina principal se indica como

public static void main (String[] args) {.

Programación básica en C y Java (elaboró: José Luis López Goytia) 109 / 141

La explicación detallada de esta línea queda fuera del alcance de este artículo, pero de manera sintética puede mencionarse que la palabra public señala un método público; static indica que se creará únicamente una vez este método independientemente de cuantos objetos se creen; void hace notar que no se devuelve ningún valor; main se utiliza para la rutina principal; finalmente, String [] args indica que puede recibir desde fuera varias cadenas de caracteres.

• La salida al monitor se hará mediante la instrucción System.out.println La explicación del significado de esta línea queda fuera del alcance de este artículo. • La instrucción Cuadrado mosaico;

define un objeto mosaico de tipo Cuadrado. Esta instrucción sólo crea la referencia al objeto en el Stack Memory.

• La instrucción

mosaico = new Cuadrado(6.0); crea el objeto en memoria, en el Heap Memory.

• Las instrucciones

Cuadrado mosaico; mosaico = new Cuadrado(6.0);

podrían abreviarse de la siguiente forma: Cuadrado mosaico = new Cuadrado(6.0);

COMPILANDO UN PROGRAMA EN JAVA DESDE COMANDOS (Indice) La creación del programa se puede realizar en cualquier editor que guarde archivos de tipo ASCII (.TXT). La extensión debe ser .java. Desde el entorno de comandos, el paso de compilación se realiza con la palabra javac. La ejecución se realiza con la palabra java. Si desea ver todas las opciones de ejecución, teclee javac sin ningún parámetro. La misma situación se aplica para java. La compilación sería similar a la siguiente: C:\Archivos de programa\Java\jdk1.5.0_06\bin>javac Cuadrado.java Si no despliega ningún mensaje, es que la compilación se hizo correctamente. En el paso siguiente se realiza la ejecución: C:\Archivos de programa\Java\jdk1.5.0_06\bin>java Cuadrado Es adecuado indicar al sistema operativo que ejecute el programa de Java desde cualquier directorio. En caso contrario, sólo se podrá ejecutar el compilador desde la ubicación <directorio de Java>\bin. En el caso de Windows XP la opción para lograr esto se encuentra de la siguiente forma: a) ir a Panel de control; b) ir a la opción sistema; c) dentro de opciones avanzadas ir a variables de entorno; d) agregar el directorio en donde se encuentra el compilador de java.

Programación básica en C y Java (elaboró: José Luis López Goytia) 110 / 141

Después de realizar estas operaciones, se puede llamar a javac y java desde cualquier otro directorio. REGLAS PARA EL NOMBRE DE IDENTIFICADORES EN JAVA (Indice)

Existen una serie de reglas para el nombre de identificadores, establecidos por Sun como un estándar para toda la programación de Java.

• Todas las clases de naturaleza pública se guardan en un archivo NombreDeLaClase.java • El nombre del constructor siempre será el mismo que el nombre de la clase. • Los nombres de las clases comienzan con mayúsculas, al igual que las interfases. • Los nombres de atributos y métodos comienzan con minúscula. • Se recomienda el uso de verbos para los métodos. • La primera letra de cada palabra intermedia debe ser mayúscula. Por ejemplo:

nombreDelMetodo. • El acceso a los atributos se realiza a través de las palabras get y set. • Las constantes se especifican con mayúscula. Por ejemplo: VALOR_MAXIMO. • La ubicación de los paquetes se hace todo con letras minúsculas.

ENCAPSULAMIENTO (Indice) En el ejemplo de cuadrado no se le ve mucho sentido a que el lado sea de tipo privado, más allá de las cuestiones didácticas. El diagrama de clases se podría simplificar como sigue:

Programación básica en C y Java (elaboró: José Luis López Goytia) 111 / 141

+ Cuadrado + lado: double + Cuadrado(dato: double) + perimetro(): double + area (): double

Con lo cual las demás clases podrían leer y modificar directamente el valor de lado. Sin embargo, imagine una clase que refleje el funcionamiento de una tarjeta de crédito. En este caso no puede haber un valor negativo. Una clase como se muestra en el siguiente diagrama:

+ TarjetaDebito + saldo: double + TarjetaDeDebito(dato: double) + meterDinero(dato:double) + sacarDinero ()

Sería sumamente riesgosa, pues permitiría leer y modificar directamente el valor del saldo desde cualquier otra clase. En su lugar se preferirá una clase que proteja el valor del saldo, a fin de que éste sólo pueda ser leído y modificado a través de los propios métodos de la clase. A este proceso se le conoce como encapsulamiento. La clase quedaría de la siguiente forma:

+ TarjetaDebito - saldo: double + TarjetaDebito(dato: double) + meterDinero(dato:double) + sacarDinero (): boolean + getSaldo(): double

Nota: un atributo también puede ser de tipo protected (protegido). En este caso sólo puede ser leído y modificado por la propia clase y sus subclases. Observe que sacarDinero() retorna un valor lógico. Si fue posible sacar dinero, afectará a saldo y retornará verdadero. En caso contrario, el saldo permanecerá intacto y devolverá falso. Tip: se recomienda que el estudiante codifique ambas clases y compruebe que no se puede afectar un atributo privado desde fuera de la propia clase.

EL OPERADOR THIS (Indice) En ocasiones, es confuso si el nombre de un identificador se refiere a un dato del objeto, a una variable o a un parámetro. Para romper esta ambigüedad se utiliza el operador this. Este operador señala que el atributo se refiere al objeto; se emplea como this.atributo. Por ejemplo, la clase Cuadrado que originalmente está escrita de la siguiente forma:

public class Cuadrado { private double lado; public void setLado(double dato) { lado = dato; } /* aquí va más código */

Programación básica en C y Java (elaboró: José Luis López Goytia) 112 / 141

} También podría escribirse de la siguiente forma:

public class Cuadrado { private double lado; public void setLado(double lado) { this.lado = lado; } /* aquí va más código */ }

En este ejemplo no se le ve mucha utilidad. Sin embargo, es indispensable su uso en diversas ocasiones, además de que algunos ambientes de desarrollo generan el código automáticamente como se muestra en la segunda versión. DIFERENCIAS ENTRE C Y JAVA (Indice) Las diferencias más significativas entre los lenguajes C y Java son las siguientes: • En lenguaje Java los apuntadores son implícitos, por tanto no existen los operadores ligados a éstos

y la sintaxis se vuelve más natural. • No se admite el operador de asignación dentro de la condición del if; solamente se admite el

operador de comparación, lo cual evita varios dolores de cabeza a los programadores. Observe el siguiente código en lenguaje C:

scanf("%d", &opcion); if (opcion = 1) printf("\nUsted desea ver Amores Perros"); else printf("\nUsted desea ver Babel");

El resultado siempre será Usted desea ver Amores Perros, porque if (opcion = 1) debe interpretarse como “asigna 1 a opcion y, si lo pudiste hacer (lo cual siempre es cierto), continúa”. En realidad lo que debería haberse puesto es if (opcion == 1). Para evitar estas confusiones, el compilador de Java sólo admite if (opcion == 1).

• En Java existen de manera natural los tipos de datos enumerados.

• En Java existe el tipo de dato cadena (String), con lo cual las cadenas se manejan de manera natural. Habría que aclarar que en términos estrictos las cadenas no son un tipo de dato primitivo, sino una clase. Pero, en términos prácticos, su manejo se da con la misma facilidad que los demás tipos de datos.

• Los tipos de datos en Java son diferentes de los de cualquier otro lenguaje25: Tipo Descripción Valor mínimo / máximo byte Entero con signo -128 a 127 short Entero con signo -32768 a 32767

25 Varios autores; Programación en Java 2; McGraw-Hill (Schaum); España, 2005; pág. 12.

Programación básica en C y Java (elaboró: José Luis López Goytia) 113 / 141

int entero con signo -2147483648 a 2147483647 long entero con signo -922117036854775808 a 92117036854775807 float real de simple precisión ±3.40282347e+38 a ±1.40239846e-45

double real de doble precisión ±1.79769313486231570e+308 a

±4.94065645841246544-324

char caracteres unicode \u0000 a \uFFFF boolean verdadero o falso true o false Los tipos por omisión son double e int. Para indicar que una cantidad se trata de un tipo de dato flotante, se señala el valor y a continuación se coloca una f (minúscula o mayúscula). Por ejemplo, 0.45f. Tip didáctico: al inicio se recomienda que por facilidad de manejo se empleen únicamente estos tipos de datos.

EJERCICIOS SUGERIDOS (Indice) • Capture la clase cuadrado, compílela y ejecútela desde el directorio en que se encuentra el sistema operativo. • Agregue la variable de entorno, mueva la clase Cuadrado a un directorio creado para los programas Java y

repita el proceso desde ese directorio (compilación y ejecución). • Realice el código de la clase Bacteria, con las siguientes especificaciones.

Esta clase asume que las bacterias se duplican en un periodo determinado (es un comportamiento típico de seres microscópicos); el fallecimiento se da de manera individual. En este caso la población inicial es, de manera forzosa, de 400 individuos (ciertamente, es un supuesto demasiado rígido, pero ejemplifica la forma de manejar constructores sin parámetros).

Bacteria - individuos: entero = 400 + Bacteria () + getIndividous(): entero + duplica () + muere ()

• Realice una clase que simule el lanzamiento de un dado, es decir, que devuelva un número al azar

entre 1 y 6. • Suponga que en el programa principal existe un objeto TarjetaDebito ejemplo1 y otro double

x, con base en el siguiente diagrama.

+ TarjetaDebito - saldo: double = 0 + TarjetaDebito(double saldoinicial) + consultarSaldo(): double + meter (double cantidad): void + sacar (double cantidad): bolean

A) Indique cuales instrucciones serían erróneas, suponiendo que se dan desde otra clase:

a) meter(ejemplo1,1000); b) ejemplo1.meter(1000);

Programación básica en C y Java (elaboró: José Luis López Goytia) 114 / 141

c) x = ejemplo1.meter(1000); d) ejemplo1.saldo = ejemplo1.saldo + 6000; Respuesta: __________________________

B) Indique nombre y extensión de los archivos que se crearían en Java al capturar y compilar el programa: ____________________________________________

• Complete las palabras que hacen falta. Cada inciso corresponde a una palabra.

public _____(a)_____ Equilatero { private _______(b)________ lado; public ________(c)______ (double dato) { lado = dato; System.out.println("Construyendo un triángulo equilátero."); } public String toString() { return "Triángulo equilátero. Lado = " + lado; } public static void main (String [] args) { Equilatero _____(d)_________; ejemplo = ______(e)_____ equilatero(8.5); System.out.println(ejemplo.toString()); } }

Respuesta: a) __________________ b) ___________________ c) ___________________ d) __________________ e) ___________________ • Dada la siguiente clase:

+ Cuadrado - lado: double + Cuadrado(dato: double) + perimetro(): double + getLado (): double + setLado (lado: double)

Haga un programa TestCuadrado.java que despliegue el área de un cuadrado con un lado de valor 8.

BIBLIOGRAFíA (Indice)

Horstmannn, Cay S.; Cornell, Gary; Java 2 Fundamentos; Prentice Hall; España, 2003. CON QUE PROSEGUIR (Indice)

• Antes de proseguir con otros temas se recomienda hacer varios ejercicios de complejidad similar. • Con que proseguir:

a. Repaso de los elementos básicos del lenguaje Java (condicionales, bifurcaciones, tipos de datos, etc.).

b. Compilación y ejecución de varias clases en el ambiente de desarrollo a utilizar o desde modo comandos.

Programación básica en C y Java (elaboró: José Luis López Goytia) 115 / 141

EL USO DE MÚLTIPLES CLASES EN JAVA

CONTENIDO Conocimientos previos Separando la clase del archivo de prueba La creación de paquetes en Java Ejercicios sugeridos Bibliografía

CONOCIMIENTOS PREVIOS (Indice)

Al llegar a este punto se recomienda que los estudiantes ya hayan realizado y compilado alguna clase sencilla.

SEPARANDO LA CLASE DEL ARCHIVO DE PRUEBA (Indice) Suponga que ya tiene codificada la clase Cuadrado.

+ Cuadrado - lado: double + Cuadrado(dato: double) + perimetro(): double + area (): double + getLado (): double + setLado (lado: double)

/* Descripción: programa que crea una clase Cuadrado con sus respectivas instrucciones de prueba. Probado con j2sdk1.4.2_05 / NetBeansIDE3.6 Elaboración: José Luis López Goytia */ public class Cuadrado { private double lado; public Cuadrado(double dato) { lado = dato; } public double area() { return lado * lado; } public double perimetro() { return lado * 4; } public double getLado() { return lado; } public void setLado(double dato) { lado = dato; } public static void main (String [] args) { Cuadrado mosaico; mosaico = new Cuadrado(6.0);

Programación básica en C y Java (elaboró: José Luis López Goytia) 116 / 141

System.out.println(mosaico.toString()); System.out.println("El lado mide " + mosaico.getLado() + ". El perímetro es " + mosaico.perimetro() + " y el área es " + mosaico.area()); mosaico.setLado(5.0); System.out.println(mosaico.toString()); System.out.println("El lado mide " + mosaico.getLado() + ". El perímetro es " + mosaico.perimetro() + " y el área es " + mosaico.area()); }

En el ejemplo anterior, la clase y las pruebas se encuentran en el mismo archivo. Esto no representa ningún problema si se trata de un solo archivo. Sin embargo, imagine que tiene un proyecto que involucra diversas clases y cada una tiene su propio main dentro del archivo. Tendríamos rutinas main esparcidas a lo largo del proyecto, cuando en realidad sólo debería haber una. Para solucionar esto, se crean archivos de prueba independientes de la clase. Estos archivos se llaman TestNombreDeLaClase. De esta forma, la clase no lleva main y el archivo TestNombreDeLaClase tiene las instrucciones necesarias para probar la clase. Para ejemplificar este enfoque, haremos una clase Cuadrado2 con su respectivo archivo de prueba, El diagrama de clase queda como sigue. [realizar diagrama] El código de la clase Cuadrado2 contendrá únicamente la clase:

/* Descripción: programa que crea una clase Cuadrado2. Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ public class Cuadrado2 { private double lado; public Cuadrado2(double dato) { lado = dato; } public double area() { return lado * lado; } public double perimetro() { return lado * 4; } public double getLado() { return lado; } public void setLado(double dato) { lado = dato; } }

Y el código de la clase TestCuadrado2 hará las veces de archivo de prueba:

/* Descripción: programa que prueba una clase Cuadrado2 ya creada. Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ public class TestCuadrado2 { public static void main (String [] args) {

Programación básica en C y Java (elaboró: José Luis López Goytia) 117 / 141

Cuadrado2 mosaico; mosaico = new Cuadrado2(6.0); System.out.println("El lado mide " + mosaico.getLado() + ". El perímetro es " + mosaico.perimetro() + " y el área es " + mosaico.area()); mosaico.setLado(5.0); System.out.println("El lado mide " + mosaico.getLado() + ". El perímetro es " + mosaico.perimetro() + " y el área es " + mosaico.area()); } }

LA CREACIÓN DE PAQUETES EN JAVA (Indice) ¿Cómo se logra que los diferentes desarrolladores de Java realicen sus clases y puedan ser usadas masivamente? La respuesta son los paquetes. Las clases se compilan en el subdirectorio bin de Java (o en el directorio especificado para el proyecto en el ambiente integrado de desarrollo que se está usando). En caso de usar otro subdirectorio, se especifica obligatoriamente mediante la palabra package. Esta indicación debe ir en la primera línea de código (sin considerar comentarios ni líneas en blanco). La instrucción queda similar a la siguiente:

package caleidosystem.proyecto; public class Ejemplo /* prosigue el código */

Las clases que quieran hacer uso de otras clases fuera de su paquete, tienen que indicar en donde se encuentran a través de la palabra import. Es importante ubicar el paquete en el cual se ubican las instrucciones de Java a utilizar. La instrucción import se coloca después de las instrucciones package; se puede indicar que utilice todas las clases de ese paquete o una clase en particular. Las instrucciones quedan similares a la siguiente:

import caleidosystem.proyecto.*; // importando todas las clases import caleidosystem.proyecto.Ejemplo; // importando sólo una clase

De hecho, Java incorpora por omisión el paquete java.lang.* a todas las clases para que reconozca instrucciones de uso común (como System.out.println). Las clases de Java son realizadas por un sinnúmero de empresas. Para evitar que existan paquetes con el mismo nombre, se recomienda que se utilice el nombre del dominio de la empresa en orden inverso (com.miempresa). Como el nombre del dominio es único a nivel mundial, prácticamente se elimina la posibilidad de paquetes duplicados. Los ambientes integrados utilizan una estructura de subdirectorios ya definida. Dentro de esa estructura, el subdirectorio src se ha reservado de facto para los códigos fuentes de las clases. Desde allí se correrán los programas. La estructura física será similar a la siguiente (nota: para facilitar un poco la lectura, usaremos caleidoSystem como si fuera nombre de dominio). caleidosystemjava subdirectorio de proyectos java ejemplos proyecto específico src directorio de clases caleidosystem nombre de dominio de la empresa proyecto directorio destinado de las clases Cuadrado2.java nombre de la clase

Programación básica en C y Java (elaboró: José Luis López Goytia) 118 / 141

pruebas directorio destinado a las pruebas TestCuadrado2.java nombre de la clase Para ejemplificar su uso crearemos una clase relativa a un rectángulo. El diagrama de clase será como sigue:

+ Rectangulo - lado1: double - lado2: double + Rectangulo(dato1: double, dato2: double) + perimetro(): double + area (): double + getLado1 (): double + getLado2 (): double + setLado1 (lado: double) + setLado2 (lado: double) + toString(void): String

El código de Rectangulo.java /* Descripción: programa que crea una clase Rectangulo. Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ package caleidosystem.proyecto; public class Rectangulo { private double lado1, lado2; public Rectangulo(double dato1, double dato2) { lado1 = dato1; lado2 = dato2; } public double area() { return lado1 * lado2; } public double perimetro() { return lado1 * 2 + lado2 * 2; } public double getLado1() { return lado1; } public double getLado2() { return lado2; } public void setLado1(double dato) { lado1 = dato; } public void setLado2(double dato) { lado2 = dato; } public String toString() { return "Lado1= " + lado1 + "y lado2=" + lado2 + "."; } }

Cuando una clase se encuentra en el mismo paquete no es necesario utilizar la palabra import. En caso contrario, emplearán import nombredelpaqute.NombreDeLaClase; se puede utilizar un asterisco en lugar

Programación básica en C y Java (elaboró: José Luis López Goytia) 119 / 141

del nombre de la clase. Observe que el nombre del paquete está todo en minúsculas. El código será similar al siguiente: import com.caleidosystem.proyecto.*; o bien import com.caleidosystem.proyecto.Rectangulo; /* Descripción: programa que prueba una clase Rectangulo ya creada. Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ package caleidosystem.pruebas; public class TestRectangulo { public static void main (String [] args) { Rectangulo mosaico; mosaico = new Rectangulo(6.0, 5.0); System.out.println("Los lados son: " + mosaico.getLado1() + " y " + mosaico.getLado2() + "."); System.out.println("El perímetro es " + mosaico.perimetro() + " y el área es " + mosaico.area()); mosaico.setLado1(4.0); mosaico.setLado1(3.0); System.out.println("Los lados son: " + mosaico.getLado1() + " y " + mosaico.getLado2() + "."); System.out.println("El perímetro es " + mosaico.perimetro() + " y el área es " + mosaico.area()); } }

Y el resultado del programa es:

Los lados son: 6.0 y 5.0. El perímetro es 22.0 y el área es 30.0 Los lados son: 3.0 y 5.0. El perímetro es 16.0 y el área es 15.0

LA SOBRECARGA DE MÉTODOS EN JAVA (Indice) Una clase permite especificar métodos con el mismo nombre y diferente número o tipo de parámetros. El método a ejecutar se elige en razón de los parámetros señalados. Es muy común que la carga se aplique a los constructores de la clase. Como ejemplo, revise el siguiente código: /* Descripción: programa que ejemplo la sobrecarga de métodos utilizando promedio Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ package caleidosystem.proyecto; public class Promedio { double promedio (double dato1, double dato2) {

Programación básica en C y Java (elaboró: José Luis López Goytia) 120 / 141

return ((dato1 + dato2) / 2); } int promedio (int dato1, int dato2) { return ((dato1 + dato2) / 2); } double promedio (double dato1, double dato2, double dato3) { return ((dato1 + dato2 + dato3) / 3); } public static void main (String[] args) { Promedio media = new Promedio(); System.out.println("El promedio de 3.5 y 6.7 es:" + media.promedio(3.5,6.7)); System.out.println("El promedio de 3 y 7 es:" + media.promedio(3,7)); System.out.println("El promedio de 3.1, 4.2 y 5.3 es :" + media.promedio(3.1,4.2,5.3)); } }

EJERCICIOS SUGERIDOS (Indice)

• Cree un proyecto desde el ambiente de desarrollo elegido y cree las clase Cuadrado, Cuadrado2 y TestCuadrado2.

• Cree en el mismo proyecto las clases Rectangulo y TestRectangulo. • Cree la clase Promedio para verificar el proceso de sobrecarga.

• Cree la siguiente clase, separando la clase del archivo de prueba correspondiente. Verifique que

no se puede modificar el saldo directamente desde la rutina principal. Posteriormente haga el atributo saldo público y confirme que sí es posible accesarlo desde fuera de la clase.

+ TarjetaDebito - saldo: double + TarjetaDebito(dato: double) + meterDinero(dato:double) + sacarDinero (): boolean + getSaldo(): double

BIBLIOGRAFIA (Indice) Eckel, Bruce; Piensa en Java; Pearson – Prentice Hall; segunda edición; España, 2002; 906 págs. Fowler, Martin; UML Gota a gota; Pearson; México, 1999; 203 págs.

Programación básica en C y Java (elaboró: José Luis López Goytia) 121 / 141

ARREGLOS EN JAVA

CONTENIDO Conocimientos previos Manejo de arreglos en Java Ejemplo Ejercicios sugeridos Bibliografía

CONOCIMIENTOS PREVIOS (Indice)

Se parte del hecho de que los alumnos ya conocen el concepto de arreglo y lo han codificado en algún otro lenguaje.

MANEJO DE ARREGLOS EN JAVA (Indice) Como primer acercamiento podría decirse que un arreglo en Java funciona igual que en C. Pero en realidad, es bastante más que eso. . La declaración del arreglo se almacena en el Stack Memory, mientras los datos del arreglo están en el Heap Memory.

Stack Memory Heap Memory

TipoDeDato[] nombreDelArreglo;

nombreDelArreglo = new TipoDeDatos[númeroDeElementos];

Figura 1. La creación de arreglos en Java.

La declaración se realiza como: TipoDeDato[] nombreDelArreglo;

Que también pudiera escribirse como: TipoDeDato nombreDelArreglo[];

Es recomendable no revolver tipos. La primera sintaxis es la que recomienda SUN. Para inicializar se puede recurrir a la forma típica, en que primero se declara y después se asigna el valor a cada elemento:

Programación básica en C y Java (elaboró: José Luis López Goytia) 122 / 141

String[] nombre; nombre = new String[3]; nombre[0] = “Adán”; nombre[1] = “Eva“; nombre[2] = “Otro“;

O bien utilizar una forma corta: String[] nombre = {“Adán”, “Eva”, “Otro” }; La forma corta también se puede aplicar a objetos. Por ejemplo: Fecha[] celebraciones = { new Fecha(1,1,2006), new Fecha(10,5,2006), new Fecha(25,12,2006) };

Este manejo permite varias posibilidades que no estaban presentes en el lenguaje C tradicional:

a) El tamaño del arreglo se puede crear en tiempo de ejecución. int numeroDeElementos; … /* en esta parte del código se calcula el valor de x */ … char[] arreglo; arreglo = new char [x];

b) Pueden crearse arreglos bidimensionales tradicionales, pero también se pueden crear arreglos de arreglos, cada uno con una longitud diferente.

int[][] dosDimensiones = new int [2][]; dosDimensiones[0] = new int[5]; dosDimensiones[1] = new int[4] De hecho, si todos fueran de la misma longitud se recomienda asignarles en un solo paso. int[][] dosDimensiones = new int [2][5];

c) Si se vuelve a crear el arreglo se pierde el contenido anterior y se vuelve a un arreglo vacío. El arreglo anterior será destruido posteriormente por el recolector de basura.

d) Por supuesto, también pueden haber arreglos de objetos. e) La palabra lenght sirve para averiguar el tamaño del arreglo.

Finalmente, cabe citar que la función arraycopy permite copiar el contenido de un arreglo a otro. Su sintaxis es: System.arraycopy(arreglo1, posicion1, arreglo2, posicion2, elementosACopiar);

Programación básica en C y Java (elaboró: José Luis López Goytia) 123 / 141

EJEMPLO (Indice)

Para ejemplificar el uso de arreglos, suponga que usted quiere crear una clase que realice cálculos estadísticos (promedio, desviación estándar, etc.). El listado de números se los dará al mandarla llamar, a través de un arreglo. El programa, con su respectivo archivo de pruebas, quedaría como sigue: /* Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ package caleidosystem.proyecto; public class Estadistica { private double[] datos; private int numeroDeElementos; public Estadistica (double[] elementos) { numeroDeElementos = elementos.length; datos = new double[numeroDeElementos]; System.arraycopy(elementos, 0, datos, 0, numeroDeElementos); // sintaxis simplificada /* Sintaxis tradicional */ // for (int i=0; i<numeroDeElementos; i++) // datos[i] = elementos[i]; } public double promedio() { double prom, suma = 0; for (int i=0; i<numeroDeElementos; i++) suma += datos[i]; prom = suma / numeroDeElementos; return(prom); } public double desviacionEstandar() { // obtener promedio double prom, s=0; prom = promedio(); for (int i=0; i<numeroDeElementos; i++) // suma el cuadrado de las diferencias s += (datos[i] - prom) * (datos[i] - prom); s = Math.sqrt(s/numeroDeElementos); return (s); } }

/* Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ package caleidosystem.pruebas; import caleidosystem.proyecto.Estadistica; public class TestEstadistica { public static void main(String[] args) { double[] listado = {3, 8, 10, 6, 4}; double resultado;

Programación básica en C y Java (elaboró: José Luis López Goytia) 124 / 141

Estadistica lista = new Estadistica (listado); resultado = lista.desviacionEstandar(); System.out.print("La desviación estándar es:" + resultado); } }

Destacaremos varios puntos de este programa:

• Observe que el arreglo en la clase no tiene longitud fija. Se establece conforme al número de elementos del arreglo que recibe desde fuera.

• El método desviacionEstandar manda llamar al método promedio.

• Se utiliza una versión simplificada para copiar archivos pero, entre comentarios, se establece el

equivalente con instrucciones tradicionales.

• La función sqrt de la clase Math es una función estática. Las funciones y atributos estáticos son aquéllos en que sólo hay uno para toda la clase, independientemente de cuantos objetos de esa clase se hayan creado. Por ello se mandan llamar con la sintaxis NombreDeLaClase.Método o NombreDeLaClase.Atributo, sin necesidad de saber si se han creado o no objetos de esa clase.

EJERCICIOS SUGERIDOS (Indice)

• Elabore el diagrama UML de la clase.

• Verifique que el código se ejecute en su compilador.

• Agregue los métodos menor y mayor a la clase.

• (AVANZADO) Agregue el método moda a la clase (la moda es el dato que se repite más veces). Si existen más de dos modas, que despliegue el valor mayor.

BIBLIOGRAFIA (Indice) Eckel, Bruce; Piensa en Java; Pearson – Prentice Hall; segunda edición; España, 2002; 906 págs. Fowler, Martin; UML Gota a gota; Pearson; México, 1999; 203 págs.

Programación básica en C y Java (elaboró: José Luis López Goytia) 125 / 141

HERENCIA Y POLIMORFISMO EN JAVA

CONTENIDO Conocimientos previos Concepto de herencia en Java Control de accesos Ejemplo de herencia Polimorfismo Ejercicios sugeridos Bibliografía Solución de ejercicios

CONOCIMIENTOS PREVIOS (Indice)

Se parte del hecho de que los alumnos ya conocen el concepto de arreglo en Java y su codificación, así como el uso de paquetes.

CONCEPTO DE HERENCIA EN JAVA (Indice) La herencia significa que una clase hija -también conocida como subclase- hereda de una clase padre, todos sus atributos y sus métodos. Para ello se emplea la palabra extends. En todo momento debe respetarse las reglas impuestas por la clase padre. Ello implica que la clase hija no puede acceder a los atributos privados de la clase padre; sólo puede accesarlos a través de los métodos que brinda la propia clase padre. Tampoco puede brincarse a su constructor, lo cual obliga a que la primera instrucción del constructor de la clase hija sea una llamada al constructor de la clase padre. Para ello existe la palabra super. Una subclase puede añadir métodos y atributos. En todo momento se considerará que lo atributos y método de la clase hija son los propios más los heredados. Una subclase también puede sustituir alguno de sus métodos, lo cual se conoce como sobreescritura de métodos. La sobreescritura de métodos cancela al método heredado y coloca el propio. Aquí conviene hacer una aclaración: todos los objetos de Java heredan de la clase Object. Esto se hace de manera automática, sin necesidad de utilizar la palabra extends. CONTROL DE ACCESOS (Indice) En Java, el alcance de los modificadores es el siguiente:

Modificador Acceso por la propia clase

Acceso por clases del mismo

paquete

Acceso por subclases

Acceso por cualquier clase

private XXX default XXX XXX protected XXX XXX XXX

Programación básica en C y Java (elaboró: José Luis López Goytia) 126 / 141

public XXX XXX XXX XXX Si no se indica el tipo de modificador, por omisión se asume que será de tipo default. EJEMPLO DE HERENCIA EN JAVA (Indice) Suponga el siguiente diagrama UML:

TarjetaDebito # saldo : double +TarjetaDebito(saldoInicial : double) + getSaldo(): double + meterDinero (cantidad : double) : void + sacarDinero (cantidad : double) : boolean

TarjetaCredito - lineaDeCredito : double + TarjetaCredito (saldo : double) + TarjetaCredito (saldo : double, lineaCredito : double) + getLineaDeCredito() : double + setLineaDeCredito(cantidad: double) + sacarDinero (cantidad : double) : boolean

La idea básica es que una tarjeta de débito sólo puede disponer del monto del ahorrador. Por lo tanto, el saldo no puede ser negativo. El método sacarDinero debe verificar si se cumple esta condición, en cuyo caso debe disminuir el saldo y devolver verdadero. Por el contrario, si se desea sacar más dinero que el saldo, no deberá realizar la operación y devolver el valor de falso. La tarjeta de crédito funciona de manera similar, pero, además del saldo, el tarjetahabiente tiene una línea de crédito. Podrá disponer de su saldo más la cantidad que le permita su línea de crédito. Por eso es necesario sobrescribir el método sacarDinero. El código quedaría como sigue:

package caleidosystem.proyecto; public class TarjetaDebito { protected double saldo; public TarjetaDebito(double montoInicial) { saldo = montoInicial; } public double getSaldo() { return saldo; } public void meterDinero (double monto) { saldo += monto; } public boolean sacarDinero (double monto) { if (monto <= saldo) { saldo -= monto; return true;

Programación básica en C y Java (elaboró: José Luis López Goytia) 127 / 141

} else return false; } }

package caleidosystem.proyecto; public class TarjetaCredito extends TarjetaDebito { private double lineaDeCredito; public TarjetaCredito (double saldo) { super(saldo); lineaDeCredito = 0; } public TarjetaCredito (double saldo, double lineaCred) { super(saldo); lineaDeCredito = lineaCred; } public double getLineaDeCredito() { return lineaDeCredito; } public void setLineaDeCredito(double monto) { lineaDeCredito = monto; } public boolean sacarDinero (double monto) { if (monto <= saldo + lineaDeCredito) { saldo -= monto; return true; } else return false; } }

POLIMORFISMO (Indice)

Java permite que una instancia de clase de tipo padre también pueda usarse para crear un objeto de tipo hijo. Este objeto de manera natural podrá acceder a los métodos que le son comunes a la clase y a la subclase. ¿Qué sucedería si se quisiera acceder a los métodos de la subclase que no contiene la clase? Se tendría que declarar una instancia de la subclase y, mediante un forzamiento de tipos, depositar allí al objeto que fue declarado en la clase. Como en múltiples ocasiones no se sabe de antemano de que tipo es el objeto -por ejemplo, cuando se recibe como parámetro- Java permite preguntarlo a través del operador instanceof. De esa forma, nos podemos asegurar que en todo momento estamos empleando el tipo correcto de datos. Retomando el ejemplo anterior: ¿qué pasaría si una tarjeta de crédito tiene una línea de crédito de 0, o bien si el usuario decide nunca emplear la línea de crédito? En la práctica se convertiría en una tarjeta de débito. Puede decirse entonces que una tarjeta de crédito también es una tarjeta de débito. Algo similar sucede en el caso de la herencia. Un objeto de tipo TarjetaCredito también es de tipo TarjetaDebito. Suponga la siguiente declaración:

Programación básica en C y Java (elaboró: José Luis López Goytia) 128 / 141

TarjetaCredito ejemplo = new TarjetaCredito (10000.0, 1500.0); La instrucción if (ejemplo instanceof TarjetaCredito) devolvería verdadero. Y la instrucción if (ejemplo instanceof TarjetaDebito) devolvería verdadero también. No sucede lo mismo de manera inversa. Una tarjeta de débito no puede comportarse como una tarjeta de crédito. Por tanto la siguiente instrucción: TarjetaDebito ejemplo = new TarjetaDebito (10000.0); if (ejemplo instanceof Credito)

devolvería falso. Si se considera ese enfoque, se podrá deducir fácilmente que si hay un objeto x, la sentencia if (x instanceof Object) devolverá verdadero sin importar que tipo de objeto sea x, pues todas las clases heredan automáticamente de Object. A manera de ejemplo, el siguiente código presenta un arreglo de objetos, en el cual se mezclan objetos de tipo TarjetaDebito y TarjetaCredito.

package caleidosystem.pruebas; import caleidosystem.proyecto.*; public class TestTarjetaCredito2 { public static void main (String[] args) { TarjetaDebito arregloDeTarjetas[]; TarjetaCredito auxiliar; arregloDeTarjetas = new TarjetaDebito[5]; arregloDeTarjetas[0] = new TarjetaDebito(2000.0); System.out.println("En el lugar 0 hay una tarjeta de DEBITO con saldo de: " + arregloDeTarjetas[0].getSaldo()); arregloDeTarjetas[1] = new TarjetaCredito(2000.0, 1000.0); arregloDeTarjetas[1].sacarDinero(2500); System.out.println("En el lugar 1 hay una tarjeta de CREDITO con saldo de: " + arregloDeTarjetas[1].getSaldo()); if (arregloDeTarjetas[1] instanceof TarjetaCredito) { auxiliar = (TarjetaCredito) arregloDeTarjetas[1]; System.out.println(" y límite de crédito de : " + auxiliar.getLineaDeCredito()); } } }

CLASES ABSTRACTAS (Indice) En ocasiones, se tienen los atributos de una clase y varios métodos, pero de otros métodos se desconoce el detalle. No obstante, sí se puede establecer la interfaz hacia el exterior (nombre,

Programación básica en C y Java (elaboró: José Luis López Goytia) 129 / 141

parámetros de entrada y tipo de datos de retorno). Con estos datos se establece un método abstracto, cuya implementación será establecida por la subclase. Cuando uno o más métodos son abstractos, se considera que la clases como tal es abstracta. Una clase abstracta tiene constructor, pero no es posible crear objetos de estas clases porque son clases “incompletas”. Los objetos se declararán de tipo subclase. Conviene aclarar que la subclase está obligada a instrumentar los métodos abstractos y puede añadir sus propios atributos y métodos. A manera de ejemplo, imagine que en una escuela cambiará el sistema de calificaciones. En ambos sistemas se realizan tres evaluaciones parciales y un examen global. En el caso 1 se coloca la calificación más alta entre el promedio de las tres evaluaciones parciales y el examen global. Por ejemplo:

Evaluaciones Promedio Examen Calificación parciales Final Definitiva 6 6 6 6 7 7 8 7 8 8 9 9 7 7 7 7 5 7

En el caso 2 se coloca la calificación más alta entre el promedio de las tres evaluaciones parciales y el examen global, pero únicamente si el promedio de las tres evaluaciones parciales es de 8 como mínimo. Si fuera menor, se coloca el resultado del examen global. Por ejemplo:

Evaluaciones Promedio Examen Calificación parciales Final Definitiva 6 6 6 6 7 7 8 7 8 8 9 9 7 7 7 7 5 5

Las clases quedarían programadas de la siguiente manera:

Programación básica en C y Java (elaboró: José Luis López Goytia) 130 / 141

+ Curso

{abstract}

- parcial1: entero - parcial2: entero - parcial3: entero - global: entero

+ Curso (calif1, calif2, calif3, examenGlobal: entero) + cambiarCalificaciones (calif1, calif2, calif3, examenGlobal: entero): void + obtenerPromedio():

entero

+ Curso2000 + Curso2006 + Curso2000 (calif1, calif2, calif3, examenGlobal: entero) + cambiarCalificaciones (calif1, calif2, calif3, examenGlobal: entero): void + obtenerPromedio(): entero

+ Curso2006 (calif1, calif2, calif3, examenGlobal: entero) + cambiarCalificaciones (calif1, calif2, calif3, examenGlobal: entero): void + obtenerPromedio(): entero

package caleidosystem.proyecto; public abstract class Curso { private int parcial1, parcial2, parcial3, global; public Curso (int calif1, int calif2, int calif3, int examenGlobal) { parcial1 = calif1; parcial2 = calif2; parcial3 = calif3; global = examenGlobal; } public void cambiarCalificaciones (int calif1, int calif2, int calif3, int examenGlobal) { parcial1 = calif1; parcial2 = calif2; parcial3 = calif3; global = examenGlobal; } public abstract int obtenerPromedio(); }

Programación básica en C y Java (elaboró: José Luis López Goytia) 131 / 141

package caleidosystem.proyecto; public class Curso2000 extends Curso { public Curso2000 (int calif1, int calif2, int calif3, int examenGlobal) { super(calif1, calif2, calif3, examenGlobal); } public int obtenerPromedio() { int sumaParcial = parcial1 + parcial2 + parcial3; int promedio; if (sumaParcial < 18) promedio = (int) (sumaParcial / 3.0); else promedio = (int) (sumaParcial / 3.0 + 0.5); if (global > promedio) return global; else return promedio; } }

package caleidosystem.proyecto; public class Curso2006 extends Curso { public Curso2006 (int calif1, int calif2, int calif3, int examenGlobal) { super(calif1, calif2, calif3, examenGlobal); } public int obtenerPromedio() { int sumaParcial = parcial1 + parcial2 + parcial3; int promedio; if (sumaParcial < 24) return global; else { promedio = (int) (sumaParcial / 3.0 + 0.5); if (global > promedio) return global; else return promedio; } } }

INTERFASES Q (Indice) Los métodos abstractos son aquéllos cuya implementación se deja de manera obligatoria a la clase hija (subclases). La clase sólo indica el encabezado: nombre de la clase, parámetros de entrada y parámetros de salida. Cuando una clase contiene uno o más métodos abstractos se dice que es una clase abstracta. Cuando todos los métodos son abstractos ya no se habla propiamente de una clase abstracta, sino de una interfase. Las interfases sirven para enunciar la estructura mínima que deben contener las clases hijas. De alguna forma heredan solamente “obligaciones”.

Programación básica en C y Java (elaboró: José Luis López Goytia) 132 / 141

A manera de ejemplo, suponga que desea hacer diversas clases de polígonos, y para cada uno debe haber –al menos- una rutina que calcule el área y otra que calcule el perímetro. El diagrama se muestra a continuación, junto con las clase Rectangulo y Triangulo como clases hija. << interface >>

+ Poligono

+ area(): double

+ perimetro(): double

+ Rectangulo + Triangulo

- lado1: double - lado2: double

+ area(): double + perimetro(): double + cambiarValores (dato1: double, dato2: double) + getLado1(): double + getLado2(): double

El código quedaría para la interfase sería:

package caleidosystem.proyecto; public interface Poligono { public double area(); public double perimetro(); }

Mientras que Rectangulo quedará:

package caleidosystem.proyecto; public class Rectangulo implements Poligono { private double lado1, lado2; public Rectangulo(double dato1, double dato2) { lado1 = dato1; lado2 = dato2; } public double area() { return lado1 * lado2; } public double perimetro() { return lado1 * 2 + lado2 * 2; } public void cambiarValores(double dato1, double dato2) { lado1 = dato1; lado2 = dato2; } public double getLado1() { return lado1; } public double getLado2() {

Programación básica en C y Java (elaboró: José Luis López Goytia) 133 / 141

return lado2; } }

El caso de Triangulo se le deja como ejercicio al lector. EJERCICIOS SUGERIDOS (Indice) GRUPO 1

• Conteste las siguientes preguntas: o ¿Cuántos atributos tiene la tarjeta de crédito? o ¿Cuántos métodos tiene la tarjeta de débito? o ¿En dónde hay una situación de sobreescritura?

• Verifique que el código se ejecute en su compilador. Para ello cree las clases TestTarjetaDebito y TestTarjetaCredito que sirvan para probar las clases creadas. Si los programas creados no corrieran adecuadamente, compárelos con la solución mostrada al final de este capítulo (no revise la solución hasta no haberlo intentado previamente).

• Cree una clase TestTarjetaCredito3 que declare un arreglo de 5 elementos de tipo TarjetaDebito.

Llene el arreglo con objetos de tipo TarjetaDebito y TarjetaCredito. Posteriormente, utilizando un ciclo, despliegue el estatus de la cuenta en una línea: tipo, saldo y, el caso de la tarjeta de crédito, límite de crédito.

• (AVANZADO) Cree una clase TarjetaDebito2 y TarjetaCredito2 con la misma

funcionalidad que la mostrada, pero suponiendo que el saldo fuera de tipo privado. GRUPO 2

• Cree una clase Circulo cuyo único atributo sea diámetro y tenga los métodos area y perimetro. Posteriormente cree una subclase Cilindro que añada el método altura y tenga codificados los métodos area y volumen.

• Codifique la clase Triangulo citada en el tema de interfases. Recuerde que las rutinas deben

funcionar para cualquier tipo de triángulo. • A partir del siguiente diagrama, realice las clases Cuadrado, Cubo y TestCubo. Tenga especial

cuidado en respetar las especificaciones de los diagramas de clase. La clase TestCubo debe desplegar lo siguiente:

Suponiendo que hay un cubo de lado 3. El área es 54. El volumen es 27.

Cuadrado - lado: double + Cuadrado () + perimetro(): double + area(): double + setLado (dato: double)

Programación básica en C y Java (elaboró: José Luis López Goytia) 134 / 141

+ getLado(): double

Cubo + Cubo() + volumen(): double + area(): double

GRUPO 3

• ¿Qué desplegará el siguiente programa?

public class EjemploDeHerencia { public EjemploDeHerencia() { System.out.println("Constructor del padre"); } public static void main (String [] args) { EjemploDeHerencia2 objeto = new EjemploDeHerencia2(); } } class EjemploDeHerencia2 extends EjemploDeHerencia { public EjemploDeHerencia2() { System.out.println("Constructor del hijo"); } } Respuesta: __________________________

__________________________ • ¿Qué desplegará el siguiente programa?

public class EjemploDeSobrecarga {

public void despliega() { System.out.println("Despliegue del padre"); } public static void main (String [] args) { EjemploDeSobrecarga2 objeto = new EjemploDeSobrecarga2(); objeto.despliega(); } } class EjemploDeSobrecarga2 extends EjemploDeSobrecarga {

public void despliega() { System.out.println("Despliegue del hijo");

} }

Respuesta: __________________________ __________________________

• Suponga el siguiente caso:

public class Cuadrado public double area() { return lado * lado } public class Cubo extends Cuadrado public double area() { return lado * lado * 6 }

Programación básica en C y Java (elaboró: José Luis López Goytia) 135 / 141

public double volumen () { return lado * lado * lado } a) ¿Qué desplegará Cuadrado c = new Cubo(5.0); System.out.println(c.area()); Respuesta: __________________________

b) ¿Con qué instrucciones se podría desplegar el volumen del cubo? ____________________________________________________ ____________________________________________________ ____________________________________________________ ____________________________________________________

• ¿Qué sucederá en el siguiente caso?

package caleidosystem.proyecto; public class ModificadoresDeHerencia { private void despliega () { System.out.println("Despliegue del padre"); } public static void main (String [] args) { ModificadoresDeHerencia2 objeto = new ModificadoresDeHerencia2(); objeto.despliega(); } } class ModificadoresDeHerencia2 extends ModificadoresDeHerencia { public void despliega () { System.out.println("Despliegue del hijo"); } }

• ¿Qué sucederá en el siguiente caso?

package caleidosystem.proyecto; public class ModificadoresDeHerencia { public void despliega () { System.out.println("Despliegue del padre"); } public static void main (String [] args) { ModificadoresDeHerencia2 objeto = new ModificadoresDeHerencia2(); objeto.despliega(); } } class ModificadoresDeHerencia2 extends ModificadoresDeHerencia { private void despliega () { System.out.println("Despliegue del hijo"); } }

BIBLIOGRAFIA (Indice) Eckel, Bruce; Piensa en Java; Pearson – Prentice Hall; segunda edición; España, 2002; 906 págs. Horstmannn, Cay S.; Cornell, Gary; Java 2 Fundamentos; Prentice Hall; España, 2003.

Programación básica en C y Java (elaboró: José Luis López Goytia) 136 / 141

SOLUCIÓN DE EJERCICIOS SELECCIONADOS (Indice) /* Descripción: programa que prueba una clase tarjeta de débito. Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ package caleidosystem.pruebas; import caleidosystem.proyecto.TarjetaDebito; public class TestTarjetaDebito { public static void main (String[] args) { TarjetaDebito tarjeta = new TarjetaDebito(1000.0); System.out.println("El saldo después de arrancar con $1000.00 es: " + tarjeta.getSaldo()); tarjeta.meterDinero(500.0); System.out.println("El saldo después de meter $500.00 es: " + tarjeta.getSaldo()); if (tarjeta.sacarDinero(2000.00) == true) System.out.println("El saldo después de sacar $2000.00 es: " + tarjeta.getSaldo()); else System.out.println("No fue posible sacar $2000.00"); if (tarjeta.sacarDinero(1000.00) == true) System.out.println("El saldo después de sacar $1000.00 es: " + tarjeta.getSaldo()); else System.out.println("No fue posible sacar $1000.00"); } }

/* Descripción: programa que prueba una clase tarjeta de crédito. Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ package caleidosystem.pruebas; import caleidosystem.proyecto.TarjetaCredito; public class TestTarjetaCredito { public static void main (String[] args) { TarjetaCredito tarjeta = new TarjetaCredito(2000.0, 1000.0); System.out.println("El saldo después de arrancar con $2000.00 es: " + tarjeta.getSaldo()); System.out.println("La línea de crédito es: " + tarjeta.getLineaDeCredito()); tarjeta.meterDinero(500.0); System.out.println("El saldo después de meter $500.00 es: " + tarjeta.getSaldo()); if (tarjeta.sacarDinero(3000.00) == true) { System.out.println("El saldo después de sacar $3000.00 es: " + tarjeta.getSaldo()); } else System.out.println("No fue posible sacar $3000.00"); if (tarjeta.sacarDinero(1000.00) == true) System.out.println("El saldo después de sacar $1000.00 es: " + tarjeta.getSaldo()); else System.out.println("No fue posible sacar $1000.00"); } }

Programación básica en C y Java (elaboró: José Luis López Goytia) 137 / 141

COMPOSICIÓN EN JAVA

CONTENIDO Conocimientos previos Concepto de composición Ejemplo Ejercicios sugeridos Bibliografía

CONOCIMIENTOS PREVIOS (Indice)

Se parte del hecho de que los alumnos ya conocen el concepto de arreglo y lo han codificado en algún otro lenguaje.

CONCEPTO DE COMPOSICIÓN (Indice) La composición significa que una clase tiene como atributo un objeto de otra clase. Imagine, por ejemplo el caso de un cliente bancario que tiene una tarjeta de débito. El diagrama quedaría similar al siguiente: + CuentaDeCheques - titular: String - cuenta: TarjetaDebito - Cliente (n:String, t: TarjetaDebito) - getTitular(): String - setTitular(n:String): void - getCuenta(): TarjetaDebito - setCuenta(t:TarjetaDebito): void La composición se puede abordar de manera natural si uno se acostumbra que un objeto se puede pasar como argumento. Para eso momento –claro está- el objeto ya debe estar creado. Recuérdese que una clase es un tipo de dato. Por tanto, en donde se pone un tipo primitivo de dato (números, caracteres o datos lógicos) es posible colocar una clase.

EJEMPLO (Indice)

A manera de guía, tómese el ejemplo de un coche conformado por un 2 puertas y 4 llantas. Las puertas y las llantas deben construirse primero para después armar el coche. Reconocemos que el ejemplo es bastante artificial pero servirá para ubicar el concepto con claridad. Los constructores respectivos desplegarán cuando ya fue construido el objeto. El código de las puertas sólo indicará que la puerta fue creada:

+ TarjetaDebito - saldo: double + TarjetaDebito(dato: double) + meterDinero(dato:double) + sacarDinero (): boolean + getSaldo(): double

Programación básica en C y Java (elaboró: José Luis López Goytia) 138 / 141

/* Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ package caleidosystem.proyecto; public class Puerta { public Puerta() { System.out.println("Construyendo un objeto puerta."); } }

El código de las llantas recibirá algunos parámetros y señalará que fueron creadas. /* Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ package caleidosystem.proyecto; public class Llanta { private double altura; private double anchura; private double rin; public Llanta (double alto, double ancho, double radio) { altura = alto; anchura = ancho; rin = radio; System.out.println("Construyendo un objeto llanta altura = " + alto + ", anchura = " + ancho + ", rin = " + rin); } }

El coche estará construido de ambos objetos: /* Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ package caleidosystem.proyecto; public class Coche { public Llanta llanta1; public Llanta llanta2; public Llanta llanta3; public Llanta llanta4; public Puerta puerta1; public Puerta puerta2; // constructor 1: construyendo un coche sin parámetros public Coche() { System.out.println("Construyendo un objeto coche."); } // constructor 2: construyendo un coche con parámetros public Coche(Llanta l1, Llanta l2, Llanta l3, Llanta l4, Puerta p1, Puerta p2) { System.out.println("Construyendo un objeto coche."); llanta1 = l1; llanta2 = l2; llanta3 = l3; llanta4 = l4;

Programación básica en C y Java (elaboró: José Luis López Goytia) 139 / 141

puerta1 = p1; puerta2 = p2; } }

Con finalidades didácticas, los atributos fueron declarados públicos, lo cual permitiría dos posibilidades:

a) Crear el objeto coche y después añadirle los objetos. b) Crear los objetos desde fuera y pasarlos al objeto coche como parámetros.

Por lo regular el camino b) es el más natural. Este caso lo ejemplifica bien. El primer caso es algo así como: “te vendo un coche pero no tiene llantas ni puertas. Tú se las pones después”. Por otra parte, el camino b) tiene mayor seguridad si los atributos llanta y puerta se hacen de naturaleza privada, en cuyo caso el camino a) ya no es posible. A continuación ambos caminos, cada uno con un archivo de pruebas: Camino a) Crear el objeto coche y después añadirle los objetos.

/* Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ package caleidosystem.pruebas; import caleidosystem.proyecto.*; public class TestCoche { public static void main (String[] args) { Coche objetoCoche = new Coche(); objetoCoche.llanta1 = new Llanta(165.0, 14.0, 15.0); objetoCoche.llanta2 = new Llanta(165.0, 14.0, 15.0); objetoCoche.llanta3 = new Llanta(170.0, 15.0, 14.0); objetoCoche.llanta4 = new Llanta(170.0, 15.0, 14.0); objetoCoche.puerta1 = new Puerta(); objetoCoche.puerta2 = new Puerta(); } }

Camino b) Crear los objetos desde fuera y pasarlos al objeto coche como parámetros.

/* Probado con j2sdk1.5.0_06 / NetBeans IDE 5.0 Elaboración: José Luis López Goytia */ package caleidosystem.pruebas; import caleidosystem.proyecto.*; public class TestCoche2 { public static void main (String[] args) { Llanta auxLlanta1 = new Llanta(165.0, 14.0, 15.0); Llanta auxLlanta2 = new Llanta(165.0, 14.0, 15.0); Llanta auxLlanta3 = new Llanta(165.0, 14.0, 15.0); Llanta auxLlanta4 = new Llanta(165.0, 14.0, 15.0); Puerta auxPuerta1 = new Puerta(); Puerta auxPuerta2 = new Puerta(); Coche objetoCoche2 = new Coche(auxLlanta1, auxLlanta2, auxLlanta3, auxLlanta4, auxPuerta1, auxPuerta2); } }

Programación básica en C y Java (elaboró: José Luis López Goytia) 140 / 141

EJERCICIOS SUGERIDOS (Indice)

• Verifique que los programas se ejecuten correctamente en su entorno.

• Cambie los parámetros de coche a privado y confirme que el camino a) ya no puede manejarse.

• Programe el diagrama inicial referente a la tarjeta de débito y la cuenta de cheques. BIBLIOGRAFIA (Indice) Eckel, Bruce; Piensa en Java; Pearson – Prentice Hall; segunda edición; España, 2002; 906 págs. Fowler, Martin; UML Gota a gota; Pearson; México, 1999; 203 págs.

Programación básica en C y Java (elaboró: José Luis López Goytia) 141 / 141

BIBLIOGRAFÍA Aho, Alfred V.; SEIT, Ravi; Ullman, Jeffrey D. Compiladores. Principios, técnicas y herramientas; Addison Wesley Longman; México, 1998; 820 páginas. Deitel; C/C++ Cómo programar y Java; Pearson; México, 2004; 1113 págs.

Eckel, Bruce; Piensa en Java; Pearson – Prentice Hall; segunda edición; España, 2002; pág. 3.

Fowler, Martin; UML Gota a gota; Pearson; México, 1999. Horstmannn, Cay S.; Cornell, Gary; Java 2 Fundamentos; Prentice Hall; España, 2003. McConnell, Steve; Desarrollo y Gestión de Proyectos Informáticos; McGraw-Hill; España, 1998. 691 páginas. Meyer, Bertrand; Construcción de software Orientado a Objetos; Prentice-Hall; Segunda edición; Madrid, 1999; 1198 páginas. Schach, Stephen R.; Análisis y Diseño Orientado a Objetos con UML y el Proceso Unificado; McGrawHill; México, 2005. Schildt, Herbert; C. Manual de Bolsillo; McGraw-Hill; España, 1992; pág. 180.