jueves, 29 de octubre de 2009

Aprende a Programar: 1 - Conceptos básicos

Hice este manual para aprender a programar con C++ cuando estaba en la universidad, ahora lo publico en mi blog para que le pueda servir a quienes quieran iniciarse en la programación desde cero.

El compilador


Para hacer un programa, nosotros no podemos usar nuestro lenguaje para decirle al ordenador qué es lo que quermos que haga, ya que no nos entendería. Nuestro lenguaje es demasiado ambiguo.
Los ordenadores entienden un lenguaje muy distinto al nuestro, llamado "lenguaje máquina", cuyo "abecedario" está compuesto únicamente por ceros y unos. Por tanto hay un pequeño problema de "comunicacion".
Para solucionar este problema se han ido creando diferentes lenguajes más cercanos al nuestro, llamados lenguajes de alto nivel, de forma que nos resulte más fácil "decirle" al ordenador lo que queremos que haga. En C++, como en otros lenguajes, le "diremos" al ordenador lo que queremos que haga mediante instrucciones, de forma cada instrucción será una línea de texto acabada en punto y coma.

Una vez que hemos hecho un programa con un lenguaje de alto nivel (por ejemplo C ó C++) necesitamos a "alguien" que se encargue de traducir el programa a lenguaje máquina para que el ordenador lo entienda. Pues bien, esta tarea es la que realiza el compilador. Por tanto al acto de convertir el código (el algoritmo) en un programa ejecutable se le llama compilar. Si en el código del programa existe algún fallo de tipo sintáctico o mal uso de lenguaje que estemos manejando, el programa no se compilará y el compilador nos indicará los fallos que existen para que los arreglemos.

¿Qué necesito para empezar?

Para empezar necesitaremos básicamente un editor de textos donde escribir el código, y un compilador, eso es todo ;-) Existen editores de textos que colorean el código conforme vamos escribiendo para tenerlo más estructurado y que sea más comprensible.
Si vas a trabajar en GNU/Linux puedes usar cualquiera de los editores de texto existentes (Kate, Vim, Nano, Emacs, etc...) y usar el compilador g++ de GNU.
Existen "entornos de desarrollo", de forma que la edición del código y la compilación la haremos en el mismo entorno. Esto es recomendable si vas a hacer proyectos suficientemente grandes como para usar varios ficheros (cada fichero contiene código sólamente, se usan varios para tener el código más estructurado), de forma que facilita y acelera diversas tareas. En GNU/Linux hay muchos entornos de desarrollo, por ejemplo Anjuta.
Si vas a programar usando Microsoft Windows, existe un buen entorno de desarrollo llamado Devcpp (devc++), que incluye el editor de textos y el compilador en el mismo programa.

Si eliges programar en GNU/Linux con G++, el procedimiento a seguir sería el siguiente: Crear un archivo con tu editor favorito, con extensión *.cc ó *.cpp. Escribir el código necesario. Y por último, ejecutar en la consola: "g++ nombre_codigo.cc" (sin las comillas evidentemente). Con lo cual el compilador G++ convierte el código en un programa ejecutable, el cual podremos ejecutar escribiendo: "./nombre_ejecutable".

Si eliges programar con un entorno de desarollo, tendrás que crear un nuevo proyecto de un programa de consola. Escribir el código necesario, seleccionar la opción "compilar" del entorno que estés usando. Y finalmente seleccionar la opción "ejecutar" para ver el resultado del programa.

Las librerias

Mediante código vamos a decirle al ordenador lo que queremos que haga mediante instrucciones. Pues bien, algunas instrucciones están almacenadas en lo que se denominan librerías que necesitaremos incluir en nuestro fichero de código.
Explicándolo de una forma algo vulgar pero sencilla de entender; imaginemos que tú eres un programa, y el usuario te da la instrucción "RESOLVER TAL PROBLEMA DE FISICA CUÁNTICA". Pues bien, si no sabes física cuántica, antes tendrías que leerte algunos libros, ¿verdad?. Pues digamos que cuando escribes un programa, has de decirle a éste los "libros" que debe "leerse" para poder realizar las instrucciones que tú le digas.
Existen muchas librerías para C++, incluso cuando aprendas a programar en C++ tú mismo podrás crear tus propias librerías.
Para incluir una librería en nuestro programa (dicho a nuestro modo: para que "el programa se lea un libro") debemos indicarlo al principio del código. Por ejemplo con:
#INCLUDE <iostream>

indicaríamos al programa que incluya la librería iostream, librería elemental para realizar operaciones de entrada/salida que veremos y explicaremos más adelante.

Los namespaces

El concepto de 'namespace' o espacio de nombres es muy sencillo. Simplemente son contenedores de librerías, es decir, que las librerías están agrupadas en namespaces, así evitamos conflictos si existen diferentes librerías con el mismo nombre. Para usar un namespace, en nuestro programa, lo indicaremos después de los 'includes':
#include <iostream>
#include <string>

using namespace std;

En este manual no profundizaremos en el tema de las librerías y los espacios de nombres, ya que nuestro objetivo es que te inicies en la programación en general, aunque para ello usemos un lenguaje en concreto.

Comentarios

Cuando escribes el código de un programa, es conveniente que vayas realizando algunas notas en éste para que cuando, al cabo de un tiempo, veas el código entiendas qué estas haciendo en cada momento.
Quizá ahora no le veas mucho sentido a esto, pero cuando empieces a hacer tus primeros programas irás pensando en anotar cosas.
Una vez escribiendo código, un comentario se escribe así:
//Esto es un comentario de una sola línea

/*Esto es un comentario de
varias líneas*/

Con la primera forma, mediante "//" estamos indicándole al compilador que no haga caso de lo que se encuentre después de encontrar las dos barras.
Con la segunda forma, estamos diciéndole al compilador que ignore lo que se encuentre desde que aparece "/*" hasta que se encuentra "*/". Así que esos comentarios aparecerán en el código, pero no afectarán para nada al programa.

