Category Archives: Curso

#define en C++, cómo sí y cómo no

El mayor objetivo de este post es darles a conocer una de las cosas que C++ permite hacer pero que nadie en su sano juicio debería de hacer. ¿Y para que se los enseño entonces? Pues para que si algún día lo ven en un código ajeno sepan qué pinch_ está pasando.

Bueno, antes que nada, #define sirve para dos cosas: definir una constante o crear un macro. Los macros pueden llegar a ser algo difícil de entender, ahora sólo veremos el asunto de las constantes. El asunto aquí es que si yo pongo (fuera del main) una línea así:

#define PI 3.14159265

…significa que cada vez que escribamos PI en nuestro programa, C++ lo interpretará como 3.14159265. Es una simple sustitución.

#define  

Pero el asunto es que se puedes hacer algunas cosas bastantes feas con esta propiedad. Vean este programa:

#include
using namespace std;

#define PI 3.14159265
#define NOF_CHAR 50
#define pause cin.get();cin.get();
#define ct cout
#define cn cin
#define false true

int main()
{
    char name[NOF_CHAR] = {0};
    ct <> name;
    ct << "Bye " << name << "." << endl;
    if(false)
        ct << "P.S. Pi = " << PI;
    pause
}

Tenemos 6 definiciones, ordenadas en su nivel de aceptabilidad:

  • #define PI 3.14159265 y #define NOF_CHAR 50, éstos ejemplifican el uso primario de #define: guardan un valor que es constante durante toda la ejecución del programa.
  • #define pause cin.get();cin.get();, ésta ya empieza a ser no aceptable pero podemos darla por buena porque nos ayuda a leer mejor nuestro código. Ya sabemos que al escribir cin.get();cin.get(); nuestro programa se pausa al igual que con un getch(), pero al usar este #define escribiremos en lugar de eso simplemente pause.
  • #define ct cout y #define cn cin, totalmente inaceptables. Algunas personas usan este tipo de #define’s para escribir menos, pero de verdad que (en la gran mayoría de los casos) no vale la pena el ahorro de caracteres, sólo estamos haciendo nuestro código menos entendible para otras personas.
  • #define false true, este es mas bien como una broma (y es increíble que funcione en verdad), pero si se usa en serio es como una rayada de madre. Si ejecutan el código verán que sí se muestra la línea donde se imprime PI aún que está dentro de un if al que nunca se debería de entrar ¿y porqué sí entra? porque false es true.
Así que ya saben cómo sí y cómo no usar un #define en C++, y ya no están ‘indefensos’ ante programadores con malos hábitos.

Cuando inicializar las variables en cero y cuando no

Cuando empecé a aprender a programar en c++ (creo que uno nunca acaba) me enseñaron que siempre hay que inicializar en cero o en algún otro valor las variables, porque si no, pueden tomar valores raros que podrían arruinar nuestro programa.

Vamos a ver si la leyenda es cierta:

#include
using namespace std;

int main()
{
    int var1;
    cout << var1;
}

Pues con mi compilador sí lo es, una variable sin inicializar toma valores raros. Pero si se han fijado en mis programas, yo no siempre inicializo mis variables, ¿por qué? Pues porque no siempre es necesario.

La regla es bastante simple: “Si la primera instrucción en la que usamos nuestra variable es de asignación, no es necesario inicializarla.” Por ejemplo:

cin >> var1; // no es necesario inicializarla
var2 = 14; // no es necesario inicializarla
cout << var3; // es necesario inicializarla
var4 = cos(45); // no es necesario inicializarla
var5++; // es necesario inicializarla
if(var6 != 7) // es necesario inicializarla
cin.getline(var7); // no es necesario inicializarla

Podemos seguir inicializando todas las variables que usemos, pero si únicamente inicializamos las necesarias vamos a dar la impresión de que sabemos lo que estamos haciendo XD

Operadores compuestos en C++

Los operadores (en cualquier lenguaje de programación) son los símbolos que permiten hacerle una operación a una o más variables. Los más conocidos son los operadores aritméticos:

  • + Suma
  • Resta
  • * Multiplicación
  • / División
  • % Módulo (residuo de la división)

Otros son los lógicos (&&, ||), los relacionales (<, >, !=, ==), etc. Pero en este post, como dice el título, vamos a ver los operadores compuestos en c++.

