6 Declaración de variables

Una característica de C++, es la necesidad de declarar las variables que se usarán en un programa. Esto resulta chocante para los que se aproximan al C++ desde otros lenguajes de programación en los que las variables de crean automáticamente la primera vez que se usan. Se trata, es cierto, de una característica de bajo nivel, más cercana al ensamblador que a lenguajes de alto nivel, pero en realidad una característica muy importante y útil de C++, ya que ayuda a conseguir códigos más compactos y eficaces, y contribuye a facilitar la depuración y la detección y corrección de errores y a mantener un estilo de programación elegante.

Uno de los errores más comunes en lenguajes en los que las variables se crean de forma automática se produce al cometer errores ortográficos. Por ejemplo, en un programa usamos una variable llamada prueba, y en un punto determinado le asignamos un nuevo valor, pero nos equivocamos y escribimos prubea. El compilador o interprete no detecta el error, simplemente crea una nueva variable, y continúa como si todo estuviese bien.

En C++ esto no puede pasar, ya que antes de usar cualquier variable es necesario declararla, y si por error usamos una variable que no ha sido declarada, se producirá un error de compilación.

Cómo se declaran las variables

Ya hemos visto la mecánica de la declaración de variables, al mostrar la sintaxis de cada tipo en el capítulo 2.

El sistema es siempre el mismo, primero se especifica el tipo y a continuación una lista de variables y finalmente un punto y coma.

La declaración de variables es uno de los tipos de sentencia de C++. La prueba más clara de esto es que la declaración terminará con un ";". Sintaxis:

<tipo> <lista de variables>;

También es posible inicializar las variables dentro de la misma declaración. Por ejemplo:

int a = 1234;
bool seguir = true, encontrado;

Declararía las variables a, seguir y encontrado; y además iniciaría los valores de a y seguir con los valores 1234 y true, respectivamente.

En C++, contrariamente a lo que sucede con otros lenguajes de programación, las variables no inicializadas tienen un valor indeterminado (con algunas excepciones que veremos más tarde), y contienen lo que normalmente se denomina "basura". Cuando se declara una variable se reserva un espacio de memoria para almacenarla, pero no se hace nada con el contenido de esa memoria, se deja el valor que tuviera previamente, y ese valor puede interpretarse de distinto modo, dependiendo del tipo.

Ámbitos

Llamamos ámbito a la zona desde que cierto objeto es accesible.

En C++ solemos referirnos a dos tipos de ámbitos: temporal y de acceso. Así, el ámbito temporal indica el intervalo de tiempo en el que un objeto existe o es accesible. El ámbito de acceso nos dice desde donde es accesible.

En este capítulo hablaremos un poco sobre el ámbito de las variables, pero no entraremos en muchos detalles todavía, ya que es un tema largo.

Por otra parte, las funciones (y otros objetos de los que aún no hemos hablado nada), también tienen distintos ámbitos.

Ámbito de las variables

Dependiendo de dónde se declaren las variables, podrán o no ser accesibles desde distintas partes del programa. Es decir, su ámbito de acceso y temporal dependerá del lugar en que se declaren.

Las variables declaradas dentro de un bucle, serán accesibles sólo desde el propio bucle, esto es, tendrán un ámbito local para el bucle. Esto es porque las variables se crean al inciar el bucle y se destruyen cuando termina. Evidentemente, una variable que ha sido destruida no puede ser accedida, por lo tanto, el ámbito de acceso está limitado por el ámbito temporal.

Nota: En compiladores de C++ antiguos, (y en algunos modernos y mal implementados), no existe este ámbito, que sin embargo está descrito en la norma ANSI.
En estos compiladores, las variables declaradas dentro de un bucle tienen el mismo ámbito temporal y de acceso que las variables locales. Es decir, existen y son accesibles desde el punto en que se declaren hasta el final de la función.
Si usamos uno de esos compiladores no será posible, por ejemplo, usar varios bucles con declaraciones de variables locales de bucle con el mismo nombre.

for(int i=0; i < 100; i++) HacerAlgo(i);
for(int i=0; i > -100; i--) DeshacerAlgo(i);


Este código daría un error al intentar redefinir la variable local i.