Aprende a Programar: 2 - Mi primer programa

Llegados a este punto vas a escribir tu primer programa. Este programa sólo muestra por la pantalla la frase "Hola mundo", es por donde todos hemos empezado. Copia el siguiente código, compílalo y ejecútalo tal y como se ha explicado en el tema anterior:
#include <iostream>
using namespace std;

int main()
{
    cout << "Hola Mundo" << endl;
    system("pause");
}

Si todo ha ido bien, habrás visto la frase "Hola mundo" por tu pantalla, pero quizá haya cosas del código que no entiendas, vamos a explicarlas.
Las dos primeras líneas deberías saber qué significan, si no lo sabes aún deberías volver a ver el tema anterior.
int main() significa que lo que vamos a escribir dentro de este bloque (delimitado por llaves) va a ser el programa principal. Más adelante veremos que podemos escribir código fuera del programa principal, de forma que será llamado desde éste (lo veremos en el tema de las funciones).
cout es un objeto conectado al dispositivo de salida estándar, es decir, tu monitor. Gracias a él y al operador de flujo << podemos mostrar datos por pantalla. endl inserta un salto de línea (retorno de carro).
system("pause") simplemente realiza una pausa hasta que el usuario pulsa una tecla, así puedes ver el resultado del programa.

MI SEGUNDO PROGRAMA

Igual que existe un objeto para la salida estándar, también existe un objeto para la entrada estándar, de forma que el programa leerá los datos que tú introduzcas con tu teclado.
Éste objeto es cin junto con el operador de flujo >>.
Vamos crear nuestro segundo programa para mostrar el uso de cin.
#include <iostream>
using namespace std;

int main()
{
    int numero;
    cout << "Introduce un numero" << endl;
    cin >> numero;
    cout << "Has introducido el numero " << numero << endl;
    system("pause");
}

Con int numero creamos una variable de tipo "interger" (número entero). Luego pedimos al usuario que introduzca un número que insertaremos en la variable que hemos creado. Por último mostramos el número que se ha introducido por pantalla. ¿Sencillo verdad?... Mmmm creo que todavía no te ha quedado claro esto de la "variable", vamos a explicarlo más en profundidad.

LAS VARIABLES Y LAS CONSTANTES

Las variables son contenedores de información, en cada momento pueden tener un valor u otro, en función del que se le haya asignado.
Hay variables de distintos tipos, esto es, el conjunto de valores que se le puede asignar a una variable, hay variables que sirven para guardar números, variables que sirven para guardar letras, etc...

En el ejemplo anterior hemos usado la variable "numero" que es de tipo entero, es decir, sólo puede almacenar números enteros. Esa variable no es capaz de guardar el valor de un número decimal, o un carácter, o una cadena de caracteres, ha sido creada para guardar en memoria simplemente números.
Los tipos de variables los veremos en el capítulo siguiente.

Antes de usar una variable, hay que decirle al compilador que la vamos a usar, esto es, declararla. Para declarar una variable lo único que tenemos que hacer es escribir el tipo, seguido del nombre (seguido de un igual y el valor si se desea) y, para finalizar la sentencia, punto y coma.

Puede que en algún momento de nuestro programa vayamos a usar una variable que siempre va a contener el mismo valor. Para este tipo de "variables" usaremos las constantes, así le diremos al compilador que a esa "variable" nunca le voy a cambiar el valor.

Los nombres de las variables han de contener sólo letras, números y el carácter subrayado '_', y el primer carácter no puede ser un número.
El compilador distingue entre mayúsculas y minúsculas, por tanto la variable "numero", es distinta a la variable "Numero" ó "NUMERO".
Para nombrar las variables los programadores tenemos unas pautas que seguimos para poder diferenciar unos objetos de otros. Las variables suelen comenzar por letra minúscula, las funciones por letra mayúscula, los nombres de las constantes empiezan por la letra k y cualquier identificador que tenga más de una palabra usará la letra mayúscula al inicio de cada una de ellas, evitando el uso del carácter '_' (por ejmplo: miVariableDeEjemplo).
Sobra decir que el nombre de las variables ha de ser suficientemente descriptivo a la vez que no excesivamente largo.

Ejemplos válidos:
int i;
int j=0;
string cadena;
const float kpi=3.1415;
const string kcadenaDeCaracteres;
float _numero;
string una_cadena;
int numero,otroNumero; //Así puedes declarar varias variables en una línea

Ejemplos incorrectos:
int int; //Una variable no puede llamarse como una palabra reservada
const kvariable; //¿Y el tipo?
string 1cadenaDeCaracteres;
float un numero decimal;
string alumn@; //SÓLO letras, números y el carácter subrayado

Aprende a Programar: 3 - Tipos de datos

Como hemos dicho en el tema anterior, existen varios tipos de variables, cada uno es capaz de almacenar los valores de un dominio en concreto. En esta unidad didáctica veremos los tipos de datos básicos.

* Entero: int. Representa cantidades enteras (positivas o negativas), en memoria ocupa 2 bytes (16 bits).
* Carácter: char. Representa un caracter ASCII, el compilador lo trata como un entero de 8 bits.
* Cadena: string. No es un tipo básico (es derivado del char), pero es de gran utilidad. Representa una cadena de caracteres, incluidos espacios. El tamaño que ocupa en memoria es variable.
* Coma flotante: float. Para rangos numéricos mayores que el tipo entero, y además con parte fraccionaria. Ocupa cuatro bytes (32 bits).
* Coma flotante de doble precisión: double. Es como el float, pero con mayor precisión (almacena números más largos). Ocupa 8 bytes.
* Lógico: bool. Sólo toma los valores true y false. C++ tiene una peculiaridad, y es que toma el valor 0 como falso, y cualquier otro como verdader.
* Vacío: void. Este tipo lo usaremos en el tema de las funciones.