¿Cómo haríamos para sumarle a una variable int, por ejemplo, 3 unidades? Alguien que nunca hubiera programado escribiría algo así:
mivar + 3;
Sabemos que eso no es válido porque una suma retorna un valor (el resultado) y ese valor tiene que ser almacenado en una variable. En el código anterior ese valor no se almacena en ninguna variable, por lo tanto ERROR. Sabiendo esto último podemos escribir esto:
mivar = mivar + 3;
En la variable mivar, guardamos el contenido de esa misma variable más tres. Todo bien ¿no? eso es perfectamente válido y normal, sin embargo los operadores compuestos nos permiten hacer lo mismo con menos código:
mivar += 3;
Como ven está inspirado en hacer que ‘lo-primero-que-se-nos-ocurre’ sea posible.

Así tenemos que:

mivar = mivar + 3; es lo mismo que mivar += 3;
mivar = mivar - 3; es lo mismo que mivar -= 3;
mivar = mivar * 3; es lo mismo que mivar *= 3;
mivar = mivar / 3; es lo mismo que mivar /= 3;

Bueno, para ver un poco de la utilidad de estos operadores y haciéndole un favor a un tal Victor, vamos a ver un programa que imprima los múltiplos de un cierto número (introducido por el usuario) que haya desde 1 hasta otro cierto número (introducido por el usuario):

#include
using namespace std;
int main()
{
    int num, lims, m=0;
    cout <> num;
    cout <> lims;
    while(lims >= (m+=num))
    {
        cout << m << ", ";
    }
}

Primero pedimos el número del cual queremos obtener múltiplos (num), luego el límite superior (lims). m obtendrá el valor de los múltiplos y lo tenemos que igualar a 0 al inicio.

Luego tenemos un ciclo while. En español dice: “Me mantendré ejecutando mientras el lims sea mayor o igual a m más num“. Dentro del ciclo mostramos la variable m.

Si, por ejemplo, num = 3, entonces la instrucción n+=num se desarrolla así:
m = 0;
m+=num; -----> m= m + num; -----> m = 0 + 3; -----> m = 3;
m+=num; -----> m= m + num; -----> m = 3 + 3; -----> m = 6;
m+=num; -----> m= m + num; -----> m = 6 + 3; -----> m = 9;
etc, etc.

Aquí podría poner un otro programa aún más útil para usar los operadores compuestos, pero mejor lo dejo para el siguiente post. Ah y si tú eres Victor, entonces tal vez te interese este post: Cómo contar el número de veces que sucede algo.

Tipos de funciones en C++

Los tipos de funciones en c++ son 4, aunque en realidad son las combinaciones de las 2 cosas que una función puede hacer. Si andan perdidos en cuanto a funciones les recomiendo leer mi post anterior: Funciones en C++.

Una función, como les decía, puede hacer (o no) dos cosas: 1 – Recibir datos y 2 – Retornar datos. De esto surgen los cuatro tipos de funciones:

  1. No reciben ni retornan
  2. Reciben y no retornan
  3. No reciben y retornan
  4. Reciben y retornan

Vamos a hacer un programa que sume dos números, usando los cuatro tipos de funciones:

No reciben ni retornan

Las más sencillas. Para usarlas sólo tenemos que saber cómo crearlas y cómo llamarlas. Una función se crea de esta forma general:
tipo nombre(){}
El ‘tipo’ se refiere al tipo de dato (int, float, void, char) y en las funciones que no retornan siempre es void.

El ‘nombre’ es el nombre de la función: cualquiera que empiece con una letra, que sea significativo y que no sea una palabra reservada.

Para llamarlas sólo hay que escribir el nombre de la función seguido de sus paréntesis y un punto y coma (;).
nombre();

Así nuestro programa sería:

#include
using namespace std;

void sumar()
{
    int num1, num2, r;
    cout <> num1;
    cout <> num2;
    r = num1 + num2;
    cout << "La suma es " << r;
}

int main()
{
    sumar();
}

Como ven, todo lo que habríamos puesto en nuestro main mejor los pusimos en una función y desde el main la llamamos. Una función siempre, siempre, siempre tiene que ir antes del main.

Una función de este tipo que hemos usado muchas veces es getch();

Reciben y No Retornan

¿Cómo haríamos para pedir los dos números en el main y que la función haga la suma? Para eso tenemos que hacer una función capaz de recibir datos, entonces la sintaxis cambia un poco:
tipo nombre(tipo_var1 nombre_var1, tipo_var2 nombre_var2){}
‘tipo’ y ‘nombre’ se refieren a lo mismo y como no retorna el tipo siempre es void.

