Documentos de Académico
Documentos de Profesional
Documentos de Cultura
2
2.1 Tipos
Los diferentes valores (enteros, reales, caracteres, vectores, listas, diccionarios, etc.) que puede
manejar un lenguaje se agrupan en tipos.
Un tipo se configura a partir de:
un conjunto de valores
Por ejemplo, un conjunto formado por enteros {. . . ,-3,-2,-1,0,1,2,3,. . . }
las operaciones permitidas para esos valores
Por ejemplo, para los enteros disponemos de la suma (+), resta (-), división (/),
multiplicación (*) y resto de la división entera ( %)
una aplicación que asocia a cada valor del tipo una representación binaria
Por ejemplo, la representación binaria del valor -2 con tipo int en C/C++ es una
agrupación de 32 bits:
11111111111111111111111111111110
Usaremos habitualmente en el curso los siguientes tipos:
bool para representar valores booleanos, es decir, cierto o falso.
int para representar valores enteros.
double para valores reales.
char para caracteres.
string para cadenas de caracteres.
vector<tipo> para colecciones de datos del mismo tipo.
1
Fundamentos de Programación en C++, Curso 2020/21
2.1.1 Clasificaciones
Los comités de estandarización de cada lenguaje o diferentes autores tienen (y varían en el tiempo)
su propia terminología acerca de conceptos tales como tipo primitivo, tipo nativo, tipo básico,
tipo fundamental, tipo compuesto, tipo escalar, etc. por lo que la bibliografía es confusa y con-
tradictoria.
Una forma no bizantina de clasificarlos podría ser:
Tipos nativos, proporcionados por el lenguaje, que pueden ser simples o compuestos.
Por ejemplo, bool, char, int, float o double en C++
Tipos definidos por el programador o suministrados por una biblioteca estándar.
Por ejemplo, string o vector de la biblioteca estándar de C++
La memoria del ordenador es el almacén de los diferentes valores que se generan al ejecutar un
programa.
La memoria se organiza como un conjunto de celdas, típicamente de tamaño 1 byte, cada una de
ellas con una dirección asociada.
La dirección permite acceder a la ubicación de cada celda y es un valor en si mismo y, por tanto,
también puede almacenarse en otras celdas de la memoria.
Así, en lenguajes como C/C++ existe el tipo puntero (pointer) cuyos valores asociados
son direcciones.
El bloque de memoria necesario para almacenar un valor asociado a un tipo necesitará de una
determinada cantidad de celdas y una determinada disposición de éstas.
Por ejemplo, un char en C/C++ ocupa 1 byte y un double ocupa 8 bytes. Sin embargo,
el equivalente al double en Python, el tipo float ocupa ¡24 bytes! El motivo es que
Python no sólo almacena la representación binaria intrínseca del número, sino otra
información relevante dadas las características de este lenguaje. De esos 24 bytes, 8
bytes contendrán los mismos bits que su equivalente en C/C++.
En C++, el bloque de memoria asociado a los tipos de datos nativos está formado por celdas
contiguas.
Para otros tipos de datos y lenguajes, las celdas que conforman un bloque de memoria no tienen
por qué ser contiguas. Pueden estar distribuidas en diferentes ubicaciones de la memoria.
Por ejemplo, el tipo de dato de C++ vector<tipo>, utilizado para almacenar coleccio-
nes de valores de un mismo tipo, tiene sus atributos en posiciones no contiguas.
Incluso el tamaño del bloque de memoria asociado a un tipo puede variar.
El tipo int en Python tienen un número variable de celdas, aumentando conforme lo
hace el valor absoluto representado.
En C++ hay una clara distinción entre los tipos de datos nativos o fundamentales (int, double,
char, etc.) y otros tipos más sofisticados.
Un bloque de memoria asociado a un tipo fundamental en C++ se caracteriza por:
1. El número de celdas (bytes) que lo componen es fijo.
2. Las celdas son contiguas.
3. Hay un único valor representado, no hay información accesoria ni metadatos.
A este tipo de datos se los conoce como datos POD (Plain Old Data), tipos simples, lisos, cuya
representación interna binaria se limita a codificar el valor.
C++ permite crear por parte del usuario nuevos tipos POD como agregación de otros tipos POD.
En este caso, varía el punto 3 en el sentido de que ahora el tipo agregado representa varios valores
POD.
Las expresiones permiten combinar datos y operadores para calcular otros datos, es decir, obtener
un resultado.
Además, pueden contener palabras clave del lenguaje y signos de puntuación.
Un operador es un símbolo que determina la operación a realizar sobre los operandos (datos) a
los que afecta.
Una sentencia es un conjunto de expresiones que permiten ejecutar una determinada acción.
En C++, las sentencias simples se caracterizan por terminar con el signo de puntuación ;.
(x + 3)*2 // expresión
a > b && c < d // expresión
int x; // sentencia
y = (x + 3)*2; // sentencia
2.6 Variables
En los lenguajes de programación bajo el paradigma imperativo una variable permite asociar
(enlazar, ligar) (bind) un identificador al bloque de memoria que almacena un valor.
Este bloque de memoria, a través de la variable, se podrá modificar y/o inspeccionar.
Advertencia: Este concepto de variable es diferente al de las variables matemáticas, a las que
se las presupone un valor fijo y desconocido.
Una declaración es una sentencia que introduce el nombre o identificador de una variable en
un programa. De esta forma, el compilador conocerá respecto al identificador:
su tipo de dato
los operadores permitidos con ese valor
A efectos prácticos, en el ámbito de este curso, la declaración y definición de una variable tienen
lugar al mismo tiempo. Por ello, lo habitual en la bibliografía es hablar en términos de declarar una
variable. Veremos más adelante con las funciones que éstas se pueden declarar en una parte del
programa y definir en otra.
Tipado estático
C++ usa tipado estático, que caracteriza a aquellos lenguajes en los que el tipo asociado a una
variable debe fijarse antes de uso en las diferentes partes del programa.
El tipado estático permite comprobar en tiempo de compilación la correcta asignación de cada
variable a un determinado tipo y, en su caso, emitir los avisos y errores pertinentes.
En lenguajes como C/C++, en el ámbito (scope) en el que está definida la variable, el nombre de
la variable identifica permanentemente al bloque de memoria.
2.7 Identificadores
Los identificadores nos permiten usar fácilmente los datos que están almacenados en memoria,
despreocupándonos de su posición en memoria, su dirección.
Con objeto de aportar legibilidad a los programas, debemos usar identificadores autoexplicativos,
informando implícitamente del cometido de la variable en el programa.
Por ejemplo, queremos representar una magnitud física correspondiente a una velocidad. ¿Qué
identificador utilizar? Veamos 4 opciones:
Tienen un significado especial para el compilador. Por ello, no pueden ser utilizadas como identifi-
cadores por el programador. Forman parte del vocabulario básico del lenguaje.
Estas son algunas de las más habituales:
Palabras reservadas heredadas del lenguaje C
auto const double float int short struct unsigned break continue else for long
signed switch void case default enum goto register sizeof typedef volatile char
do extern if return static union while
Palabras incorporadas al lenguaje C++
asm dynamic_cast namespace reinterpret_cast try bool explicit new static_cast
typeid catch false operator template typename class friend private this using
const_cast inline public throw virtual delete mutable protected true wchar_t
2.7.2 Normas
Un identificador no puede tener cualquier nombre. Las normas son las siguientes:
1. Debe empezar por una letra o carácter de subrayado.
natural _var2 alumno_eii x1
A pesar de estar permitido, es recomendable no usar el subrayado al inicio, pues es utilizado
por los desarrolladores de bibliotecas y compiladores y, eventualmente, podemos generar una
colisión.
2. Las mayúsculas son caracteres distintos que las minúsculas.
interes e Interes son variables distintas.
3. No pueden utilizarse las palabras reservadas del lenguaje, como double, false, etc.
2.7. Identificadores 7
Fundamentos de Programación en C++, Curso 2020/21
El ámbito o alcance en un programa de una variable es la parte del programa donde la variable
es accesible.
Básicamente podemos dividir a las variables en función del ámbito como locales o globales.
Las variables globales son accesibles por todas las funciones desde su declaración hasta el final
del fichero.
El uso de variables globales no es aconsejable a pesar de que parezca útil y cómodo:
Disminuye la legibilidad
Su uso puede producir efectos colaterales, al producirse alteraciones no previstas de su valor
en una parte del programa que afectan a su uso en otra zona.
Dificultan la modularidad del código.
Las variables y/o funciones globales se justifican cuando se necesitan en casi todas las funciones
del programa.
Las variables std::cin y std::cout, que estudiaremos en breve, son globales).
Ejemplo de uso de variables globales
Las funciones de este programa, main() y mi_funcion(), son interdependientes. Esto es, en general,
¡una situación no deseable!
#include <iostream>
double z = 1.; // Se declara z como global.
void mi_funcion(); // Estudiaremos las funciones mas adelante
int main()
{
std::cout << z << std::endl;
z = z + 1.;
std::cout << z << std::endl;
mi_funcion(); // Funcion modifica el valor de z
std::cout << z << std::endl;
}
void mi_funcion() //Estudiaremos las funciones más adelante
{
z = z*z;
}
Advertencia: ¡En este curso no se permitirá el uso de variables globales! Veremos más adelante
una solución de compromiso, los espacios de nombres (namespaces).
Las variables locales son accesibles desde su declaración hasta el final del bloque de código del
fichero en el que han sido declaradas.
Un bloque de código viene determinado por una pareja de llaves { }.
Si el bloque donde se ha declarado la variable local contiene a su vez otros bloques, también es
accesible dentro de ellos.
En caso de que una variable aparezca declarada en varios niveles de anidamiento dentro de un
bloque, prevalece la declaración del bloque más interno.
#include <iostream>
using namespace std;
int main()
{
double z = 0.;
cout << z << endl;
{
z = z + 1.;
{
int z = 2; //Declaración local con el mismo nombre
cout << z << endl;
}
{
cout << z << endl;
}
}
}
Atención: Dada su escasa legibilidad, las declaraciones anidadas de la misma variable, como
las del ejemplo, son situaciones que nunca deberían ocurrir en un programa bien diseñado.
Las variables locales se destruyen, dejan de ser accesibles, cuando la ejecución del programa aban-
dona el bloque donde han sido declaradas.