Es importante distinguir entre los distintos tipos de datos. Una de las cuestiones que le cuesta entender a los que se inician en la programación, es la diferencia entre el caracter '5', y el número 5. Son dos tipos de datos distintos. Nosotros tenemos asociado el caracter '5' con el valor cinco, pero son cosas diferentes, uno es el signo y el otro es el significado. Es evidente que necesitemos un signo para representar ese significado, para representar el valor 5 usamos el símbolo '5'. Así que cuando necesitemos que nuestro programa tenga que mostrar un mensaje en pantalla indicando una cifra numérica, esta será representada por sus caracteres correspondientes, pero cuando necesitemos que el programa opere con una cantidad numérica, indicaremos el valor correspondiente, mediante números.
El compilador trata a una variable de tipo char o string como caracteres, de forma que si a una variable de estos tipos le asignas el caracter '5', el compilador la trata como una tecla de tu teclado simplemente, no como el valor 5. Más adelante veremos la conversión de tipos, de forma que es posible convertir variables de un tipo en otro.

OPERADORES

Un operador es un símbolo que nos permite realizar operaciones sobre los datos, que serán los operandos.

OPERADOR ASIGNACIÓN

Usamos el operador asignación para almacenar datos en nuestras variables, de la siguiente forma: nombreVariable=expresion;. La asignación se efectúa de derecha a izquierda, evaluando la expresión y asignando su valor al identificador de la variable.
Si los tipos de la expresión y de la variable no coinciden, el compilador genera un cambio automático de tipo de la expresión, al tipo de la variable.
Ejemplos: a=b+2; c=3*6; m=7;
C++ permite realizar varias asignaciones en la misma sentencia, de forma que las asignaciones se efectúan de derecha a izquierda (realizando las conversiones de tipo necesarias, como se ha indicado antes).
Ejemplo:

int a;
float x,y;
x=a=y=3.5;

Ahora analicemos lo que ha pasado: primero se ha asignado el valor 3.5 a la variable y. Luego se asigna el valor de y (3.5) a la varible a, pero, ¡atención!, a es de tipo int, por tanto el compilador hace una conversión de tipos, convierte el valor 3.5 en un valor entero, 3. Por tanto ahora a vale 3, y a x se le asigna el valor de a, 3.0. Por tanto al final queda:
y=3.5, a=3, x=3.0

Tenemos variantes del operador asignación que nos serán útiles para ahorrar tiempo y espacio. Veamos unos ejemplos:

x+=10; equivale a x=x+10;
x-=10; equivale a x=x-10;
Lo mismo ocurre con *= /= %=

OPERADORES ARITMÉTICOS

Sirven para realizar operaciones matemáticas entre los datos.
Existen operadores binarios (actúan sobre dos objetos) y monarios (sobre un objeto).

Binarios:

* + suma
* - resta
* * multiplicación
* / división
* % resto de la división entera

Hay que resaltar que el operador / devuelve un resultado entero en caso de que los operandos sean del tipo int.
Ejemplo:

int a;
float x;
a=7/5; //a vale 1
x=7.0/5; //x vale 1.4

Monarios:

* ++ Incrementa la variable en una unidad.
* -- Decrementa la variable en una unidad.

Los operadores de incremento y decremento se pueden usar a la derecha o a la izquierda de la variable (a++; o ++a;). Pero hay que tener en cuenta que si el operador se usa a la izquierda, la variable se incrementa o decrementa antes de utilizarla. Mientras que el si el operador se usa a la derecha, la variable cambia su valor después de usarla.
Ejemplo:

int x,n;
x=5;
n=++x; //n=6 y x=6
n=x++; //Después de esta asignación x valdrá 7 pero n sigue valiendo 6

Es IMPORTANTE señalar que cuanto se declara una variable no tiene un valor asignado, y por tanto sería un error realizar un incremento o decremento sobre una de estas variables, ya que no contiene ningun valor para incrementar o decrementar. Antes de aplicar un operador monario habría que inicializar la variable (darle algún valor).

OPERADORES RELACIONALES

Sirven para comparar los valores de dos expresiones y devuelven uno de los dos valores posibles: true o false.

* < Menor que
* > Mayor que
* <= Menor o igual
* >= Mayor o igual
* == Igual que
* != Distinto de

Uno de los errores más comunes es C++, es confundir el operador '=' con el operador '==', de forma que a veces se llega a resultados erróneos.
Por ejemplo:

int a=3;
a==3 //Devuelve verdadero (true)
a<10 //Devuelve verdadero
a>5 //Devuelve falso
a<=2 //Devuelve falso
a>=3 //Devuelve verdadero
a=5 //¿Qué crees que devolverá?

Pues devuelve VERDADERO, porque no estamos comparando si a es igual a 5, sino que estamos asignando 5 a la variable a, por tanto la expresión vale 5, y como hemos dicho, ¡¡en C++ lo que no es 0 es verdadero!!.

OPERADORES LÓGICOS

Permiten interconectar expresiones relacionales:

* && "y"
* || "o"
* ! "no"

Supngo que sabes algo de lógica, pero por sea caso vamos aponer unos ejemplos:
bool cierto=true,falso=false;
int n=3;
string cadena="hola";

cierto && cierto //Devuelve true
cierto && falso //Devuelve false
cierto || falso //true
(cierto || falso) && falso //false
cierto || (falso && falso) //true
!cierto //true
!cierto && !falso //falso
!cierto && cierto //falso
!cierto || !falso //true
!falso && cierto //true
!(cierto && falso) //true
n==3 && n<10 //true
n==3 && n<2 //false
n<3 || n==3 //true
n!=10 || n==20//true

CONVERSIÓN DE TIPOS