Dentro del paréntesis tenemos otros aspectos:

‘tipo_var1’ se refiere al tipo de la variable que nuestra función va a recibir.

‘nombre_var1’ se refiere al nombre de esa variable.

Si queremos recibir una variable hasta ahí es suficiente, si queremos otra variable ponemos una coma (,) y declaramos la siguiente variable.

Para llamar la función hay que poner la variables que vamos a enviar dentro del paréntesis en el mismo orden en que las declaramos en la función:
nombre(var1, var2);

Nuestro programa quedaría así:

#include
using namespace std;

void sumar(int num1, int num2)
{
    int r;
    r = num1 + num2;
    cout << "La suma es " << r;
}

int main()
{
    int num1, num2;
    cout <> num1;
    cout <> num2;
    sumar(num1, num2);
}

Pedimos los dos números en el main, los enviamos a la función, ésta los suma y los muestra.

Una función de este tipo que hemos usado muchas veces es el odiado por muchos, amados por otros, gotoxy(x,y);

Retornan y No Reciben

¿Y si ahora queremos lo contrario? Pedir los números en la función, pero mostrar el resultado en el main. Para eso necesitamos una función que retorne.

Recibir es enviar datos del main a la función. Retornar es enviar datos de la función al main. Para retornar datos hay que hacer dos cosas: no usar void como tipo y usar return.

De forma general:
tipo nombre() { return var; }
El ‘tipo’ tiene que ser del tipo de variable que queremos retornar, si nuestra variable retorna una variable int, pues el tipo de la función es int.

Para indicar qué variable estamos retornando usaremos la palabra return seguido de la variable. Usualmente esto va al final de la función.

Para llamar a la función hay que preparar un colchón en donde caiga la variable que está retornando.
var = nombre();
La variable que está retornando nuestra función se va a almacenar en la variable ‘var’. Este es un buen momento para recordarles que las variables declaradas entre dos llaves {} únicamente existen entre esas dos llaves. O sea que la variable ‘var’ de la función no es la misma que la variable ‘var’ de la función; sin embargo la var del main está adquiriendo el valor de la var del main. Un poco confuso lo se, no se preocupen.

Nuestro programa quedaría así:

#include
using namespace std;

int sumar()
{
    int num1, num2, r;
    cout <> num1;
    cout <> num2;
    r = num1 + num2;
    return r;
}

int main()
{
    int r;
    r = sumar();
    cout << "La suma es " << r;
}

¿A alguien se le ocurre una función conocida de este tipo?

Reciben y Retornan

Ahora queremos que nuestra función únicamente sume, el main se va a encargar de pedir los números y sumar los resultados. Para eso necesitamos que nuestra función reciba las variables y además retorne el resultado. ¡Wow! ¿Es acaso eso posible? Claro que sí.

Es sólo cuestión de combinar las funciones que reciben y no retornan con las que retornan y no reciben.

Nuestro programa quedaría así:

#include
using namespace std;

int sumar(int num1, int num2)
{
    int r;
    r = num1 + num2;
    return r;
}

int main()
{
    int num1, num2, r;
    cout <> num1;
    cout <> num2;
    r = sumar(num1, num2);
    cout << "La suma es " << r;
}

Las funciones de la librería math.h son en su mayoría de este tipo. sqrt(); pow(); sin();

En principio puede parecer que las funciones sirven únicamente para organizar el código, lo cual es cierto, pero no sólo eso. ¿Se imaginan si tuviéramos que escribir todo el código detrás de un simple gotoxy();? Ah verdad…

Bueno, no me iba a quedar tranquilo si no les mostraba la versión optimizada de la última función:

#include
using namespace std;

int sumar(int num1, int num2)
{
    return num1 + num2;
}

int main()
{
    int num1, num2;
    cout <> num1;
    cout <> num2;
    cout << "La suma es " << sumar(num1, num2);
}

😀

Funciones en C++

Supongo que ya es hora de retomar el blog y ponerme a hablar de funciones en c++. Una función es un pedazo de código fuera del main, con un nombre y que puede ser ‘llamado’ desde otra parte de nuestro programa.

