Podríamos definir a un programa como un conjunto de instrucciones o acciones que tienen por objetivo realizar una tarea. Así por ejemplo hay un programa de actividades en homenaje al día de la Madre, por poner un ejemplo.
En informática un programa también se podría definir de forma similar. Conjunto de instrucciones que tienen como fin la realización de una tarea. Ahora bien, las tareas que se pueden realizar en un ordenador, unido a la velocidad con que trabaja el mismo hacen que la realización de un programa no sea tan sencillo. No obstante, haciendo un zoom del concepto, sigue siendo el mismo.
Hoy día, con la gran capacidad de procesamiento de los nano-chips unido a la gran diversidad de técnicas de programación hacen que realizar un programa no sea tan sencillo y sea mas bien una tarea de equipo.
Es muy difícil que una persona maneje todas las técnicas de programación existentes. Como programador no puedes aprenderte todos los lenguajes, es imposible, puedes conocer algunas técnicas que son comunes a todos los lenguajes, pero después debes definir el que deseas aprender y desarrollar y en el cual quieres perfeccionarte. Y eso que no mencionamos sobre los paradigmas. Es imposible tener éxito en todos. No te dan los tiempos y no puedes desenvolverte bien en todos. Esto sucede en todas las ramas de las ciencias. Por eso existen los especialistas, personas que profundizan el estudio en un área específica. En informática o programación pasa exactamente lo mismo, es imposible que una sola persona haga todo y de todo.
Tras esta breve digresión (que da para mucho más) de lo principal volvemos a lo nuestro, básicamente un programa necesita de datos, la materia prima con que trabaja, procesa esos datos y devuelve el resultado del procesamiento de esos datos.
La materia prima son muy diversos, las operaciones a efectuar con esos datos también y, por lo tanto, el resultado.
Vamos a analizar un programa muy simple que puede ser el de sumar dos números enteros.
// sum.cpp
#include <iostream>
int suma(int a, int b);
int main() {
int a, b;
std::cout << "Hola, Mundo!, este es mi primer programa." << std::endl;
std::cout << "Ingrese un entero: " ;
std::cin >> a;
std::cout << "Ingrese otro entero: ";
std::cin >> b;
std::cout << "La suma es: " << suma(a,b) << "\n";
return 0;
}
int suma(int a, int b) {
return a+b;
}
/* comando de compilación en g++
$ g++ -o sum sum.cpp
*/
La primera línea "#include <iostream>" hace que esté disponible las utilidades de esta librería. En nuestro programa se utilizará las funciones de entrada y salida.
La porción de código; int suma(int a, int b); es la declaración de una función que retorna un número entero y que acepta o requiere de dos parámetros, también enteros a y b.
Una declaración como ésta cumple la función de avisar al compilador que hay una función (o una variable) que está definido en alguna parte y que tiene este nombre y ésta estructura. La definición de la función puede estar al final del mismo archivo que contiene a la función principal o, inclusive en otro archivo. Esta instrucción se conoce como prototipo de la función, porque muestra su estructura, muestra el tipo del valor de retorno así como el o los tipos y, a veces, los nombres de sus parámetros.
La linea que contiene a: "int main() {" es la entrada al programa. Todo programa tiene una función principal llamada main. Esta función retorna un valor entero y, de momento no acepta ningún parámetro, pero puede hacerlo. La llave "{" abre un conjunto de instrucciones que se toma como una estructura compuesta.
Para que se pueda entender, podemos escribirlo así de simple:
int main(){
...
return 0;
}
El cero es el valor de retorno de la función. Este valor puede ser evaluado por el Sistema Operativo para determinar si el programa se ha ejecutado correctamente. La instrucción int a, b; declara (y define) dos variables de tipo entero. En este caso, se reserva memoria para contener dos valores enteros, pero no se da un valor inicial. ¿Por qué se dice que también hay definición? Pues porque se reserva la memoria y se asocia una etiqueta (el nombre) a la dirección de la memoria reservada. Además, el tipo indica cómo debe interpretarse el contenido de ese lugar de la memoria.
Esta instrucción pudo haberse realizado así:
int a;
int b:
o bien,
int a=0;
int b=0;
En este último caso las instrucciones son, además de declaración y definición, también inicialización (porque se da un valor inicial) Las variables que no se inicializan contienen lo que se llama "basura informática". Son ceros y unos que están alojados allí producto de la utilización de esa zona de la memoria por otro programa y que no se utiliza.
Ahora bien ¿Puede haber solo declaración de una variable? Pues si, para ello es necesario agregar un modificador llamado "extern". Este modificador hace que lo que sigue a dicha instrucción sea un aviso al compilador de que existe un "tokens" o componente sintáctico (el nombre) que está definido en otro lugar (otro archivo) pero que no es necesario reservar memoria para su tratamiento.
La instrucción extern int a; no reserva memoria, solo avisa al compilador de que hay una variable entera llamada a.
Luego observamos la instrucción std::cout << "..."; Ésta permite que todo lo que pongamos entre las comillas aparezca en la pantalla (salvo algunas excepciones como veremos). El "cout" (console output) reemplaza al printf de C. El std indica que lo que sigue al :: está en la librería estándar. El :: se llama operador de resolución de ámbito. ¿Cómo se entiende esto? Pues, podría haber un objeto cout que esté por ejemplo en una hipotética librería mi_std. Si quisiera utilizar ese objeto en lugar del anterior, pondría mi_std::cout. De esta forma no hay colisión de nombres.
Hay dos formas de utilizar los objetos de una librería. Una de ellas es la que se utilizó en el ejemplo, por medio de operador de resolución de ámbito, la otra es utilizar la directiva using.
Estas dos formas pueden verse en los dos ejemplos siguientes.
// Utilizando el operador de resolución de ámbito.
#include <iostream>
int main() {
...
std::cout << "..." std::endl;
return 0;
}
// Utilizando la directiva using
#include <iostream>
using namespace std;
int main() {
...
cout << "..." << endl;
return 0;
}
Por último, el << es el operador de inserción en el flujo de salida, así se denomina al objeto cout. Estos conceptos lo ampliaremos cuando hayamos desarrollado otros conceptos relacionados con las clases.
Así como el objeto cout permite sacar contenidos por la pantalla, el objeto cin permite introducir información en el programa (generalmente a través del teclado) La instrucción std::cin >> a; podría interpretarse así: "aceptaré lo que hayas introducido y lo pondré en la variable entera a" siempre y cuando el datos introducido pueda evaluarse como entero.
La instrucción std::cout << "La suma es: " << suma(a,b) << "\n"; llama o invoca a la función suma y le pasa como datos una copia del contenido de las variables a y b. La función retorna el resultado de la operación y lo pone en el objeto cout para que pueda mostrarse en la pantalla.
Después de la llave que cierra la función principal main, está la definición de la función suma. Demás está decir que es de lo más básico. La idea es justamente hacerlo simple para entenderlo.
int suma(int a, int b){
return a+b;
}
El primer int indica que la función retornará un valor de tipo entero, suma es el nombre de la función y lo que figura entre paréntesis se llaman parámetros formales. Son variables que pertenecen a la función y se utilizan para guardar una copia de las variables que se pasan a través de los parámetros. El return a+b; realiza la suma y luego retorna la misma.
Ahora bien, ¿no era más conveniente realizar la suma dentro del main? En realidad si, para una operación tan simple como esta si. El objetivo fue aquí introducir algunos conceptos y algunas ideas que son muy utilizada en cualquier programa.
Invocar o llamar a una función es algo muy común. Supongamos que en lugar de sumar dos números necesitamos que nos brinde los datos estadísticos de una serie de números. Hacerlo a "mano" sería un despropósito. Imagine que una función o un conjunto de funciones nos pueda brindar todas las "medidas de tendencia central" y las "medidas de dispersión" de una serie. No sería más conveniente escribir esas funciones una sola vez y luego llamar o invocarlo pasándole los valores de la serie. Es algo muy lógico. No nos pondríamos a escribir las funciones todas las veces que necesitamos, lo haríamos una sola vez y, una ves que funciona lo dejamos disponible. Con esto se logra la re-utilización de código.
Otro concepto que aparece es la idea de programación modular. Un programa se divide en secciones más pequeñas tratando de que sea lo más simple posible. Las funciones son estas partes más pequeñas. Cada función puede estar definida en un archivo separado y ser invocado cuando se lo requiera. Una función no puede escribirse en dos archivos distintos.