A veces nos interesa que una variable o expresión se comporte como si fuese de un tipo distinto al que es. Esto se puede conseguir colcando entre paréntesis el tipo de dato deseado delaten de la variable o expresión. Esto se llama conversión de tipo o cast.
El cambio afecta al valor resultante, pero no afecta a los datos en si.
Ejemplo:

int a,b;
float d;
a=7;
b=5;
d=a/b; //d vale 1
d=(float)a/b //d=1.4 y a sigue siendo entero
a=(int)d; //a=1 y d=1.4

Aprende a programar: 4 - Estructuras de Control

Las estructuras de control nos permiten definir el flujo de nuestro programa, nos permiten indicar qué sentencias se ejecutarán en función de que se cumplan una serie de condiciones. También nos permitirán repetir la ejecución de una o varias sentencias un número determinado de veces. Para el primer caso usamos las estructuras de selección, y para el segundo las estructuras de repetición.

Cada sentencia que se usa en C++ está separada de la otra por ';'. En algunos casos nos interesa agrupar sentencias, pues bien, el bolque de sentencias se define mediante llaves '{' y '}'. Todas las sentencias que estén dentro del mismo bloque se ejecutarán el mismo número de veces.

ESTRUCTURAS DE SELECCIÓN

El formato es el siguiente:
if (expresion)
    bloque de sentencias 1;
else
    bloque de sentencias 2;

Esta sentencia evalúa la expresión booleana que hay entre paréntesis, y si el resultado es cierto se ejecutarán las sentencias del bloque 1 y en caso contraro se ejecutarán las del bloque 2.
Ejemplo:
#include <iostream>
using namespace std;

int main()
{
    int num;
    cout << "Introduce un numero" << endl;
    cin >> num;

    if(num%2==0)
        cout << "El numero es par" << endl;
    else
        cout << "El numero es impar" << endl;

    system("pause");
}

El bloque else es opcional. Si en caso de que no se cumpla la condición no quieres hacer nada, no tienes porque poner el bloque else. Recuerda que si quisieras ejecutar varias sentencias seguidas, tendrían que estar englobadas con llaves.
Ejemplo:
#include <iostream>
using namespace std;

int main()
{
    int num;
    cout << "Introduce un numero" << endl;
    cin >> num;

    if(num%2==0)
        cout << "El numero es par" << endl;
    else {
        cout << "El numero es impar" << endl;
        cout << "O sea, que no es par"<< endl;
    }

    system("pause");
}

Selección Múltiple

Se usa cuando se dispone de una expresión que al evaluarla puede dar varios resultados.
El formato es el siguiente:
switch (expresion)
{
    case valor1:
        sentencia 1;
        sentencia 2;
        break;
    case valor2:
        sentencia;
        break;
    default:
        sentencia;
}

Las etiquetas case no pueden estar repetidas y deben ser del mismo tipo que el selector.
Si ninguno de los valores de las etiquetas case coincide con el valor del selector, se pasará a la siguiente instrucción que haya después de switch, a menos que se haya usado la opción default, que será la que se ejecuta en caso de que el valor de la expresión no coincida con ningún valor de los case.
Ejemplo:
#include <iostream>
using namespace std;

int main()
{
    int num;
    cout << "Introduce un numero del 1 al 3" << endl;
    cin >> num;

    switch (num) {
        case 1:
            cout << "uno" << endl;
            cout << "que no pare ninguno" << endl;
            break;
        case 2:
            cout << "dos" << endl;
            cout << "nos movemos los dos" << endl;
            break;
        case 3:
            cout << "tres" << endl;
            cout << "voy del reves" << endl;
            break;
        default:
            cout << "Has introducido un numero menor que 1 o mayor que 3" << endl;
    }

    system("pause");
}

¡¡ACUÉRDATE DE PONER EL BREAK!! Es importante escribir el break después de cada case ya que si no se escribiera break, una vez encontrada la etiqueta case correspondiente, se ejecutaría la sentencia asociada a dicha etiqueta y todas las sentencias que hay a continuación hasta el final del switch o encontrar una sentencia break.

ESTRUCTURAS DE REPETICIÓN

Volvamos al ejemplo anterior, el cual nos indicaba si un número era para o impar. Vamos a hora a modificarlo para que nos obligue a introducir un número mayor que cero.
#include <iostream>
using namespace std;

int main()
{
    int num;
    cout << "Introduce un numero positivo" << endl;
    cin >> num;

    if (num<=0) {
        cout << "ERROR" << endl;
        cout << "Introduce un numero positivo" << endl;
        cin >> num;
    }

    if(num%2==0)
        cout << "Es par" << endl;
    else
        cout << "Es impar" << endl;

    system("pause");
}

Mediante esta solución sólo garantizamos que si el usuario se equivoca una vez se le permita de nuevo la entrada de datos, pero si el usuario se equivoca por segunda vez, no tendrá la oportunidad para rectificar y la comparación se hará con un número menor o igual a cero. Por tanto, necesitamos otro tipo de estructura para repetir una serie de sentencias un determinado número de veces.

Con condicion inicial: WHILE

Se emplea para genarar bucles (repeticiones) mientras la sentencia de la expresión sea cierta.
Forma general:
while (condicion)
    sentencia;

En caso de haber varias sentencias, se agruparán mediante llaves como ya sabemos.

Tiene que haber dentro del bucle alguna sentencia que altere el valor de la expresion, sino se entraría en un bucle infinito.

Ejemplo (solución al problema anterior):
#include <iostream>
using namespace std;

int main()
{
    int num;
    cout << "Introduce un numero positivo" << endl;
    cin >> num;

    while (num<=0) {
        cout << "ERROR" << endl;
        cout << "Introduce un numero positivo" << endl;
        cin >> num;
    }

    if(num%2==0)
        cout << "Es par" << endl;
    else
        cout << "Es impar" << endl;

    system("pause");
}

Podemos hacer cosas interesantes como mostrar la tabla de multiplicar de cualquier numero:
#include <iostream>
using namespace std;