Las variables declaradas dentro de una función, y recuerda que main también es una función, sólo serán accesibles para esa función, desde el punto en que se declaran hasta el final. Esas variables son variables locales o de ámbito local de esa función.

Al igual que ocurre con las variables locales de bucle, en las de función, las variables se crean al inciar la función y se destruyen al terminar.

Las variables declaradas fuera de las funciones, serán accesibles desde todas las funciones definidas después de la declaración. Diremos que esas variables son globales o de ámbito global.

El ámbito temporal de estas variables es también global: se crean junto con el programa, y se destruyen cuando el programa concluye.

Las variables globales son las únicas que son inicializadas automáticamente con valor cero cuando se declaran. Esto no sucede con ninguna variable local.

En todos los casos descritos, el ámbito temporal coincide con el de acceso: las variables que no pueden ser accedidas es porque no existen todavía o porque han sido destruídas. Más adelante veremos casos en que estos ámbitos no coinciden.

Una variable global declarada después de la definición de una función no será accesible desde esa función, por eso, normalmente se declaran las variables globales antes de definir las funciones.

Pero esto es hablando de forma general, en realidad, en C++ está mal visto usar variables globales, ya que se consideran poco seguras.

Ejemplo:

int EnteroGlobal; // Declaración de una variable global

int Funcion1(int a); // Declaración de un prototipo

int main() {
   // Declaración de una variable local de main:
   int EnteroLocal;

   // Acceso a una variable local:
   EnteroLocal = Funcion1(10); 
   // Acceso a una valiable global:
   EnteroGlobal = Funcion1(EnteroLocal); 

   return 0;
}

int Funcion1(int a) 
{
   char CaracterLocal; // Variable local de funcion1
   // Desde aquí podemos acceder a EnteroGlobal, 
   // y también a CaracterLocal 
   // pero no a EnteroLocal
   if(EnteroGlobal != 0)   
      return a/EnteroGlobal;
   return 0;
}

De modo que en cuanto a los ámbitos locales tenemos varios niveles:

<tipo> funcion(parámetros) // (1)
{
   <tipo> var1;             // (2)
   for(<tipo> var2;...)     // (3)
   ...
   <tipo> var3;             // (4)
   ...
   return var;
}

(1) Los parámetros se comportan del mismo modo que variables locales, tienen ámbito local a la función.

(2) Las variables declaradas aquí, también.

(3) Las declaradas en bucles, son de ámbito local en el bucle.

(4) Las variables locales sólo son accesibles a partir del lugar en que se declaren. Esta variable: var3, es de ámbito local para la función, pero no es accesible en el código previo a su declaración.

Es una buena costumbre inicializar las variables locales.

Los ámbitos pueden ser alterados mediante ciertos modificadores que veremos en otros capítulos.

Enmascaramiento de variables

Generalmente no es posible, y no suele ser necesario, declarar dos variables con el mismo nombre, pero hay condiciones bajo las cuales es posible hacerlo.

Por ejemplo, podemos declarar una variable global con un nombre determinado, y declarar otra variable (del mismo tipo o de otro diferente) de forma local en una función, usando el mismo nombre.

En ese caso decimos que la segunda declaración (la local), enmascara a la primera (la global). Con eso queremos decir que el acceso a la variable global está bloqueado o enmascarado por la local, que es a la única que podemos acceder directamente.

Por ejemplo:

int x;

int main() {
   int x;
   
   x = 10;
   return 0;
}

En este programa, cuando asignamos 10 a x estamos accediendo a la versión local de la variable x. En la función main, la variable global x está enmascarada, y no puede accederse a ella directamente.

Del mismo modo, una variable de ámbito de bucle o de ámbito de bloque puede enmascarar a una variable global o local, o a una de un bloque o bucle más externo:

   int x = 10;
   {
      int x = 0;
      for(int x = 0; x < 10; x++) HacerAlgoCon(x);
   }

En este caso la declaración de x dentro del bloque enmascara la declaración anterior, y a su vez, la declaración dentro del bucle for enmascara a la declaración del bloque.

Otra cuestión sería qué utilidad pueda tener esto.

Operador de ámbito

