Les traigo acá un breve y practico tutorial de como funciona y como usar el bucle FOR en c++. Incluye dos alternativas usado con iteradores. Espero que le guste y hasta la próxima entrega.

Estamos cercanos a los dias de la celebración de Pascuas, leyendo sobre como se implementa la fecha en que cae, se me ocurrió escribir el siguiente desafío.

El Computus es el cálculo de la fecha de Pascua. A principios del siglo IV había en la cristiandad una gran confusión sobre cuándo había de celebrarse la Pascua cristiana o de Pascua de Resurrección, con motivo del aniversario de la resurrección de Jesús de Nazaret. Habían surgido en aquel momento numerosas tendencias o grupos de practicantes que utilizaban cálculos propios. (Wikipedia: Calculo de Pascua)

Escribí mi versión en C++ para que sirva de guía y se animen a escribirlo en otros lenguajes o a mejorar este codigo.

 

:

Continuando con los tutoriales hoy le traigo un video de como usar la estructura de control de repetición por contador While.

Espero les guste, a continuación el video y el código.

 

 

Escribi un programa para que me sume todos los numeros naturales menores a N, siendo N ingresado por teclado, por ejemplo si ingresamos 4 calcula la suma de (1 + 2 + 3 +4 = 10). Pero resulta que cometi un error por lo que el programa devuelve mal el resultado.

El desafio consiste en encontrar el error en mi codigo para que el programa funcione correctamente.

 

Makefiles son una forma sencilla de organizar la compilación de código. Este tutorial es un muy simple ejemplo de lo que se puede hacer con “make”, pero pretende ser una guía de principiantes para que pueda crear rápida y fácilmente sus propios archivos make para pequeños proyectos.

Vamos a tomar el código de ejemplo del articulo anterior. Lo que representaría un típico programa principal, algo de código funcional en un archivo separado, y un archivo de inclusión, respectivamente.

 

 

Normalmente, se compilará esta colección de código ejecutando el siguiente comando:

Este comando compila los dos códigos fuente involucrados en la creación del binario ejecutable “main” el parámetro -I. le dice al compilador que los archivos de inclusión .hpp los tiene que buscar en el directorio actual “.”

Por desgracia, este enfoque de la compilación tiene dos problemas. En primer lugar, si se pierde el comando de compilación o se cambia de computadora tiene que volver a escribir desde cero el comando. En segundo lugar, si sólo está haciendo cambios a un archivo .cpp, recompilar todos los archivos de código fuente cada vez que necesita recompilar demanda mucho tiempo y es poco eficiente. Ambos problemas se puede solucionar mediante el uso de un archivo “Makefile” con las instrucciones necesarias para la generación del ejecutable.

El makefile más simple que se podría crear sería algo como:

 

Si pones estas regla en un fichero llamado Makefile o makefile  y ejecutas “make” en la línea de comandos se ejecutará el comando de compilación como esta escrito en el makefile.

Se pone luego del nombre del ejecutable que se generara el símbolo : seguido de los archivos de codigo fuente que son necesarios para su creación y en la linea siguiente el comando de compilación necesario. Es importante destacar que antes de la llamada al compilador en la segunda linea hay un “Tab

Con el fin de ser un poco más eficiente, vamos crear un nuevo archivos Makefile:

 

Ahora hemos definido algunas constantes CC y CFLAGS. Resulta que estos son constantes especiales que se usan para decirle a make como queremos compilar. En particular  CC es el macro que especifica el compilador que vamos a usar usar, y CFLAGS es la lista de las banderas a pasar al comando de compilación. Al poner los archivos de objetos – main.o y suma.o – en la lista de dependencias y en la regla, make sabe que debe compilar primero las versiones .cpp individualmente, y luego construir el ejecutable.

El uso de esta forma de makefile es suficiente para la mayoría de proyectos de pequeña escala. Sin embargo, hay una cosa que falta: la dependencia de los archivos de inclusión. Si se va a realizar un cambio en suma.hpp, por ejemplo, que make no vuelva a compilar los archivos .cpp. Con el fin de solucionar este problema, tenemos que decirle make que todos los archivos .cpp dependen de ciertos archivos .hpp. Podemos hacer esto escribiendo una regla simple y agregarlo al archivo MAKE.

 