int main()
{
    const int kveces=10;
    int contador;
    int n;

    cout << "Introduce un numero" << endl;
    cin >> n;

    contador=0;
    while(contador<=kveces)
    {
        cout << n << " x " << contador << " = " << n*contador << endl;
        contador++;
    }

    system("pause");
}

Con condicion al final: DO WHILE

Al igual que en la estructura anterior, el bucle se ejecutará meintras las expresión sea verdadera.
do
    sentencias;
while (expresion);

La diferencia entre while y do-while es que en el segundo se comprueba la condición de continuación del bucle al final, esto significa que siempre se ejecutará por lo menos una vez el cuerpo del bucle.
Un uso muy común de este tipo de bucles es el de realizar filtros para garantizar que el usuario introduzca información correctamente, según los valores permitidos.

Para usar todo lo que llevamos aprendido hasta ahora, vamos a hacer el pequeño juego de escribir un número entre 1 y 100, y luego que otra persona tenga que adivinarlo en menos de 5 intentos.
#include <iostream>
using namespace std;

int main()
{
    int intentos,secreto,numero,i;
    const int klineas=24; //Líneas de la pantalla
    const int kMaxIntentos=5;

    do {
        cout << "Escribe el numero a adivinar entre 1 y 100: ";
        cin >> secreto;
        cout << endl;
    }
    while (secreto<1 || secreto>100);

    system("pause");

    //Ahora borraremos la pantalla
    i=0;
    while (i<klineas) {
        cout << endl;
        i++;
    }

    intentos=0;
    numero=0;

    while(numero!=secreto && intentos<kMaxIntentos) {
        cout << "Adivina el numero: ";
        cin >> numero;

        if(secreto>numero)
            cout << "El numero que buscas es mayor" << endl;
        else
        if (secreto<numero)
            cout << "El numero que buscas es menor" << endl;

        intentos++;
    }

    if (numero==secreto)
        cout << "MUY BIEN, SOLO HAS NECESITADO "<<intentos<<" INTENTOS." << endl;
    else
        cout << "HAS HECHO "<<kMaxIntentos<< " INTENTOS Y NO LO HAS ADIVINADO. ERA EL " << secreto << endl;

    system("pause");
}

Con contador: FOR

Es equivalente a un bucle con condicion inicial, pero genera un código más compacto. Se suele uasr cuando la finalización del bucle depende del valor de una variable que se decremente o incrementa en una cantidad fija (no tiene porque ser una unidad). No obstante, se puede usar para muchas posibilidades.
El formato general es:
for (e1;e2;e3)
    sentencias;

* e1 es una o varias sentencias que se ejecutan una sola vez antes de comenzar el bucle.
* e2 es una expresión lógica que mientras se evalúe a cierto se ejecutará el bucle.
* e3 es una o varias sentencias que se ejecutan en cada iteración después de ejecutar las sentencias del cuerpo del bucle.

Una estructura FOR es equivalente a una do while de la siguiente forma:
e1;
while(e2)
{
    sentencias;
    e3;
}

Por ejemplo, en el ejemplo anterior, podríamos haber usado un bucle FOR para borrar la pantalla en vez del WHILE:
for (i=0;i<klineas;i++)
    cout << endl;

Como vemos, las instrucciones para borrar la pantallan pasan de ocupar 4 líneas, a sólo 2.

Aprende a programar: 5 - Programación Modular

A medida que el tamaño de los programas se hace más grande, incrementa la dificultad de comprenderlos y también se incrementa el número de tareas repetidas que deben ser escritas.
Mediante las funciones podemos escribir el código que se repite varias veces simplemente una vez (crear una función), y después simplemente "decir" queremos usarlo (llamar a una función). Así, a parte de aumentar la legibilidad del programa y reducir el tamaño, nos da la oportunidad de dividir el programa en partes o módulos, de forma que podemos dividir un programa complejo en varias partes más sencillas (¡Divide y vencerás!).

Vamos a ver un ejemplo para comprender mejor lo que es la modularidad. Vamos a construír un algoritmo, no de un programa ni en lenguaje C++, sino de una situación real en un lenguaje inventado por nosotros:
Algoritmo: RevisarCoche
{
    poner Gasolina;
    comprobar Aceite;
    verificar Luces Repuesto;
}

Mediante esta abstracción hemos creado un algoritmo sencillo, formado por otras subtareas.
Ahora definiremos las otras subtareas
Algoritmo: PonerGasolina
{
    marcar Cantidad en Surtidor;
    echar Gasolina;
    pagar;
}

Algoritmo: ComprobarAceite
{
    sacar la varilla;
    mirar la varilla;
    mientras (nivel sea menor que el máximo) {
        poner la varilla;
        añadir aceite;
        sacar la varilla;
        mirar la varilla;
    }
}

Algoritmo: VerificarLucesRepuesto
{
    si hay caja de luces de repuesto
        comprobar juego de luces
        sino
        comprobar juego completo
}

Si tuviéramos que explicarle a alguien como realizar la tarea de revisar el coche, le diríamos: primero pon gasolina, luego comprueba el aceite y luego las luces. Y, luego, podríamos concretarle cualquiera de estos tres puntos. Evidentemente no le diríamos primero marca la cantidad en el surtidor, luego echa gasolina, luego paga, luego saca la varilla, luego mira la varilla, etc...

De esta manera, al hacer este otro algoritmo:
Algoritmo:ComprobarGasolina
{
    si nivelGasolina<=NivelReserva
        PonerGasolina;
}

sólo tenemos que llamar la función PonerGasolina y no volver a describir todo el proceso de marcar cantidad en surtiror, echar gasolina, etc...

