Explora Libros electrónicos
Categorías
Explora Audiolibros
Categorías
Explora Revistas
Categorías
Explora Documentos
Categorías
1. Introducción
No tiene ejercicios.
2. Conceptos básicos
2.1) Quedaría del siguiente modo:
2.3) El programa puede parecer a primera vista muy sencillo. En primer lugar vamos a leer y escribir una
cadena. La primera solución intuitiva:
void main() {
El problema es que esto únicamente nos lee la primera palabra de una cadena (esto se explicará en el
capítulo de entrada/salida). Aunque no se comprenda de momento, la solución se encuentra en el
fichero EJ02_03.CPP
void main() {
double d1, d2;
out << "Introduce dos reales: ";
cin >> d1 >> d2;
cout << "La suma es: " << d1 + d2 << endl
}
2.6) Sí es correcta.
2.7) Este comentario es erróneo. Hemos dicho que los comentarios no se detectan en las cadenas. Pues no
es completamente cierto. No se detecta su apertura pero sí su clausura. Por ello, las sentencias se
convertirían en:
";
*/
/*
cout << "/* Me pillaste *""/"; // Concatenación de cadenas
*/
3. Tipos de datos
3.1) La función es:
int Convierte(char c) {
return int(c - '0');
}
// Usando int() en vez de (int) se ahorra un par de paréntesis
3.2) Sí que es válido ya que en C++ todos los tipos integrales son compatibles. Aunque sería mucho
mejor explicitar las conversiones:
b= (byte)w;
w= (word)l;
d= (dword)w;
4. Control de Flujo
4.1) El listado es funcionalmente correcto pero sintácticamente no. Faltan los puntos y comas de las
cuatro sentencias de asignación.
if (a < b)
if (a < c)
min= a;
else
min= c;
else
if (b > c)
min= c;
else
min= b;
4.2) Programa que cuenta el número de ocurrencias en una cadena de las 5 vocales en 5 variables
diferentes: a, e, i, o, u. Usaremos la función Leer_Cadena() del ejercicio 2.3. El programa está
en EJ04_02.CPP
for(a; b; c);
se convierte en:
{
a;
while(b) {
d;
c;
}
}
b) int i= 0, j= 0; // Correcto
// Dos declaraciones de tipo entero
while ..
4.7) En este ejercicio se ha pretendido aumentar la atención del lector en este error común y sutil pero
difícil de detectar. La condición del bucle está formada por el operador de asignación (=) y no el operador
de comparación (==), con lo que el resultado del programa es que sólo muestra un 0, ya que el resultado
de la asignación i=10, además de asignar 10 a la variable i, es que devuelve el valor 10, que es un
valor cierto, al ser no nulo. Si después lo negamos con el operador ! obtenemos falso, con lo que el bucle
sale después de la primera iteración.
5. Operadores
5.1) Es simple:
x & (x - 1)
5.3) Se supone que tenemos dos valores enteros almacenados en dos variables reales. Yo lo haría así:
float Resto(float a, float b) {
return float((long)a % (long)b);
}
5.5) Con algo parecido a esto sería suficiente para que pareciera aleatorio. Si además hacemos coincidir la
llamada a Rand() con un factor externo (tiempo, preferiblemente), esta función es casi
impredecible. El programa se encuentra en EJ05_05.CPP
6. Funciones
6.1) La solución se encuentra en el fichero EJ06_01.CPP
6.3) Es sintácticamente correcto. El compilador crea variables temporales para almacenar estas constantes
y así ya puede tomar la dirección. De todas formas no es un buen estilo de programación pasar constantes
por referencia porque aunque la función modifique su valor no nos podemos dar cuenta.
6.4) La llamada f(25) es ambigua. El compilador no sabe si llamar a la función con un argumento o
llamar a la segunda usando parámetros por defecto. La llamada f(17, 42) es completamente
correcta ya que no hay ambigüedad.
7. Variables
7.1) Las variables estáticas se inicializan a 0. Las variables automáticas no. Por tanto a valdrá 0 y b tendrá
un valor indefinido dependiendo del compilador. No se recomienda usar la declaración de 'a' de ese
modo. Es mejor explicitar:
int a= 0;
7.2) Este sería un programa que volvería loco al propio Bjarne Stroustrup:
static float f;
// Error: mismo campo.
static float s;
// Decl.4.Campo local estático. Se almac. en el s. de
datos. s vale 0
{
float f;
// Decl. 5. Campo de bloque. Se almacena en la pila
f= 2; // Accedo a la 'f' de la decl. 5
::f= 3; // Accedo a la 'f' de la decl. 1
s= 4; // Accedo a la 's' de la decl. 4
a= 5.5; // Accedo a la 'a' de la decl. 3
// No hay forma de acceder al parámetro 'f' de la función
(Decl. 2)
}
}
7.3) Como hemos visto en el caso anterior, no es correcto ya que los dos tienen el mismo campo local
automático.
7.4) Dará un error en la definición const int a ya que las constantes se deben inicializar en el
momento de la definición. Las otras dos también darían error.
sino a:
7.7) Este sería un programa que volvería loco al propio Bjarne Stroustrup:
void Funcion(float f) {
// Decl. 2. Campo local automático. Se almacena en pila
float f;
// Error: parámetros y var. locales tienen el mismo
campo
auto float a; // Este auto es opcional
// Decl.3.Campo local automático. Se almacena en pila.
a vale ?
static float f;
// Error: mismo campo.
static float s;
// Decl.4.Campo local estático.Se almac. en el s. de
datos. s vale 0
{
float f;
// Decl. 5. Campo de bloque. Se almacena en la pila
f= 2; // Accedo a la 'f' de la decl. 5
::f= 3; // Accedo a la 'f' de la decl. 1
s= 4; // Accedo a la 's' de la decl. 4
a= 5.5; // Accedo a la 'a' de la decl. 3
// No hay forma de acceder al parámetro 'f' de la función
(Decl. 2)
}
}
8. Sobrecarga y conversiones
8.1) En C++, las constantes tienen tipo por lo que el compilador asignará:
- la tercera es un char. No hay coincidencia exacta ni trivial. Pero hay promoción con int; por
tanto, se llama a Print(int ).
En general, las posibles soluciones a los problemas que aparecen (como el de la segunda llamada) son:
8.2) Sí, no hay coincidencia exacta o trivial, no hay promociones, pero hay conversión estándar
aritmética. Por tanto, se llama sin ningún problema.
8.3) No porque tomará f() como float y no como una función. Concretamente, dará un error
de llamada a no-función ("call of non-function") ya que estamos intentando llamar a un float como
si fuera una función.
8.8) Las dos primeras llamadas invocan a sus funciones correspondientes sin ningún problema. La tercera
sigue estos pasos: Primero: no hay coincidencia exacta. Segundo: no hay promoción. Tercero: conversión
estándar, pero la hay a los dos, no le damos preferencia a la que no tiene signo. Por tanto daría error de
ambigüedad.
8.12) En C++, typedef no crea tipos nuevos distintos, sólo les da un nombre diferente.
8.13) Para las cinco llamadas, el proceso es bien diferente:
1.- El literal 0.0 es un double. Pasos: Primero: coincidencia exacta. Por tanto
se llama a f(double ).
8.14) Para la primera combinación, la segunda llamda es correcta (mismo tipo), pero la primera no,
porque no hay conversión estándar desde int a enum. Como si está permitido lo contrario, la
combinación dos es perfectamente correcta. La combinación tercera también lo es, llamando cada una a
su correspondiente función.
8.15) El compilador da un error de ambigüedad, ya que no sabe si llamar a ff(fc) sin signo
o ff(fc) con signo. ¡Qué complicados son los complicadores!
9. Punteros
9.1) El primero carga en p la dirección de la variable a (p= &a), pero al cerrarse el bloque la
variable a se destruye con lo que el acceso posterior de (*p= 10) puede ser catastrófico.
El segundo programa, en cambio, funciona correctamente ya que el carácter a tratar se almacena en
el 'heap' y no en la pila, así al cerrar el bloque no destruimos ninguna variable ya que no hemos definido
ninguna tampoco. El acceso (*p= 10) será válido hasta que pongamos (delete p;).
void main() {
char *p;
int a;
{
p= &a;
}
*p= 10;
}
9.6) Ese programa es muy peligroso. Leemos una cadena en s, pero s apunta a una dirección
indefinida; por ello, podemos estar estropeando código, datos de nuestro o de otro programa. Además no
se puede asegurar que la salida sea igual que la entrada. En fin, que este es uno de los errores más graves
y típicos del C++. Además, puede que en un primer momento funcione. Más tarde el error aparecerá
inesperadamente de forma catastrófica. La solución es reservar la memoria que vamos a usar:
#include <iostream.h>
void main() {
char s[100];
// Suponemos que con 100 caracteres es suficiente
cin >> s;
cout << s;
}
#include <iostream.h>
void main() {
char *s;
s= new int[100];
cin >> s;
cout << s;
delete []s;
}
9.7) No ocurre nada, al final del programa el compilador se encarga de hacer todos los delete que falten.
De todas formas, es muy recomendable no olvidarse de ponerlo porque si es en una función que se llama
1000 veces acabaremos con el 'heap' lleno!. Tampoco es muy recomendable hacer lo que se ha hecho en
el ejercicio 1, pero a veces como en ese ejercicio, es necesario.
9.8) Para hacer lo que se nos pide en el ejercicio habría que hacer uso de punteros:
float f;
int *pi= (int *)&f;
char *pc= (char *)&f;
Y con f, *pi, *pc accederíamos a lo mismo que con la unión: f, i, c. Claramente, usar
una unión anónima es más limpio aunque con punteros se ve físicamente que comparten la misma
memoria. En este caso, trabajar con punteros puede ser peligroso, ya que si tenemos:
char c;
int *pi= (int *)&c;
float *pf= (float *)&c;
un acceso a (*pi) a (*pf) excedería del tamaño del carácter, estropeando lo que hay después en
memoria, que en este caso es el puntero que accede. Aquí, se puede decir, que está casi asegurado que el
sistema se quede bloqueado o lo que en el argot se conoce como "colgado".
9.9) El programa compara los punteros, no donde apuntan. Si lo sustituyéramos por(*s == *t)
tampoco ya que sólo compararía el primer elemento. Queda como ejercicio hacer una función que
compare cadenas. En el siguiente capítulo también se verán algunas funciones de comparación.
#include "iostream"
int main()
{
//Se muestra un mensaje por pantalla.
cout << "Hola Mundo" << " Desde AAP." << endl;
return 0;
}
#include "iostream"
#include "string"
int main()
{
string salida1 = "Ejemplo de salida"; //El valor de esta variable se mostrará en
pantalla
int numero = 2; //Este valor también se mostrará en pantalla.
string salida2 = "Desde AAP."; //Estos valores se concatenarán en una única salida
return 0;
}
En este ejemplo de salida por pantalla hemos visto
que también es posible usar la instrucción cout para
mostrar en pantalla el valor de las variables así sean
numéricas o cadenas de texto. También vimos que
podemos concatenar los valores de esas variables
entre sí y también concatenarlas con otros valores
directamente (espacios, puntos, símbolos, etc.).
Ya tenemos claro cómo mostrar texto por pantalla en
C++ ahora haremos uso de este concepto y veremos
cómo leer texto por teclado en C++. Veamos:
Entrada o lectura de datos en C++
Tal como mencioné hace un momento, la lectura de
datos en C++ es bastante simple. Leer datos por
teclado en C++ se hace usando el comando cin
>> es importante notar el uso de los dos
signos >> que son usados para controlar el flujo de
datos. No te preocupes mucho por ellos, solo ten en
cuenta que cada vez que vaya a usar la
instrucción cin debes agregarle >> para quedar con
un cin>>. Una manera muy sencilla de recordar esta
instrucción es que in significa entrar y como estamos
programando en C++ le añadimos la letra C al
comienzo quedando así cin>> (sin olvidar los >>).
Veamos unos ejemplos simples para leer datos en
C++. Recuerda como dije más arriba que lo ideal
para leer datos es indicarle al usuario qué es lo que
esperamos que ingrese por lo que en estos ejemplos
usaremos también lo recién aprendido (mostrar texto
por pantalla).
Ejemplo 1 de lectura de datos en C++
#include "iostream"
#include "string"
int main()
{
cout << "Hola! Este es un ejemplo en C++" << "\n" << "Por favor ingrese su
nombre:" << endl; //La instrucción \n es un salto de línea Mostrando los textos
separados
cout << "Bienvenido al sistema " << nombre << ". Gracias por usar nuestra
aplicación" << endl;
return 0;
}
#include "iostream"
#include "string"
int main()
{
cout << "Hola! Aqui podras realizar sumas" << endl;//Mensaje de bienvenida
float numero1, numero2; //Se declaran los números que se sumarán (pueden ser
decimales)
cout << "Por favor ingrese el primer valor: " << endl; //Se pide el primer numero
cin >> numero1; //Se asigna el primer valor a numero1
cout << "Por favor ingrese el segundo valor: " << endl; //Se pide el segundo numero
cin >> numero2; //Se asigna el segundo valor a numero2
cout << "El resultado de la suma de " << numero1 << " + " << numero2 << " es: " <<
numero1+numero2 << endl; //Se muestra el resultado.
return 0;
}