Esta adición creamo primero la macro DEPS, que es el conjunto de archivos .hpp de los que  los archivos .cpp dependen. Entonces definimos una regla que se aplica a todos los archivos que terminan en el sufijo .o. La regla dice que el archivo .o depende de la versión .cpp del archivo y los archivos .hpp incluidos en la macro DEPS. La regla luego dice que para generar el archivo .o, make necesita compilar el archivo .cpp usando el compilador definido en la macro CC. La bandera -c dice que genere el archivo de objeto, -o $@ dice para ponga la salida de la compilación en el archivo con el nombre en el lado izquierdo de los :,  $< es el primer elemento de la lista de dependencias, y  la macro CFLAGS se define como lo hicimos anteriormente.

Bueno este es un simple tutorial con ejemplos de como usar la herramienta Make. Aun así apenas nos asomamos a ver todo el potencial que nos ofrece.

 

En nuestro articulo anterior Cómo organizar tu código fuente en C++  definíamos algunas pautas para organizar nuestro código en varios archivos a fin de mejorar su tratamiento. En este articulo vamos a ver como hacer esto con un ejemplo simple, tomemos para ello el siguiente ejemplo que suma dos números a través de una función:

Vamos a retirar la función suma a un nuevo archivo, para ello necesitamos crear en realidad dos nuevos archivos y modificar el original. Por una parte tendremos la implementación de la función suma en un nuevo archivo llamado en este caso suma.cpp:

Que simplemente contiene la implementación de la función suma, para poder incorporar esta implementación en otros códigos fuentes es preciso que creemos un nuevo archivo con la definición de la función, para hacerlo, creamos ahora un archivo llamado suma.hpp donde podemos observar que la h hace referencia a header.

Acá tenemos unicamente la definición de la función y un par de directivas de preprocesador, veamos de que se trata.

La primera parte se llama un guardia de cabecera o header guard en ingles, estas lineas impiden que un archivo de cabecera sea cargado mas de una vez mediante #include. Sirve para proyectos de software muy extensos especialmente.

La segunda parte es el contenido real del archivo .hpp, que debe ser las declaraciones de todas las funciones que queremos otros archivos puedan ver. Todos nuestros archivos de cabecera deben tener una extensión .hpp.

Finalmente el archivo principal main.cpp queda de la siguiente manera:

Observe que la segunda linea incluye las funciones definidas en suma.hpp que se implementan en suma.cpp. Ahora ya las podemos usar libremente y a discreción a lo largo de este código fuente.

Julio Cesar tenía la premisa de “Divide y Triunfaras”, y muy mal no le fue en sus conquistas. Vamos a ver como organizar nuestro código fuente dividiéndolo en fragmentos de código más fáciles y cómodos de manejar, vamos a aprender cómo hacerlo y bajo qué criterios.

Muchos programas simples se pueden escribir en un solo archivo fuente en C++, pero, cualquier proyecto serio va a necesitar dividir en varios archivos con el fin de ser más manejable.

Sin embargo, muchos programadores que recién comienzan no se dan cuenta de cuál es la importancia de esto, sobre todo porque algunos ya lo intentaron y se encontraron con tantos problemas que decidieron que no valía la pena el esfuerzo.

Este artículo intenta explicar por qué hacerlo y en un próximo artículo cómo hacerlo correctamente.

Voy a llamar a los archivos estándar de C ++ (por lo general con extensión .cpp) “archivos de codigo fuente”. Esto será para distinguirlos de los “archivos de cabecera” (por lo general con extensión .h o .hpp).

¿Por qué dividir el código en varios archivos?

La primera pregunta que algunos programadores novatos se hacen cuando ven un directorio lleno de archivos de código fuente es, “¿por qué no está todo en un solo archivo?”