Por si aún no lo has entendido te lo describiré de otra forma:
Supongamos que tienes que ir a comprar el pan, luego ir a casa de tu amigo Pepe a pedirle unos apuntes y volver a casa. En tu cabeza estás pensando que tienes que realizar estas tres tareas, y sabes que cada tarea conlleva otras subtareas. Por ejemplo, comprar el pan conlleva ir a la panadería, pedir el pan, calcular las monedas que le das al dependiente, dar monedas, recoger cambio, etc... a su vez, la tarea de ir a la panadería conlleva calcular una ruta dependiendo del sitio donde estés, mirar para cruzar, cruzar en caso de que no vengan coches y un largo etc...
Pues bien, en tu cabeza tienes el subalgoritmo de cruzar la calle, el algoritmo de calcular la ruta más corta, el de dar monedas, etc... de forma que si hicieras una lista de las cosas que tengas que hacer harías:

* Comprar el Pan
* Ir a casa de Pepe
* Volver a casa

Y efectivamente no escribirías:

* Coger llaves
* Abrir puerta de casa
* Cerrar puerta de casa
* Mirar la calle
* Cruzar cuando no venga ningún coche
* etc...

Pues lo mismo pasa en la programación.
¿Entiendes el sentido de la programación modular? Espero que si...

FUNCIONES

Formato de funciones en C++:
TipoDeDatos NombreFunción(parámetro1, parámetro2, ..., parámetroN)
{
    sentencias; //(cuerpo de la funcion)
    return expresion; //Valor devuelto
}

Una función es una operación que recibe uno o más valores llamados argumentos o parámetros, de forma que produce un resultado (valor de retorno).
En C++ los subprogramas se llaman funciones.

TipoDeDatos Es el tipo de datos que devuelve la función, en caso de que la función no devuelva nada, será de tipo void.
NombreFuncion Representa al nombre con el que se va a identificar a la función. Es aconsejale utilizar un verbo en infinitivo que describa la acción del mismo y que empiece por mayúscula para diferenciarlas de las variables.
Parámetros Los parámetros son variables que el programa principal "pasa" a la función para que ésta haga las operaciones necesarias. Una función puede no tener parámetros.

La forma estándar de llamar a una función en caso de que devuelva algún parámetro es:
menor=Menor(a,b); o fecha=DiaDeHoy();
O en caso de que no devuelva valor alguno:
Sumar(a,b); o VerInstrucciones();

Por ejemplo, podríamos tener un programa que borre la pantalla varias veces, podríamos crear una función para hacer el código más sencillo, de forma que el programa quedaría así:
#include <iostream>
using namespace std;

void BorrarPantalla()
{
    for (int i=0;i<24;i++)
    cout << endl;
}

int main()
{
    cout << "Vamos a borrar la pantalla" << endl;
    system("pause");
    BorrarPantalla();
    cout << "Vamos a volver a borrar la pantalla" << endl;
    system("pause");
    BorrarPantalla();
    system("pause");
}

Lo siguiente es un ejemplo de una función con parámetros de entrada (parámetros que el programa principal pasa a la función) y de salida (valor que devuelve la función);
#include < iostream >
using namespace std;

bool EsBisiesto(int anyo)
{
    if(anyo%4==0 && anyo%100!=0 || anyo%400==0)
        return true;
    else
        return false;
}


int main()
{
    int unAnyo;
    bool bisiesto;

    cout << "Introduce un anyo" << endl;
    cin >> unAnyo;

    bisiesto=EsBisiesto(unAnyo);

    if(bisiesto==true)
        cout << "Es bisiesto" << endl;
    else
        cout << "No es bisiesto" << endl;

    system("pause");
}

También sería válida la siguiente forma de usar la función:
if(EsBisiesto(unAnyo))
    cout << "Es bisiesto" << endl;
else
    cout << "No es bisiesto" << endl;

Parámetros por valor y por referencia

Cuando llamas a la función void Funcion(paramFunc,paramFunc2) mediante la forma establecida desde el programa principal (o desde otra función) Funcion(paramMain,paramMain2) lo pasa con los parámetros es que paramFunc y paramFunc2 son una copia de paramMain y paramMain2 respectivamente. De forma que si en la función modificamos los valores de paramFunc y paramFunc2 no estaremos modificando los valores de paramMain y paramMain2. A veces es interesante que si que se modifiquen los parámetros paramMain y paramMain2, así la función puede devolver varios parámetros.
Cuando los parámetros originales no se modifican, se dice que se pasan los parámetros por valor, mientras que si los originales SI que modifican se dice que los parámetros se pasan por referencia.

La definición y sintaxis de uso de parámetros por referencia es igual que la de parámetros por valor exceptuando que en la definición de la cabecera de la función y en sus propios prototipos se deberá anteponer al nombre del parámetro el carácter '&'.

Veamos algunos ejemplos:
#include <iostream>
using namespace std;

void PasarPorValor(int a, int b)
{
    a=a+b;
    b=a;
}
int main()
{
    int numero, numero2;
    numero=10;
    numero2=20;
    PasarPorValor(numero,numero2);
    cout << "numero=" << numero << ", numero2=" << numero2 << endl;
    //numero=10, numero2=20   
    system("pause");
}

Vemos que, aunque en la función modifiquemos los valores de a y b, no cambian los valores de numero1 y numero2. A continuación veremos un caso en el que sí, ya que pasaremos los valores por referencia:
#include <iostream>
using namespace std;

void PasarPorReferencia(int &a, int &b)
{
    a=a+b;
    b=a;
}
int main()
{
    int numero, numero2;
    numero=10;
    numero2=20;
    PasarPorValor(numero,numero2);
    cout << "numero=" << numero << ", numero2=" << numero2 << endl;
    //numero=30, numero2=30   
    system("pause");
}

NOTA IMPORTANTE: La ejecución del código de una función termina cuando se llega a la última línea de esta, o cuando se encuentra el primer return, ya que una función sólo puede devolver un valor, la única forma de "devolver" varios valores es pasando los parámetros por referencia.

Aprende a programar: 6 - Vectores y Matrices