Imagínense que están entrenando a su perro a hacerse el muertito. Cada vez que ustedes dicen ‘muertito‘, el perro se tira de espaldas en el suelo, cierra los ojos y saca la lengua. En programación, el contenido de la función sería tirarse de espaldas, cerrar los ojos y sacar la lengua; el nombre de la función sería muertito; y cada vez que nosotros decimos muertito estamos llamando a la función.

Nuestra función sería algo así:

void muertito()
{
   Perro.Tirarse(posicion='espalda');
   Perro[OjoDer].Cerrar();
   Perro[OjoIzq].Cerrar();
   Perro[Lengua].Sacar();
}

Jajaja, bueno, bueno. Ya en serio vamos a hacer un clásico Hola Mundo pero usando una función:

#include
using namespace std;
void hola()
{
    cout << "Hola Mundo!";
}
int main()
{
    hola();
}

Como ven, esta función es muy estúpida. No nos beneficia en nada y nos hace escribir más código del necesario, pero nos sirve para ver cómo actúa una función: al momento de llamar a la función, el compilador se brinca a la función, la ejecuta y cuando termina, vuelve al punto desde donde brincó.

Si pudieran leerle la mente a un compilador, este diría:

Linea 1. Incluir la librería iostream. OK
Linea 2. Usar el namespace estándar. OK
Linea 3. Oh! una función llamada hola, la recordaré.
Linea 4. Llave. Parte de la función. Ignorar
Linea 5. Imprimir “Hola Mundo!”. Parte de la función. Ignorar
Linea 6. Llave. Parte de la función. Ignorar
Linea 7. ¡Por fin el main!
Linea 8. Llave. Entrar
Linea 9. Esta función se me hace conocida… oh sí ya recuerdo. Ejecutar lineas 4, 5 y 6
Linea 10. Llave. Salir

Ahora veamos una función que sí nos es útil:

#include
using namespace std;

void hola(char nombre[50])
{
    cout << "Hola " << nombre << "!";
}

int main()
{
    char nombre[50];
    cout << "Cual es tu nombre?: "; cin.getline(nombre, 50, 'n');
    hola(nombre);
}

Primero pedimos un nombre, lo guardamos en una variable y se le mandamos a la función para que lo muestre.

No se preocupen, si nunca habían visto una función tal vez no entiendan la sintaxis, pero el objetivo de este post es que sepan qué es una función y para qué se puede usar. En el siguiente post voy a explicar la sintaxis de los cuatro tipos de funciones en c++.

Como usar cin.getline en C++

Bueno, siguiendo con la línea de los posts sobre la librería string.h les traigo esta función que no está en esa librería pero que es muy útil al trabajar con strings. Ya dijimos que un/una string es una variable que puede contener 0, uno o más caracteres.

Ya vimos en nuestra introducción a string.h cómo declarar un string, hacerle algunas modificaciones y cómo mostrarlo. Ahora veremos como pedir un string (que el usuario la introduzca por medio del teclado).

Esto es muy sencillo si usamos la función cin.getline(); Esta función necesita tres datos o parámetros:

  1. Nombre. El nombre de la variable que va a contener el string
  2. Longitud. La cantidad de caracteres que queremos que se puedan introducir (nunca mayor que la longitud del string).
  3. Caracter de fin. El caracter que el usuario va usar como final de la cadena. Por lo general es el ‘enter‘ que se representa como ‘n’ (diagonal n).

Por ejemplo, supongamos que tenemos un arreglo char de 500 elementos llamado str (nuestra string) y queremos pedirle al usuario que la “llene”, la función cin.getline quedaría así:

cin.getline(str, 500, 'n');

Como ven, los parámetros van separados por comas (,), y el caracter de fin está entre comillas simples (‘). Pero bueno, dejemos de suponer y empecemos a programar.

#include
using namespace std;

int main()
{
    char str[500];
    cout << "Introduce una frase: ";
    cin.getline(str, 500, 'n');
    cout << "Tu frase es: " << str;
    cin.get();
}

Mas sencillo no podría ser.

Introducción a string.h

string.h es una librería de c++ que contiene funciones que nos facilitan la vida al trabajar con cadenas o strings. Una cadena es un conjunto de caracteres almacenados en una variable.

Deberíamos saber que char es un tipo de dato que almacena un caracter, por lo tanto un arreglo lineal de caracteres es una cadena:

char str[100];

Ahora podemos llenar nuestra cadena..

str ="Soy una cadena";

…y mostrarla

cout << str;

Pero recuerden que no podemos hacer nada de esto si no tenemos incluida la librería string.h. Vamos a ver un programa de ejemplo:

#include
#include
using namespace std;

int main()
{
    char esunacadena[100] = "Soy una cadena", esunacopia[100];
    strcpy(esunacopia, esunacadena);
    strcat(esunacopia, " - copia");
    cout << esunacadena << endl << esunacopia;
    cin.get();
    return 0;
}
  1. Primero declaramos dos cadenas (‘esunacadena’ y ‘esunacopia’) que pueden tener hasta 100 caracteres, ‘esunacadena’ la llenamos con el texto “Soy una cadena“.
  2. Luego con la función strcpy copiamos el contenido de ‘esunacadena’ a ‘esunacopia’. Ahora las dos cadenas tienen el mismo texto.
  3. Ahora con la función strcat agregamos el texto ” – copia” al final de’esunacopia’.
  4. Al final solo mostramos las dos cadenas.

Bastante fácil ¿no? En los próximos días voy a postear otros programas muy sencillos para seguir checando las funciones mas comunes para trabajar con cadenas.

Cómo empezar a usar iostream

Programar es como pensar, cada quien lo hace diferente, y el mismo lenguaje c++ nos facilita diversas formas de hacer las mismas cosas. Por ejemplo, el programa Hola Mundo que hicimos al principio podemos hacerlo utilizando la librería <iostream> en lugar de <stdio.h>:

#include<iostream>
using namespace std;  // Esta línea es necesaria cuando
                     // utilizamos la librería iostream

int main()
{
  cout << "Hola Mundo!";  //cout es el equivalente de printf,
                         //si se fijan la sintáxis es muy parecida.
  cin.get();  // cin.get es el equivalente de getch, detiene la ejecución del programa.

  return 0;  // No es necesaria para que el programa funcione,
            // pero es una buena costumbre indicar que nuestro programa terminó
           // sin errores.
}

La sintáxis de cout es:
cout << "mensaje" ;
Mostrando una variable:
cout << "El promedio es:" << prom ;
El siguiente mensaje aparecerá en una línea nueva:
cout << "mensaje" << endl;

¿Y cómo leo datos (scanf)?

Para sustituir scanf() usamos cin, por ejemplo:
cin >> edad;
Lee los caracteres introducidos y los guarda en la variable edad.

Un programita muy simple:

#include<iostream>
using namespace std;

int main()
{
  int edad;
  cout<<"Cual es tu edad?: "; cin >> edad;
  cout<<"ntTu edad es " << edad;
  cin.get();cin.get();

  return 0;
}

En este caso necesitamos usar dos cin.get para detener el programa. Esto se debe al uso de cin.

Como usar ciclo While en C++

Ya dijimos en el post anterior que los ciclos infinitos for son muy parecidos a los ciclos while, pero quedó en duda cómo es un ciclo while.

While” significa “mientras“, así que nuestro ciclo while se repetira mientras una cierta condición siga siendo verdadera.El ejemplo del post anterior quedaría así:

#include<stdio.h>
#include<conio.h>
 int main()
 {
  char end=0;
  while(end!='y')
  {
    gotoxy(5,5);printf("Ya quieres salir? (y/n): ");scanf("%c",&end);
    clrscr();
  }
}

En español el programa dice: “Mientras end sea diferente de y voy a seguir preguntando si quieres salir.

Mas adelante veremos más programas que utilicen ciclos while.

El break y el ciclo infinito

Ya vimos hace poco el ciclo for, y vimos que su estructura era así:

for ( inicio ; fin ; aumento )

¿Qué pasa si no ponemos ni inicio ni fin? Pues obtenemos un ciclo infinito, así:

for(;;)

¿Y cómo se detiene? Pues con un break, así:

for(;;)
{
break;
}

¿Y esto de que me sirve? Pues la idea es repetir las instrucciones hasta que el usuario quiera, es decir:

#include<stdio.h>
#include<conio.h>
int main()
{
  char end=0;
  for(;;)
  {
    gotoxy(5,5);printf("Ya quieres salir? (y/n): ");scanf("%c",&end);
    if(end=='y')
      break;
    clrscr();
  }
}

Creo que no les había mencionado que si dentro de una condición if sólo va una instrucción no es necesario poner llaves, y también aplica con los ciclos.

Si el usuario no introduce una ‘y’, el programa nunca se detendrá. Luego vamos a ver que las propiedades de un ciclo for infinito son muy parecidas a las del ciclo while que veremos más adelante.