La división de cualquier proyecto de tamaño razonable nos provee de algunas ventajas, las más significativas de las cuales son las siguientes:

  • Acelerar la compilación – la mayoría de los compiladores trabajan en un archivo a la vez. Así que si todos sus 10000 líneas de código se encuentra en un archivo, y cambian una línea, entonces usted tiene que recompilar 10000 líneas de código. Por otro lado, si sus 10000 líneas de código se distribuyen uniformemente a través de 10 archivos, a continuación, cambiar una línea única requerirá compilar solo 1.000 líneas de código. Las 9000 líneas en los otros 9 archivos no necesitarán volver a compilarse.
  • Aumentar organización – La división de su código a lo largo de líneas lógicas, será más fácil para usted (y los otros programadores del proyecto) para encontrar funciones, variables, declaraciones, etc.
  • Facilitar la reutilización de código – Si el código está cuidadosamente dividido en secciones que operan en gran medida de forma independiente el uno del otro, esto le permite utilizar ese código en otro proyecto, que le ahorra un montón de tiempo y trabajo en volver a escribir el código.
  • Compartir código entre los proyectos – El principio aquí es el mismo que con el tema reutilización. Al separar cuidadosamente código en determinados archivos, se hace posible que los múltiples proyectos que utilizan algunos de los mismos archivos de código sin duplicarlos. El beneficio de compartir un archivo de código entre los proyectos y no sólo utilizando la copia y pega es que cualquier corrección de errores realizados en ese archivo o archivos de un proyecto afectará el otro proyecto, por lo que ambos proyectos pueden estar seguros de utilizar la versión más reciente del código.
  • Dividir las responsabilidades de codificación entre los programadores – Para grandes proyectos, esta es quizás la principal razón para la separación de código en varios archivos. Sistemas de gestión de configuración y los sistemas de control de versiones como CVS o Git ayudarle con esto.

Ahora que ya estás convencido de que hay beneficios para la división de tu proyecto en varios archivos más pequeños. Así que, ¿cómo hacerlo? Aunque algunas de las decisiones que tomes serán razonablemente arbitrarias, hay algunas reglas básicas que debes seguir.

En primer lugar, mira cómo dividir el código en secciones. A menudo esto es mediante su división en subsistemas separados, o “módulos”, como el sonido, la música, gráficos, manejo de archivos, base de datos, etc.

Crea nuevos archivos con nombres significativos para saber de un vistazo qué tipo de código es el que contienen.

A veces es necesario que un módulo se divida en dos o más archivos, ya que podría tener sentido hacerlo por razones lógicas.

Una vez que haya dividirlo según este criterio los archivos de código fuente, el siguiente paso es considerar lo que va a entrar en los archivos de cabecera. Básicamente consiste en poner el código que suele estar en la parte superior del archivo de código fuente en un archivo de cabecera separado.

EL código que se pone  en un encabezado por lo general incluye algunos o todos de los siguientes:

  • definiciones de clases y struct
  • typedefs
  • prototipos de funciones
  • variables globales
  • constantes
  • macros #defined
  • directivas #pragma

Peligros potenciales

Las reglas dadas arriba son bastante generales y sólo sirven como punto de partida para la organización de su código. En casos sencillos, se puede seguir esas directrices. Sin embargo, hay algunos detalles más que se tienen que considerar.

En mi experiencia, hay cuatro errores básicos que las personas enfrentan cuando entran en el oscuro mundo de los archivos de cabecera definidos por el usuario.

  • Los archivos de código fuente ya no se compilan ya que no pueden encontrar las funciones o variables que necesitan.
  • Definiciones duplicadas en una clase o identificador se incluye dos veces en un archivo de origen.
  • Duplicar instancias de objetos dentro del código que compila bien. Este es un error que une, a menudo difícil de entender

Conclusión

Si se realiza correctamente, la organización de los archivos de esta manera puede acelerar su desarrollo sin perjudicar en absoluto o introducir algún problema adicional. A pesar de que parece que hay mucho que considerar cuando se hace así, con el tiempo se convierte en una práctica habitual.

Sólo recuerde estos puntos clave:

  • Divida el código siguiendo el criterio de identificar los modulos logicos
  • Use los archivos de .cpp para la implementación y los archivos .hpp para la interfaz

Boost es un conjunto de librerias de software libre y revisión por pares preparadas para extender las capacidades del lenguaje de programación C++. Su licencia, de tipo BSD, permite que sea utilizada en cualquier tipo de proyectos, ya sean comerciales o no.

Su diseño e implementación permiten que sea utilizada en un amplio espectro de aplicaciones y plataformas. Abarca desde bibliotecas de propósito general hasta abstracciones del sistema operativo. Con el objetivo de alcanzar el mayor rendimiento y flexibilidad se hace un uso intensivo de plantillas. Boost ha representado una fuente de trabajo e investigación en programación genérica y metaprogramación en C++.