Hasta ahora las variables usaban un valor simple como un entero, un carácter, un booleano, etc... a medida que se maneja mayor número de datos y de variables, se incrementa la dificultad de comprender los programas y el tamaño de éstos. Gracias a las estructuras de datos podemos tener esas variables mejor organizadas, en una estructura, de forma que sea sencillo acceder a ellas.
Hay muchos tipos de estructuras de datos, en esta unidad didáctica sólo haremos un primer acercamiento explicando los vectores y las matrices.

Imaginemos que tenemos que almacenar las notas de 10 alumnos en nuestro programa, según lo que sabemos hasta ahora, tendríamos que crear 10 variables diferentes para tenerlas todas disponibles en nuestro programa. Quizá sea algo viable, pero... ¿y si queremos almacenar 500 notas?, ¡¡sería bastante engorroso tener que crear 500 variables!!... una solución bastante común y recurrida a este tipo de problema son los vectores.

VECTORES

Un vector es un conjunto finito y ordenado de elementos del mismo tipo, el hecho de estar ordenado significa que cada elemento es identificable por la posición que ocupa dentro del vector, lo que permite acceder de forma directa a cualquiera delos elementos que forman ese conjunto finito de datos, para ello habrá que indicar la posición que ocupa el elemento.
Para definir un vector necesitamos saber cuál será su tamaño, es decir, cuántos elementos podrá almacenar como máximo.

Definición de un vector:
tipoDato nombreVector[tamaño];

Algunos lenguajes, como C++, tienen la peculiaridad de que comienzan por la posición 0, y terminan por la posición tamaño-1;
Por ejemplo, si definimos int vector[10];, el primer elemento sería vector[0] mientras que el último sería vector[9]. Si intentamos acceder a vector[10] obtendríamos un error de ejecución.

Podemos usar cualquier elemento del vector como si se tratase de una variable de su tipo. Si tenemos un vector de números enteros, podemos sumar, restar elementos de los vectores: vector[2]+vector[5],etc...

Ejemplo de uso de un vector:

#include <iostream>
using namespace std;

int main()
{
    int ktam=10;
    float notas[ktam];
    int i;

    //Vamos a almacenar las notas
    for (i=0;i<ktam;i++)
    {
        cout << "Introduce la nota del alumno " << i+1 << endl;
        cin >> notas[i];
    }

    //Ahora mostramos las notas
    for (i=0;i<ktam;i++)
        cout<< "La nota del alumno " << i+1 << " es de " << notas[i] << endl;

    system("pause");
}

Para usar vectores como parámetros de una función, simplemente tenemos que incluir los corchetes en la declaración de la función para indicar que el parámetro es un vector. Ejemplo:
#include < iostream >
using namespace std;

void LeerNotas(float vector[],int tamanyo)
{
    int i;
    for (i=0;i<tamanyo;i++)
    {
        cout << "Introduce la nota del alumno " << i+1 << endl;
        cin >> vector[i];
    }
}

int main()
{
    const int ktam=10;
    float notas[ktam];
    int i;

    //Vamos a almacenar las notas
    LeerNotas(notas,ktam);

    //Ahora mostramos las notas
    for (i=0;i<ktam;i++)
        cout<< "La nota del alumno " << i+1 << " es de " << notas[i] << endl;

    system("pause");
}

Un vector siempre se pasa a una función como parámetro POR REFERENCIA.

MATRICES (VECTORES MULTIDIMENSIONALES)

En ocasiones, para representar un conjunto de datos del mismo tipo puede no ser del todo cómodo utilizar vectores de una sola dimensión. En el ejemplo anteror, se almacenaba una nota para cada alumno, pero ¿y si se quiseran guardar 10 notas de cada alumno?, ¡volvemos a tener el mismo problema que con las variables!. La solución a esto es crear vectores multidimensionales, donde cada posición del vector tiene otras tantas posiciones. Por tanto, si declaramos una matriz de 10x10 elementos, en total son 100 elementos.

Veamos ahora como se aplicaría el uso de matrices al nuevo problema:
#include <iostream>
using namespace std;

const int kalumnos=3;
const int knotas=3;

void LeerNotas(float matriz[][knotas],int alumnos,int notas)
{
    int i,j;
    for (i=0;i<alumnos;i++)
        for (j=0;j<notas;j++)
        {
            cout << "Introduce la nota "<< j+1 <<" del alumno " << i+1 << endl;
            cin >> matriz[i][j];
        }
}

int main()
{
    float notas[kalumnos][knotas];
    //notas[i][j] sería la nota j del alumno i
    int i,j;

    //Vamos a almacenar las notas
    LeerNotas(notas,kalumnos,knotas);

    //Ahora mostramos las notas
    for (i=0;i<kalumnos;i++)
        for (j=0;j<knotas;j++)
            cout<< "La nota "<< j+1 <<" del alumno " << i+1 << " es de " << notas[i][j] << endl;

    system("pause");
}


Para que una función reciba como parámetro un vector multidimensional, se ha de especificar el tamaño de todas las dimensiones excepto la primera.

¡FIN!

y ahora.... ¿por donde sigo?... Bueno, si has terminado este manual, te aconsejo que empieces con la programación orientada a objetos. ¡Suerte! ;)

miércoles, 28 de octubre de 2009

Popups modales con javascript y ThickBox

ThickBox es como Lightbox pero te permite mostrar contenido HTML además de imágenes. En la web se puede comprobar cómo queda:



Su uso es muy sencillo, solamente hay que asignar los atributos href y class de un enlace tal que así:

Show hidden modal content.

Donde "hiddenModalContent" es el id del div que se mostrará:



Para cerrar el popup simplemente llamamos a la función tb_remove():