Existe un método para acceder a una variable global enmascarada por una variable local. Se trata del operador de ámbito, que consiste en dos caracteres de dos puntos seguidos (::).

Veremos este operador con más detalle en el capítulo dedicado a los espacios con nombre, pero veamos ahora cómo lo podemos usar para acceder a una variable global enmascarada:

int x; // Variable global

int main()
{
   int x; // Variable local que enmascara a la global
   
   x = 10; // Accedemos a la variable local
   ::x = 100; // Mediante el operador de ámbito accedemos a la global
   return 0;
}

El operador de ámbito, usado de este modo, permite acceder al espacio de variables global. Pero este no es más que un uso restringido del operador, que tiene muchas más aplicaciones.

Comentarios de los usuarios (27)

Gonzalo lopez
2010-09-02 18:51:28

oiie ocupo saber k tipo de variable ocupo poner para un numero entero pero el numero es mayor que 32000

y si fuera menor que 32000 seria int pero ocupo el tipo de variable para entero mayor que 32000 me puedes ayudar

gonzalo lopez
2010-09-02 18:52:49

aaa perdon es para C++

lesmes
2010-12-01 03:28:12

no me sirvio para nada su curso, ninguno de los ejemplos me compilo satisfactoriamente.

jaime
2011-02-18 03:59:30

necesito ejemplos como raiz cuadrada valor absoluto,

x al cuadrado y numero aleatorio

Steven
2011-02-18 19:22:17

Hola Jaime,

Estos ejemplos que escribes se realizan con las funciones estándares de la biblioteca matemática declaradas en <cmath>. Por ejemplo,

sqrt( 4 );    // raíz cuadrada
abs( -23 );   // valor absoluto
pow( 3, 2 );  // potencias

En el caso de elevar un número al cuadrado, es más rápido multiplicar; o sea,

3*3

Para números aleatorios, necesitas la función estándar 'rand()' que se declara en <cstdlib>. También es aconsejable invocar UNA SOLA VEZ la función 'srand()' para inciar la generación de números pseudo-aleatorios. Esta función también se declara en <cstdlib>.

Puedes consultar la referencia en nuestra página de las funciones estándares. Los enlaces son: http://c.conclase.net/librerias/?ansilib=math#inicio y http://c.conclase.net/librerias/?ansilib=stdlib#inicio

Espero que esto te sirva.

Steven

Nicolás Liendo
2011-02-25 16:16:54

Excelente, este curso es muy bueno.

Verdaderamente se aprende así.

Un saludo y lo felicito por semejante esfuerzo.

Principiante
2011-06-15 20:41:31

