Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Libro Sintaxis C PDF
Libro Sintaxis C PDF
30 de noviembre de 2012
Esta obra está bajo una licencia Reconocimiento-NoComercial-CompartirIgual 3.0 Un-
ported de Creative Commons: No se permite un uso comercial de la obra original ni
de las posibles obras derivadas, la distribución de las cuales se debe hacer con una li-
cencia igual a la que regula la obra original. Para ver una copia de esta licencia, visi-
te http://creativecommons.org/licenses/by-nc-sa/3.0/deed.es_ES o envie una carta a
Creative Commons, 171 Second Street, Suite 300, San Francisco, California 94105, USA. ía. inclu-
ye
II Introducción a C/C++ 3
1. Sintaxis básica 4
1. El preprocesador de C/C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2. Palabras reservadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3. Literales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4. Identificadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
5. Expresiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
6. Tipos predefinidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
7. Definición de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
8. La asignación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
9. Bloque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
10. Sentencias de selección . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
11. Sentencias de repetición . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
12. Subprogramas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
12.1. Procedimientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
12.2. Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
12.3. Parámetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
13. Tipos definidos por el programador . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
13.1. Registros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
13.2. Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
13.3. Anidamientos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
B. Bibliotecas estándares de C 27
1. Entrada/salida . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2. Clasificación de caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3. Matemática . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4. Utilidades estándares . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
2
Parte II
Introducción a C/C++
3
Capítulo 1
Sintaxis básica
1. El preprocesador de C/C++
El preprocesador de C/C++ examina el código fuente y lo modifica antes de ser compilado.
Busca líneas o directivas que empiezan con el carácter ‘#’ en la primera columna. La mayoría de
estas directivas sirve para compilar (o no) selectivamente trozos del código fuente.
Una de las más utilizadas es la directiva de inclusión de ficheros, include y se utiliza para
incluir ficheros, bien ubicados en directorios estándares poniendo entre <> el nombre del fichero:
#include <fichero>
o bien ubicados en directorios no estándares, poniendo entre comillas dobles el nombre de fichero
y empezando el camino en el directorio actual:
#include "fichero"
Otra de las directivas del preprocesador más utilizadas es define, la cual sustituye todas las
ocurrencias de una cadena abreviada en el código fuente por otra más compleja de escribir.
#define cadena_abreviada cadena_compilada
El uso de define es más general y admite incluso argumentos en la cadena abreviada para
utilizarla a modo de función o macro.
2. Palabras reservadas
Son las palabras clave que permiten construir la estructura sintáctica de C y C++ y no
necesitan definirse porque el compilador ya conoce su significado:
4
Capítulo 1. Sintaxis básica 5
3. Literales
Son las constantes sin nombre, tanto numéricas como textuales, que no necesitan ser definidas.
Los caracteres van entre comillas y los números no. Además, los números pueden llevar sufijos
para indicar el tipo de dato que es:
Números naturales: 1452, 12345u, 123456789ul.
Números enteros: 1452, -325, 123456789l.
Números en base octal: 0166, 0777.
Números en base hexadecimal: 0x1a, 0X1A.
Números reales en coma fija de doble precisión: 1.4.
Números reales en coma fija de simple precisión: 1.4f.
Números reales en coma fija de gran precisión: -4.2L.
Números reales en coma flotante: -4e2, 3e-5, 12e-9L.
Caracteres simples imprimibles: 'a', '+', '&'.
Caracteres ascii especificados con su código en octal: '\017'.
Caracteres ascii especificados con su código en hexadecimal: '\x2c'.
Cadenas de caracteres: "Si es una cadena, las comillas son dobles.".
Cadena de caracteres vacía: "".
La tabla 1 muestra algunos caracteres no imprimibles que en C/C++ se pueden escribir como
secuencias de escape.
5
Capítulo 1. Sintaxis básica 6
4. Identificadores
Un identificador es una palabra que no es reservada, tiene un máximo de 32 caracteres, comien-
za por una letra y va seguida de letras, dígitos o el carácter subguión ‘_’. Así son identificadores:
dato, dato1, dato2000, Pi_Al_Cuadrado, Pi_doble,
pero no son identificadores:
50_Al_Cuadrado, 5por15, variable.entera, constante K (con el espacio en
blanco), while.
5. Expresiones
C y C++ admiten distintos tipos de expresiones combinadas con distintos tipos de operadores.
Pueden ser textuales, numéricas y lógicas. En general, las expresiones de distinto tipo no pueden
mezclarse para no violar las llamadas reglas de compatibilidad de tipos, las cuales, por ejemplo, no
permiten mezclar caracteres con números o números con expresiones lógicas.
Expresiones de caracteres
Los operandos básicos son literales, constantes simbólicas o variables de tipo carácter. Las
llamadas a funciones que devuelven caracteres también son expresiones de caracteres. Con los
caracteres simples en general no se opera, pero en C++ (no en C) podemos comparar las cadenas
de caracteres con los operadores relacionales <, >, <=, >=, == y !=, y también podemos unirlas con
el operador de concatenación +, es decir, la expresión "Hola, " + "que tal!" nos produce
"Hola, que tal!".
Expresiones numéricas
Los operandos básicos son literales, constantes simbólicas o variables de tipo numérico. Estas
expresiones se forman combinando operandos numéricos con los operadores aritméticos +, -, *, /, %
y los paréntesis (). Pueden contener llamadas a funciones que devuelvan valores numéricos como
sqrt(), sin(), floor()... definidas en la biblioteca matemática estándar (véase el apéndice B).
Expresiones lógicas
Son expresiones que devuelven true o false, llamadas de tipo lógico. Pueden ser variables,
constantes simbólicas o llamadas a funciones que devuelvan valores de tipo lógico. Las compara-
ciones formadas con los operadores relacionales <, >, <=, >=, == y != también son expresiones de
tipo lógico, aunque sus operandos pueden ser de cualquier tipo cuyos dominios estén ordenados,
como los números o los caracteres.
Las expresiones lógicas pueden agrupar subexpresiones lógicas con los operadores lógicos de
conjunción, &&, disyunción, ||, o negación, !, y los paréntesis.
Precedencia de operadores
Siempre que no se violen las reglas de compatibilidad de tipos, en una expresión pueden aparecer
distintos tipos de operadores, los cuales se operan en el orden que indiquen los paréntesis escritos
en la expresión y según el orden que les corresponda por su precedencia. La tabla 2 muestra
la precedencia de operadores de mayor a menor prioridad. En general, los aritméticos son más
prioritarios que los comparativos, y éstos a su vez son más prioritarios que los lógicos. Nótese, no
obstante, la alta prioridad del operador lógico de negación !.
6
Capítulo 1. Sintaxis básica 7
Conversiones de tipos
C/C++ realiza las siguientes conversiones de tipos implícitas:
Cuando se mezclan operandos numéricos enteros y/o reales en una expresión, el tipo de la
expresión se promociona al más preciso y/o al de mayor tamaño.
Cuando una expresión de tipo numérico se asigna a una variable del mismo tipo pero de
menor precisión, la expresión se convierte al tipo de la variable destino, perdiéndose la
precisión.
Los caracteres en realidad se almacenan con su código ascii, por lo que C/C++ los admiten
en expresiones de tipo entero, pero no es recomendable mezclar caracteres con números.
Aunque las expresiones enteras utilizadas como expresiones lógicas es un concepto herededa-
do de C, tanto en C como en C++ pueden emplearse expresiones enteras en las condiciones,
considerándose falso el valor 0, y verdadero cualquier valor distinto de 0.
Por otro lado, son posibles las conversiones de tipo explícitas que tengan sentido. Para ello, en
las expresiones se puede utilizar el llamado cast con el nombre de tipo destino entre paréntesis al
estilo C:
(tipo) expresion
6. Tipos predefinidos
Los tipos predefinidos son los tipos carácter o numéricos simples, también llamados escalares.
Aunque no se considera escalar, en C++ se puede utilizar también como predefinido el tipo cadena,
string. Sus dominios están ordenados, por lo que puede utilizarse los operadores relacionales con
cualquiera de ellos. Por otro lado, el tipo lógico es un tipo simple y predefinido en C++, pero no
existe en C.
Todos los tipos predefinidos, a excepción de los numéricos de tipo real, son ordinales porque
cada valor tiene un sucesor y un predecesor únicos (excepto el primer y último valor, lógicamente).
Las cadenas, al no ser escalares, tampoco se consideran ordinales.
7
Capítulo 1. Sintaxis básica 8
La tabla 3 muestra los tipos predefinidos indicando si almacenan signo y sus variantes según
su tamaño. La función predefinida sizeof(tipo) puede utilizarse para determinar el tamaño
en bytes de un determinado tipo.
Caracteres char
(ordinales) unsigned char
Cadenas de caracteres string
(no escalares) (Sólo en C++)
Números naturales unsigned short [int]
(ordinales) unsigned int
unsigned long [int]
unsigned long long [int]
Números enteros short [int]
(ordinales) int
long [int]
long long [int]
Números reales: float
(no ordinales) double
long double
Valores lógicos: bool
(ordinales: false<true) (Sólo en C++)
Tabla 3: Tipos predefinidos en C/C++ (los corchetes no se escriben, indican lo que es opcional).
7. Definición de datos
Variables
Todas las variables deben definirse antes de ser usadas. Tienen alcance de bloque (block scope),
por lo que sólo pueden utilizarse dentro del bloque donde se definen (véase sección 9 más adelante).
Pueden definirse sin inicializar:
tipo identificador;
La expr_constante puede ser un literal, una constante simbólica o una expresión constante
previamente definida que sea compatible con el tipo de la variable.
Constantes simbólicas
Las constantes simbólicas son constantes con un nombre. En C++ se definen con la palabra
reservada const seguida del tipo:
const tipo identificador = expr_constante;
donde la expr_constante puede ser un literal o bien otra constante simbólica previamente
definida que sea de tipo compatible. En C se suele utilizar la directiva define del preprocesador,
la cual no asigna ningún tipo a la constante ni tampoco le reserva memoria porque es una simple
sustitución que realiza el preprocesador previa a la compilación:
#define identificador constante
8
Capítulo 1. Sintaxis básica 9
8. La asignación
Es la sentencia de transferencia de datos por excelencia en C/C++. Su sintaxis es la siguiente:
valorL = valorR;
Cuando el valorL es una expresión que no referencia una posición de memoria, es típico el
siguiente mensaje o alguno similar con el que responden los compiladores o alguno similar:
error: lvalue required as left operand of assignment
E/S básica
En C++ se utiliza la biblioteca estándar moderna <iostream>:
#include <iostream>
using namespace std;
...
cout << expresion << expresion << ...; // salida
cin >> variable >> variable >> ...; // entrada
Los tipos de las expresiones y variables pueden ser cualesquiera de los predefinidos, incluyendo
cadenas de caracteres. En el caso de la lectura de cadenas, sólo se lee hasta el primer blanco
(espacio, tabulador o carácter de fin de línea).2
En C sólo podemos utilizar la biblioteca tradicional <stdio.h>: 3
#include <stdio.h>
...
printf("formato", expresion, expresion, ...); // salida
scanf("formato", & variable, & variable, ...); // entrada
Nótese en ambos casos que la entrada debe producirse siempre sobre variables o valoresL que
hagan referencia a una posición de memoria donde se pueda guardar el valor que entra. El valor
de salida en cambio puede ser cualquier expresión o valorR.
1 La L y la R vienen del inglés, left y right, por estar a la izquierda y a la derecha del operador = respectivamente.
2 Para leer una línea completa, utilícese la función getline de la biblioteca (ver sección A).
3 Véase algún libro de programación en C para más información.
9
Capítulo 1. Sintaxis básica 10
9. Bloque
Agrupación de sentencias entre llaves {} que pueden incluso anidar otros bloques. Suelen
formar parte de las sentencias de control de flujo.
{
sentencias
{ // bloque anidado
sentencias
}
sentencias
}
}
if (condicion) {
sentencias
}
else if (condicion) { // opcional
sentencias
}
else if (condicion) { // opcional
sentencias
}
...
else { // opcional
sentencias
10
Capítulo 1. Sintaxis básica 11
sentencias;
break;
sentencias;
break;
...
default:
sentencias;
Bucles pre-test
while (condicion) {
sentencias
sentencias
11
Capítulo 1. Sintaxis básica 12
La primera expresion del for sólo se ejecuta una vez antes de empezar el bucle. La condición
se evalúa justo antes de cada iteración. Y la última expresión se ejecuta después de cada iteración
completa, justo antes de la siguiente evaluación de la condición de control.
El bucle for es más adecuado cuando existe una variable de control clara de la que depende
la terminación.
Bucle post-test
En los bucles post-test la condición se evalúa después de cada iteración, por lo que al menos
siempre se ejecuta el cuerpo del bucle una vez.
do {
sentencias
} while (condicion);
12. Subprogramas
Los subprogramas permiten ejecutar bloques de sentencias que se definen una sola vez en
el programa, pero que pueden llamarse múltiples veces con diferentes datos o parámetros. Es-
tos parámetros pueden ser de entrada, cuando suministran información al subprograma llamado
para realizar sus cálculos, o pueden ser de salida si devuelven información que ha calculado el
subprograma. También pueden ser de entrada-salida.
Los parámetros que aparecen dentro del subprograma se llaman formales, o fictíceos 4 , mientras
que los que aparecen en las llamadas son los parámetros reales. Esto es así porque los parámetros
de los subprogramas no están en memoria hasta que cobran vida cuando son llamados y sustituidos
por los reales, que ya existen en memoria. Al terminar el subprograma, los parámetros fictíceos
desaparecen de la memoria del proceso.
Cada parámetro formal definido en la cabecera del subprograma especifica el tipo del corres-
pondiente parámetro real que debe aparecer en la llamada en el mismo orden, de tal manera que
el tipo del parámetro real debe ser compatible con el que indica el parámetro formal.
En general, en los lenguajes de programación existen dos tipos de subprogramas: los procedi-
mientos, cuyas llamadas representan una acción; y las funciones, cuyas llamadas representan un
valor y tratan de simular el comportamiento de una función matemática.
12.1. Procedimientos
Los procedimientos no devuelven nada como valor de función por lo que no actúan como las
típicas funciones matemáticas, y la información de salida la devuelven siempre en parámetros de
salida o por algún dispositivo de salida como la pantalla. Antes de realizarse llamadas, hay que
definir el procedimiento como se muestra a continuación:
4 En inglés dummy arguments.
12
Capítulo 1. Sintaxis básica 13
sentencias
12.2. Funciones
Las funciones son subprogramas que pueden simular las llamadas a las típicas funciones mate-
máticas, ya que devuelven el valor que toma la propia función a través de la sentencia return, la
cual debe aparecer al menos una vez dentro del subprograma, y preferentemente una sola vez al
final. En la definición debe especificarse el tipo del valor devuelto, tal como se indica a continuación:
tipo Identificador(definicion param_formal1,
definicion param_formal2, ...)
{
sentencias
Antes de evaluar la función se evalúan sus argumentos, y la función se evalúa antes que la
expresión donde aparece la llamada.
12.3. Parámetros
Ya hemos dicho que los parámetros puede ser de entrada o salida según la dirección hacia donde
fluya la información. Los parámetros de entrada deben estar inicializados antes de la llamada, ya
que es información de entrada al subprograma. Los parámetros de salida deben modificarse al
menos una vez dentro del cuerpo del subprograma, ya que es la información que generará el
subprograma. Los parámetros de salida no necesitan ser inicializados antes de realizar la llamada,
pero los de entrada-salida sí.
Puesto que los parámetros de salida y de entrada-salida van a contener la información generada
por el subprograma después de la llamada, el parámetro real de la llamada debe ser una variable
o valorL que haga referencia a una posición de memoria donde se guardará el resultado. Se dice
que se pasan por referencia. La definición del parámetro formal utiliza el carácter ‘&’ detrás del
tipo:
tipo Subprograma( ..., tipo & param_formal, ...)
Sin embargo, los parámetros reales de entrada pueden ser cualquier expresión compatible con
el correspondiente parámetro formal. En realidad, se crea una copia nueva del parámetro real, ya
que el original no es necesario modificarlo. Se dice que se pasa por valor. Aunque no es obligatorio,
es conveniente poner el calificador const delante del tipo en la definición del parámetro formal
13
Capítulo 1. Sintaxis básica 14
para que el compilador avise cuando se modifique un parámetro de entrada, lo que normalmente
no es necesario5 :
tipo Subprograma( ..., const tipo param_formal, ...)
13.1. Registros
Un registro es una colección heterogénea (de tipos distintos) de variables o campos que se
acceden con el nombre común de todo el registro y un nombre único que identifica el campo
dentro del registro. El tipo de cada campo puede ser cualquiera.
La definición de un tipo registro se hace con la sentencia typedef utilizando además la palabra
reservada struct propia de los registros. A continuación y entre llaves {} se define cada campo
con su tipo como si fueran variables locales al registro.
// definicion del tipo registro
typedef struct {
int dni;
string nombre;
string domicilio;
float estatura;
float peso;
} TPersona; // nombre del tipo nuevo
Una vez definido el tipo registro, la definición de variables registro es similar a la habitual,
pudiéndose inicializar incluyendo entre { } los valores de cada campo separados por comas:
5 Siempre se puede definir y copiar su valor en una variable local del mismo tipo.
14
Capítulo 1. Sintaxis básica 15
// definicion de 3 registros
TPersona empleado, directivo, becario;
Y la definición de registros constantes es muy parecida a la de los registros variables, pero con
la palabra reservada const, que evita su posterior modificación:
const TPersona DomenicoEscarlati = {
31283130,
"Domenico Escarlati Perolo",
"C/ Brieva del Verano, 31, Messina",
1.70,
72.2,
};
Los campos de los registros se pueden utilizar exactamente igual que las variables del mismo
tipo. Se acceden con el nombre común del registro, el operador de acceso ‘.’ y el nombre del campo
sin dejar espacios en blanco entre ellos:
maquinista.dni = 87654321;
maquinista.nombre = "Juanito Cigarra";
if (empleado.peso < 100) ...
return maquinista.estatura;
// definicion de 3 registros
DatosPersona empleado, directivo, becario;
Pero no se puede:
15
Capítulo 1. Sintaxis básica 16
13.2. Arrays
Un array es una colección homogénea de datos o componentes de un mismo tipo base con un
nombre común, y colocadas consecutivamente en memoria ordenadas por un índice, de tal forma
que cada valor del array se identifica de forma única con el nombre del array y por su índice. En
C/C++ la primera posición es siempre la 0.
El siguiente esquema muestra el contenido en memoria de un array de 10 enteros con el índice
de cada posición debajo.
-12 1 55 0 -54 72 -6 -88 523 32
0 1 2 3 4 5 6 7 8 9
Al igual que con los registros, para utilizar arrays primero hay que definir el tipo array. Después
se definirán todos los arrays que se vayan a utilizar como variables, ya que el tipo no especifica ni
reserva ninguna posición de memoria, sino sólo la estructura de una variable de tipo array. En la
definición del tipo array, además de indicar el tipo base, hay que indicar la longitud máxima en
tiempo de compilación, es decir, esta longitud debe ser una expresión constante, por lo que son
estructuras estáticas 6 .
En estas notas vamos a trabajar con los nuevos arrays que incorpora el estándar de C++ 20117 .
La diferencia fundamental con los arrays tradicionales es que los nuevos permiten la asignación
completa de dos arrays, mientras que esto no era posible con los arrays tradicionales de C/C++.
Definición de arrays
Los tipos array se definen con la sentencia typedef, normalmente como una definición global.
A continuación se definen los arrays que se necesiten, que ya sí son datos reales en memoria, y
suelen definirse como variables locales o constantes simbólicas.
El tamaño máximo de un array ya definido puede obtenerse con la función size() en número
de elementos, o con la función sizeof en número de bytes, tal como se muestra en el siguiente
ejemplo. Nótese la diferencia en la notación entre ambas funciones, ya que la primera es una
función de biblioteca, y la segunda es propia de C/C++.
6 Existen también en C++ arrays dinámicos que permiten indicar la longitud en tiempo de ejecución usando el
operador new.
7 Es posible que se necesite activar la correspondiente opción al compilar, -std=c++0x.
16
Capítulo 1. Sintaxis básica 17
int main()
{
TZs array1; // variable array sin inicializar
TZs array2 = {0,1,2}; // inicializadas solo 3 primeras posiciones
...
cout <<"Numero de elementos: " <<array1.size() <<endl;
cout <<"Numero de bytes: " <<sizeof(array1) <<endl;
...
El índice puede ser cualquier expresión entera, pero ¡ojo! el resultado debe estar
dentro del rango de valores que admita la longitud del array.
Una alternativa para acceder a elementos de un array chequeando el rango de errores es con el
operador at: a.at(0), a.at(1), a.at(2)... Esta alternativa sí chequea los errores de rango.
Con una componente individual se puede realizar todas las operaciones que admita el tipo
base, por ejemplo, si el tipo base es int, los componentes se pueden sumar, comparar, asignar,
pasar como parámetros, leer de teclado, etc.
2011 permite también el paso por valor para crear la copia del parámetro real en el parámetro formal. No obstante,
es más eficiente pasar un array de entrada por referencia constante.
9 La asignación es la que también posibilita la devolución completa de un array como valor de una función.
17
Capítulo 1. Sintaxis básica 18
cin >>numero;
while (nleidos<MaxZs && numero!=0) {
// 0 es el centinela, no se almacena
a[nleidos] = numero;
cin >>numero;
nleidos++;
}
return nleidos;
}
/*
* Paso de un array (por ref. cte.) como parametro de entrada.
* Escritura en pantalla de los n primeros elementos de un array.
*/
void EscribirZs(const TZs &a, const int n)
{
int i;
// n debe ser menor que MaxTZs
for (i=0; i<n; i++) {
cout<< a[i]<< ’ ’;
}
cout <<endl;
}
/*
* Devolucion de un array como valor de una funcion.
* Suma de dos arrays componente a componente.
*/
TZs SumarZs(const TZs &a1, const TZs &a2, const int n)
{
TZs suma; // para devolver en el return
int i;
// n debe ser menor que MaxTZs
for (i=0; i<n; i++) {
suma[i] = a1[i] + a2[i];
}
return suma;
}
18
Capítulo 1. Sintaxis básica 19
/*
* Paso de un array (por referencia) como parametro de e/s.
* Invertir los n primeros elementos de un array.
*/
void VoltearZs(TZs &a, const int n)
{
int i=0, temp;
// n debe ser menor que MaxTZs
// si n es impar, el elemento central no hace falta moverlo
for (i=0; i<n/2; i++) {
temp = a[i];
a[i] = a[n-i-1];
a[n-i-1] = temp;
}
}
/*
* Suma 3 series de numeros enteros.
* Despues se invierten los componentes de las 2 primeras.
*/
int main()
{
TZs serie1, serie2, suma;
int long1, long2, long_menor;
// una de las series es un array constante
const TZs serie3 = { 1, 1, 1, 1, 1};
const int long3 = 5;
19
Capítulo 1. Sintaxis básica 20
Arrays multidimensionales
Puesto que el tipo base de un array puede ser cualquiera, cada componente puede ser a su vez
otro array, con lo que tendríamos un array bidimensional. Las definiciones siguientes definen un
tipo para matrices no necesariamente cuadradas. Observa que el tipo base del tipo TMatriz es
un array vector fila.
// dimensiones de la matriz
const unsigned NE = 2; // numero de columnas
const unsigned NF = 3; // numero de filas
typedef array <float,NE> TFila;
typedef array <TFila,NF> TMatriz;
Los siguientes subprogramas ilustran un manejo básico de suma de matrices. Por supuesto,
para acceder ahora a una posición individual se necesita especificar un índice por cada una de las
2 dimensiones.
/*
* Lectura de una matriz completa por teclado.
* Se pasa la matriz como parametro de salida.
*/
void LeerMatriz(TMatriz &m)
{
int j, k;
for (j=0; j<NF; j++) {
for (k=0; k<NE; k++) {
cin >>m[j][k];
}
}
}
/*
* Escritura en pantalla de una matriz completa.
* Se pasa la matriz como parametro de entrada.
*/
void EscribirMatriz(const TMatriz &m)
{
for (int j=0; j<NF; j++) {
for (int k=0; k<NE; k++) {
cout <<m[j][k] <<’ ’;
}
cout <<endl;
}
}
20
Capítulo 1. Sintaxis básica 21
/*
* Suma de 2 matrices elemento a elemento.
* Se pasan las matrices como parametro de entrada y el resultado
* se devuelve como valor de la funcion.
*/
TMatriz SumarMatrices(const TMatriz &m1, const TMatriz &m2)
{
TMatriz suma;
int j, k;
for (j=0; j<NF; j++) {
for (k=0; k<NE; k++) {
suma[j][k] = m1[j][k] + m2[j][k];
}
} return suma;
}
/*
* Suma de 2 matrices elemento a elemento.
* El primer parametro es de entrada/salida: la matriz original.
* El segundo parametro es de entrada y se suma a la original.
*/
void AcumularMatriz(TMatriz &original, const TMatriz &m)
{
for (int j=0; j<NF; j++) {
for (int k=0; k<NE; k++) {
original[j][k] += m[j][k];
}
}
}
/*
* Suma de 3 matrices elemento a elemento.
* Las 2 primeras se suman con SumarMatrices(), y
* la 3ra. se suma con AcumularMatriz().
*/
int main()
{
TMatriz msuma, m1, m2;
const TMatriz m3 = {10, 10, 10, 10, 10, 10}; // esta no se lee.
21
Capítulo 1. Sintaxis básica 22
El siguiente ejemplo ilustra la suma de tensores, los cuales pueden representarse con arrays
tridimensionales, donde el tipo base de cada componente es una matriz. Nótese que se puede
reutilizar algunos de los subprogramas de matrices definidos en el ejemplo anterior.
// dimensiones del tensor
const unsigned NE = 2; // numero de columnas
const unsigned NF = 3; // numero de filas
const unsigned NC = 2; // numero de capas
typedef array <float,NE> TFila;
typedef array <TFila,NF> TMatriz;
typedef array <TMatriz,NC> TTensor;
int main()
{
TTensor t1, t2, tsuma;
const TTensor t3 = {1,1, 2,2, 3,3, 4,4, 5,5, 6,6};
22
Capítulo 1. Sintaxis básica 23
Cadenas
En C++ existe la clase string que se puede utilizar como tipo de datos para almacenar
cadenas de caracteres. Está definida en la biblioteca estándar <string> que además dispone de
muchas funciones para realizar operaciones con cadenas sin tener que programarlas. Las cadenas
de tipo string pueden asignarse, pasarse como parámetros por valor y por referencia, y pueden
devolverse como valor de una función.
En la sección 3 del anexo puede consultarse algunas de las funciones habituales que ofrece esta
clase. En este caso las cadenas son objetos y la sintaxis para las llamadas utilizan el operador ‘.’
como si el objeto (la cadena) fuese un registro.
13.3. Anidamientos
Tanto el tipo base de un array, como el de los campos de un registro pueden ser de tipo com-
puesto, posibilitando la definición y uso de muchos tipos de estructuras de datos. A continuación
se muestran dos posibilidades habituales.
Anidamientos dentro de registros. En estos casos el tipo de uno de los campos es otro tipo
compuesto previamente definido.
typedef struct {
dia, mes, anio;
} TFecha; // definicion del tipo TFecha
typedef struct {
int dni;
string nombre;
string domicilio;
TFecha f_nacim;
float estatura;
float peso;
} TJugador; // definicion del tipo TJugador
// accesos posibles
... delantero.nombre ... // nombre del delantero
... delantero.f_nacim ... // registro con fecha de nacimiento
... delantero.f_nacim.dia ... // dia de nacimiento del delantero
... delantero.f_nacim.mes ... // mes de nacimiento del delantero
Anidamientos dentro de arrays. Aquí simplemente se pone como tipo base del array otro
tipo compuesto previamente definido.
// accesos posibles
... visitante[0].nombre ... // nombre primer jugador visitante
... visitante[0].f_nacim ... // fecha de nacimiento completa
... visitante[i].f_nacim.anio ... // nacimiento del jugador i
...
23
Apéndice A
1. Entrada/salida
En C++ la escritura en pantalla y lectura de teclado se manejan con los flujos estándares
de entrada/salida, que son objetos, y como tales, las llamadas a sus operaciones (o métodos) se
realizan con el operador de acceso ’.’.
El flujo estándar de entrada es cin y, por defecto es el teclado, aunque desde el sistema
operativo (sin modificar el programa) puede redirigirse a un fichero o a otro dispositivo. Los flujos
de salida son cout, que es la salida estándar, y cerr, que es la salida de errores. Al igual que el
flujo de entrada, ambos pueden redirigirse desde el sistema operativo de forma separada.
#include <iostream>
Entrada de números o caracteres saltando espacios precedentes:
cin >> variable >> variable >> ...
Salto de los espacios pendientes de leer:
cin >> ws
Lectura de un carácter sin saltar espacios:
char c = cin.get()
Lectura de una línea completa en un array de un máximo de max caracteres:
getline(cin, cad)
cin.getline(cad)
cin.getline(cad, max)
Salida de números o caracteres:
cout << expresion << expresion << ...
cerr << expresion << expresion << ...
Vaciado de la salida pendiente:
cout << flush
cerr << flush
Envío a la salida de un salto de línea:
cout << endl
cerr << endl
2. Ficheros
En C++ los ficheros se consideran flujos (stream) como los flujos estándares cin y cout, por
lo que su manejo es muy similar a éstos.
24
Apéndice A. Bibliotecas estándares de C++ 25
#include <fstream>
Definición de flujos
ifstream fi fichero de entrada
ofstream fo fichero de salida
fstream f fichero de entrada/salida
Apertura y cierre de flujos
fi.open("nombre.dat") modo de entrada
fo.open("nombre.dat") modo de salida
f.open("nombre.dat", ios::in) modo de entrada
f.open("nombre.dat", ios::out) modo de salida
f.open("nombre.dat", ios::binary) modo binario
fo.open("nombre.dat", ios::app) modo salida para añadir al final
f.open("nombre.dat", ios::in|ios::out) modo de entrada/salida
f.close() cierre del flujo f
Lectura y escritura en flujos
f >> variable >> variable >> ... lectura del flujo f
f.get(c) lectura de un carácter
f.getline(cadena, tam) lectura de una línea f
(máximo tam caracteres)
f << expresion << expresion << ... escritura en el flujo f
25
Apéndice A. Bibliotecas estándares de C++ 26
3. Cadenas
En C++ las cadenas pueden manejarse como arrays de caracteres al estilo de C, o como objetos
de la clase string. En particular, los siguientes ejemplos dan una idea de la potencia de la clase
string de C++.
#include <string>
Definición
string s, s1, s2 Define las cadenas s, s1 y s2.
string s2="vinicial" Define la cadena s2 y la inicializa.
string s(s2) Define la cadena s y la inicializa con s2.
Entrada/salida
cin >> s Lee una cadena de teclado en s saltando los espacios.
getline(cin,s) Lee una línea de teclado en s.
cout << s Imprime en pantalla s.
Longitud y acceso individual
s.length() Devuelve la longitud efectiva (tipo int) de s.
c = s[0] Pone en la variable c (char) el primer carácter de s.
c = s[s.length()-1] Pone en c el último carácter de s.
Asignación
s = "valor" Asigna la cadena valor a s.
s[i] = c Pone en s[i] el carácter c.
s = s2 Asigna la cadena s2 a s.
s += s2 Concatena la cadena s2 al final de s.
s = s1 + s2 Asigna a s la concatenación de s1 y s2.
s.append(s1+s2) Añade a s la concatenación de s1 y s2.
Comparaciones
s == s2 Devuelve true si s y s2 son iguales.
s < s2 Devuelve true si s es menor que s2 por orden ascii.
r = s.compare(5,3,s2) Pone en r (int) el valor 0 si s==s2, -1 si s<s2, y +1 si s>s2.
Búsqueda y sustitución
pos = s.find(s2) Devuelve la posición (int) donde empieza la subcadena s2 dentro
de s.
s2 = s.substr(5,3) Devuelve en s2 la subcadena de 3 caracteres de s que empieza en
la posición 5.
s.replace(5,3,s2) Reemplaza los 3 caracteres de s que empiezan en la posición 5
por la cadena s2.
s.insert(5,s2) Inserta en s a partir de la posición 5 la cadena s2.
La clase string también tiene métodos (subprogramas) para convertir y trabajar con arrays
de caracteres equivalentes al estilo de C.
26
Apéndice B
Bibliotecas estándares de C
1. Entrada/salida
#include <cstdio>
2. Clasificación de caracteres
#include <cctype>
27
Apéndice B. Bibliotecas estándares de C 28
3. Matemática
#include <cmath>
√
sqrt(x) Devuelve x.
exp(x) Devuelve ex .
log(x) Devuelve loge (x).
log10(x) Devuelve log10 (x).
pow(base, expo) Devuelve baseexpo .
fabs(x) Devuelve |x| ∈ R.
floor(x) Devuelve bxc.
ceil(x) Devuelve dxe.
sin(alfa) Devuelve sin(alpha).
cos(alfa) Devuelve cos(alpha).
tan(alfa) Devuelve tan(alpha).
asin(x) Devuelve sin−1 (x) en el rango [−π/2, π/2].
acos(x) Devuelve cos−1 (x) en el rango [0, π].
atan(x) Devuelve tan−1 (x) en el rango [−π/2, π/2].
atan(y,x) Devuelve tan−1 (y/x) en el rango [−π, π].
Todas devuelven un número real de tipo double. Y las trigonométricas trabajan con ángulos
en radianes.
4. Utilidades estándares
#include <cstdlib>
28