A mí, personalmente, me gusta más la opción de crearme una función para mostrar los popups, ya que si lo hacemos como he explicado anteriormente nuestra aplicación queda ligada al uso de thickbox y si en un futuro queremos cambiar (porque hemos encontrado otra librería que nos gusta más, por ejemplo) tendríamos que ir cambiando todo el código en la aplicación. Por ello podemos hacer uso de la siguiente función:

showPopup = function(div_id, width, height){
//Generar URL para thickbox
var thickboxURL = "#TB_inline?height=" + height + "&width=" + width + "&inlineId=" + div_id + "&modal=true";
//Llamar a método de thickbox que muestra un popup con la URL generada
tb_show(null, thickboxURL, null);
}

De esta forma si posteriormente quieres cambiar de librería para mostrar popups (por ejemplo colorbox tiene muy buena pinta) sólo tienes que modificar esa función, no toda la aplicación.

martes, 27 de octubre de 2009

6 formas de obtener el directorio actual en C#

Aquí tienes 6 formas distintas de obtener el directorio actual con C#:

AppDomain.CurrentDomain.BaseDirectory: Esta es la mejor opción, te devuelve el directorio base donde se encuentran las librerías, incluyendo aplicaciones ASP.NET

Directory.GetCurrentDirectory(): Realiza una llamada a GetCurrentDirectory de kernel32.dll. La documentación de MSDN afirma que no se garantiza que funcione en dispositivos móviles.

Environment.CurrentDirectory: este llama a Directory.GetCurrentDirectory()

Assembly.Location: se utiliza de la forma:

this.GetType().Assembly.Location

Devuelve la ruta completa al ensamblado, incluyendo el nombre del ensamblado en si.

Application.StartupPath: Está en el espacio de nombres System.Windows.Forms, se suele usar en los Windows Forms únicamente.

Application.ExecutablePath: Es lo mismo que Application.StartupPath, pero este incluye el nombre del ejecutable.

miércoles, 21 de octubre de 2009

Prueba tus aplicaciones symbian en cualquier terminal

Cuando desarrollas para Symbian encuentras que existen distintas resoluciones de pantalla para cada terminal, distintas funcionalidades, etc... para que puedas probar tus aplicaciones (ó las que quieras) no necesitas instalarte el SDK con el emulador. Nokia nos ofrece gratuitamente "Remote Device Access", a través del cual tendremos acceso a una gran variedad de terminales para hacer con ellos (casi) lo que queramos.

Puedes elegir entre los móviles disponibles ó reservar los que no lo están.





Cuando elijas el terminal que quieras, mediante una aplicación Java puedes acceder a todas sus funcionalidades, instalar software, etc...







Además, estos terminales tienen acceso a internet, para poder realizar cualquier prueba.

Bug en Sensor Service API también en Flash Lite

Hace unos días comenté la existencia de un bug en el API "Sensor Service" de nokia WRT (http://sviudes.blogspot.com/2009/10/bug-en-sensor-service-api-de-nokia-web.html). Pues bien, ocurre exactamente lo mismo con Flash Lite, por lo tanto parece ser que es un bug de Symbian S60. Tras estar unos 10 minutos funcionando, la aplicación se cierra, ejecutándose sobre un 5800. Unos 40 minutos tarda si se usa un N97 (con la última versión de firmware)...

Editado 20/04/2010: En la versión 50.0.005 del firmware, en el nokia 5800, el bug comentado está solucionado. 

jueves, 15 de octubre de 2009

Iniciar sesión automáticamente en Windows XP

Haz click en Inicio y luego selecciona "Ejecutar...", escribe CONTROL USERPASSWORDS2 y pulsa intro (ó Aceptar) y verás una ventana como la siguiente:

Desmarca la casilla donde dice "Los usuarios deben de escribir su nombre y contraseña para usar el equipo", luego pulsa aceptar y te pedirá la contraseña del usuario que iniciará sesión automáticamente, escríbela y listo.

miércoles, 14 de octubre de 2009

¿Bug en "Sensor Service API" de Nokia Web Runtime Widgets?

Los WRT (Web Runtime Widgets) son programas realizados con html, css y javascript encapsulados en un fichero wgz (por ejemplo, mi alcoholímetro).

Javascript se está convirtiendo en un estándar no sólo para aplicaciones web, sino también para aplicaciones móviles (véase WebOS, Nokia WRT y PhoneGAP). Además, se nos facilita un bonito API para poder acceder a las distintas funcionalidades del terminal (GPS, agenda, sensores, mensajes, etc...).

Hace poco comencé a realizar un sencillo juego, el cual usa el acelerómetro del móvil como sistema de manejo. Todo muy bien, si no fuera porque tras 10 minutos de juego, éste se cierra mostrando un mensaje que dice "Memoria llena, se cerrarán todas las aplicaciones"... "algo habrás hecho mal" pensará más de uno... (es lo que también pensé yo) pero lo cierto es que, después de muchas pruebas, me di cuenta de que el juego funcionaba correctamente si no utilizaba el acelerómetro... "algo habrás hecho mal con el acelerómetro" pensarás (lo mismo pensé yo), pero cual fue mi sorpresa (y la de más de uno) al comprobar que el propio ejemplo que ofrece Nokia (http://wiki.forum.nokia.com/index.php/Sensors_Service_in_WRT) también se cierra al estar 10 minutos abierto... ¿bug? ¿mala documentación?... sea como sea, por culpa de esto, no voy a poder acabar mi bonito juego...

Editado 20/04/2010: En la versión 50.0.005 del firmware, en el nokia 5800, el bug comentado está solucionado.

martes, 6 de octubre de 2009

Generar números aleatorios con javascript

Usando la función Math.random podemos obtener un número aleatorio comprendido entre 0 y 1, usando esta sencilla función, podemos definir el intervalo dentro del cual queremos que esté el número aleatorio:


function aleatorio(min, max){
return parseInt(min, 10) + Math.round( Math.random() * (max - min) );
}


Los números "max" y "min" están comprendidos entre los posibles resultados obtenidos.