Varios fundadores de Boost pertenecen al Comité ISO de Estándares C++. La próxima versión estándar de C++ incorporará varias de estas bibliotecas.

Vamos a hablar un poco de vectores e iteradores en C++. Como derivado de C es comun que muchos desarrolladores a pesar de conocerlos les cueste adaptarse al uso de iteradores.

Contenedores, los vectores:

Un contenedor de la STL es una clase genérica que puede instanciarse para representar diversos tipos de objetos. Esta clase incluye ciertas operaciones (muy básicas) sobre los objetos de su tipo;  estas operaciones están representadas por funciones-miembro, incluyendo constructores y funciones-operador, que son a su vez funciones genéricas.

De su propio nombre (“Containers”) podemos deducir que su misión principal es funcionar como estructuras de datos, y en este sentido podemos decir que entre sus funcionalidades más destacadas se encuentran la gestión del espacio de almacenamiento necesario lo que de por si es una gran ventaja ya que el programador no tiene que preocuparse de asignar o liberar memoria para los objetos creados.

Veamos uso de los contenedores mediante un sencillo ejemplo, si tenemos que manejar un conjunto de enteros, puede utilizarse una matriz de enteros, pero ya hemos señalado que esta estructura nos obliga a conocer de antemano la cantidad de datos a almacenar (el tamaño de la matriz).

Una alternativa es utilizar como “contenedor” para nuestros enteros una clase genérica de la STL denominada vector.

Como se puede observa en la linea 8 definimos un vector de tipo int al que llamamos enteros.

Teniendo ya el objeto disponible vamos a usar uno de sus métodos o funciones miembro “push_back” para ir cargando el vector con valores del tipo que fue definido.

Luego mediante cout podemos acceder a los valores almacenados en el vector de la misma manera que lo haríamos en un array, es decir a travez de su indice.

¿Sencillo no? Y lo mejor de todo es que nos despreocupamos completamente de la dimensión de la colección y el manejo de memoria.

Iteradores:

Pero vamos un poco mas alla con C++, veamos como podemos usar un iterador para recorrer nuestro vector.

El concepto de iterador es fundamental para entender las clases de contenedores y algoritmos asociados inclusos en la Librería Estándar de Plantillas de C++.   En realidad los algoritmos son funciones globales que aceptan iteradores como argumentos, y a través de ellos puedan operar sobre los elementos del contenedor.

Un iterador es una especie de puntero que es utilizado por un algoritmo para recorrer los elementos almacenados en un contenedor. Dado que los distintos algoritmos necesitan recorrer los contenedores de diversas maneras para realizar diversas operaciones, y los contenedores deben ser accedidos de formas distintas, existen diferentes tipos de iteradores. Cada contenedor de la Librería Estándar puede generar un iterador con funcionalidad adecuada a la técnica de almacenamiento que utiliza. Es precisamente el tipo de iterador requerido como argumento, lo que distingue qué algoritmos STL pueden ser utilizados con cada clase de contenedor. Por ejemplo, si un contenedor solo dispone de iteradores de acceso secuencial, no pueden utilizarse con algoritmos que exijan iteradores de acceso aleatorio.

Pero vamos a un ejemplo que es la mejor forma de entenderlos:

Acá incorporamos un iterador, en la linea 9 declaramos un iterador a un vector de enteros.

Mas abajo podemos observar que en la linea 13 apuntamos con el iterador al primer elemento-ítem de nuestro vector.

Luego en la linea 14, 15 y 16 podemos ver como accedemos los enteros almacenados en el vector mediante los iteradores, observe que para acceder al valor se usa “*” como lo hacemos con punteros.

Pongamos atención ahora a la construcción de las lineas 17-19, este es el uso común y adecuado que se hace de los iteradores para recorrer una colección, en este caso mediante “for” que es en esencia un iterador.

Observemos que es este ultimo ejemplo hemos utilizado los métodos .begin() u .end() para denotar los limites de acción de for. También debemos notar que usamos el operador de  auto-incremento ++ para el iterador.

Bueno queridos lecoter espero que les haya gustado.