Me gustaría que en el curso de C++ (hasta el momento todo lo que he leído está perfecto) se incluyesen mas ejemplos en cada apartado, pero ejemplos completos (desde los #includes hasta el return).

Saludos y enhorabuena por el curso (ojala logre aprenderlo, pero me cuestan los punteros...)

jimmie
2011-06-20 00:28:16

ayuda con el siguiente procedimiento: que lea una palabra de hasta 20 caracteres y la escriba como se ve en la

figura:

Entrada: HOLA

Salida:

HOLA

O L

L O

ALOH

de antemano muchas gracias

frco
2011-11-23 23:54:51

Muchas gracias por este curso. Me ha enganchado desde el principio aunque todavía voy por la lección 6. Esta explicado muy bien, y eso me anima a continuar con él.

Excelente trabajo.

Juan
2011-12-08 19:02:06

Excelente la explicación de los temas...voy apenas en el capitulo 6 pero ha servido mucho!

Ariel
2012-07-14 07:31:14

Hola, acabo de ver C++ en la facu y entré para adelantar un poco antes de comenzar el segundo cuatrimestre. Dí una leída desde el comienzo de su curso y no puedo dejar de felicitarlo, es excelente, los ejemplos son clarísimos, muy bien explicado todo en detalle, realmente le agradezco por su enorme y desinteresado trabajo, ya que no solo es gratis sino que siquiera tuve que registrarme. Muchas gracias desde Argentina!

sac
2012-08-08 00:32:09

El curso es excelente, es el mejor de los que he visto hasta ahora (los otros no se adecuan bn a los principiantes ¬¬)

en fin...

no me quedo del todo claro lo de que en c++ esta mal visto utilizar variables globales, porque se consideran inseguras.

agradezco la atencion y felicitaciones por el curso!!

Steven R. Davidson
2012-08-08 01:53:03

Hola Sac,

Gracias por tu comentario.

Veamos, la razón de no usar variables globales es porque se pueden cometer demasiados errores lógicos y de diseño que son MUY difíciles de detectar en un proyecto. Si tienes un programa relativamente sencillo, no será un gran problema entender la relación de tal variable global con el resto del programa y así asegurar su corrección.

Cuando tienes un proyecto de mediana envergadura, con miles de variables, funciones, y varios códigos fuentes, te va a resultar casi imposible mantener la "paz" entre las variables globales y las funciones. Como seres humanos, nos gusta que las cosas sean fáciles de entender a través de conceptos y cuantos más sencillos, mejor. Por eso solemos ver cada función íntegramente y a veces independientemente. Sin embargo, al usar variables globales, ya no tenemos esa independencia, porque cualquiera puede acceder a la variable global y provocar comportamientos erróneos en otra parte de nuestro programa.

Esto es demasiado peligroso y por eso lo mejor es que no ocurra. Optamos por pasar la información necesaria como parámetros a una función y tratarla como variables locales. Es mucho más sencillo tratar cada función como una sola entidad, especialmente para su corrección, que estar pendientes del uso correcto de ciertas variables globales para ciertas funciones bajo ciertos usos del programa. Como no podemos limitar el uso de las variables globales de la forma en que queremos, no es recomendable usarlas.

Dicho todo esto, sí hay casos válidos en los que se requieren definir y usar variables globales, pero hay que tener MUCHO cuidado. En general, no es nada recomendable, pero siempre hay excepciones a la regla.

Hasta pronto,

Steven

sebastian vega
2012-08-11 21:29:54

como se podria explicar la siguiente definicion de funcion:

Int f (int a);

Carlos
2012-10-02 04:01:48

Hola, estoy siguiendo este curso de manera lineal, y no entiendo, en el ejercicio 6.5, qué significa el 12 entre corchetes ([12]) junto a resp, (resp[12]) y después lo de resp[0].

Gracias.

Steven R. Davidson
2012-10-03 02:41:16

Hola Carlos,

Se trata de un "array" de 12 elementos de tipo 'char' que sirve para representar una cadena de caracteres. Y luego, podemos acceder a cada elemento usando los corechetes a modo de índice. Explicamos las cadenas de caracteres en el capítulo 8 ( http://c.conclase.net/curso/?cap=008#inicio ).

Puedes saltarte este ejemplo #5 hasta que veas el tema de las cadenas de caracteres, que para entonces puedes retroceder para volver a verlo.

Hasta pronto,

Steven

Gustavo F. Paredes
2013-02-28 23:48:42

Pues entonces para un uso de memoria mas efectivo, conviene declarar las variables de un for (por ejemplo) dentro de la misma sentencia, para que al terminar el bucle se destruya y libere memoria.

En una PC no parece muy problematico, pero en sistemas embebidos (donde los recursos no son muy amplios) es un dato importante tener en cuenta esto.

Saludos.

Gustavo

Khancerberus
2013-08-05 03:31:09

mmm buen dato, no sabia mas o menos como hacer que las variables se destruyeran, pasando al tema, el curso esta muy bueno, he aclarado bastantes dudas, ademas de los ejercicios didacticos dan ganas de seguir hasta el final con este curso

Victoria
2013-11-09 19:32:59

Hola me podrias ayudar con un ejercicio que dice asi : Ingresar dos valores que sean diferentes, y visualizar la mayor cantidad ingresada

Jose
2014-01-29 21:43:55

Hola, felicidades por la página, resulta muy amena y didáctica. El caso es que estaba mirando problemitas para hacer y me encuentro este y me surgen dudas. Se trata de un programa que lee un par de matrices las multiplica y saca el resultado. Cada acción la hace en una función y el código no presenta problemas.

Las funciones tienen el void delante, entiendo que no devuelven nada. Entonces si no devuelven nada y las variables son locales a ella dónde almacena las dos matrices?? a y b, no debiera perderse en el limbo?

además " es obligatorio definir todas las variables"

producto_matrices (a,b,p);

esta sentencia hace alusión a "a,b y p"

pero sólo está definida la a, no debiera estar definidas b y p? y además ser globales para que las funciones que leen, multiplican y escriben puedan acceder a ellas??

Un saludo

#include <cstdlib>

#include <iostream>

using namespace std;

void leermatriz (float m[3][3])

{

.

.

}

void producto_matrices (float a [3][3],float b[3][3

],float p[3][3])

{

.

.

}

void escribir_matriz (float m[3][3])

{

.

.

}

int main()

{

float a[3][3];

leermatriz (a);

leermatriz (b);

producto_matrices (a,b,p);

escribir_matriz (p);

system("PAUSE");

return EXIT_SUCCESS;

}

Steven R. Davidson
2014-01-29 22:52:52

Hola José Luis,

En este caso, técnicamente los parámetros 'm', 'a', 'b', y 'p' son punteros, porque estás pasando arrays. El puntero en sí es lo que se crea y se destruye, no el contenido apuntado, que en estos casos se trata de 9 elementos de 'float'. Esto lo explicamos en los capítulos 12 y 15 ( http://c.conclase.net/curso/index.php?cap=015b#FUN2_ArrayParam ).

Lo que sí es cierto es que los arrays en 'main()' sí deben estar definidos: 'a', 'b', y 'p'; esto es,

int main()
{
  float a[3][3], b[3][3], p[3][3];
  ...
}

Como ves no hace falta usar variables globales. Pasamos los arrays (locales) por parámetros a las funciones.

Espero que esto aclare la duda.

Steven

ivan
2014-04-02 01:32:54

hola tengo una duda en el 6.1 cuando cree mi version del codigo lo hice casi igual pero con el operador /

y me salio que solo los dos primeros numeros eran multiplos de 3 y al verificar con el ejemplo vi el operador % que enrealidad nunca lo e utilizado, tengo entendido que el operador % es de divicion al igual que /

a si que mi duda es ¿no deveria dar lo mismo que diferencia hay en los operadores % y / no entiendo :( ?

paso mi codigo porsi hice algo mal

#include <cstdlib>

#include <iostream> //Biblioteca para uso de cout

using namespace std;

int main()

{

for(int i=1;i<=20;i++)

{

cout<<i;

if(i / 3 == 0) cout <<" es multiplo de 3";

else cout<<" no es multiplo de 3";

cout<<endl;

}

system("PAUSE");

return EXIT_SUCCESS;

}

Steven R. Davidson
2014-04-02 02:24:16

Hola Iván,

El operador % no es igual que /. Es cierto que ambos tienen que ver con la división, pero % calcula el resto de la división, mientras que / nos da el cociente.

Además, sabemos por las matemáticas que 1 y 2 no son múltiplos de 3, por lo que usar el operador / no es correcto.

Espero que esto te aclare las dudas.

Steven

ivan
2014-04-03 21:22:50

muchas gracias, yo no savia eso gracias :)

erik
2014-05-31 23:52:43

Hola buenas tardes

Estoy trabjando en codeblocks, y tengo un problema a la hora de compilar y ejecutar el programa me sale el siguiente error: undefined reference to ´winmain@16´, mi programa trata de incluir como entrada variables de tipo entero y como respuesta una bool, pero estoy con ese error y nose como solucionarlo.

Gracias

Steven R. Davidson
2014-06-01 15:39:28

Hola Erik,

Lo más seguro es que elegiste un proyecto de GUI para MS-Windows o posiblemente estás compilando sin usar un proyecto.

Elige un proyecto vacío o de una aplicación de consola. No aconsejo compilar códigos fuente sin tener un proyecto; siempre crea un proyecto.

Espero que esto te sirva.

Steven

jerry
2014-10-14 07:24:41

Tengo una pregunta. He seguido este curso hasta el apartado numero 5 Sentencias, y quisiera saber si se va a ensenar como intallar los softwares necesarios para empezar a hacer algunos ejercicios si es que nos va a poner ejercicios, muchas gracias de antemano.