Docsity
Docsity

Prepara tus exámenes
Prepara tus exámenes

Prepara tus exámenes y mejora tus resultados gracias a la gran cantidad de recursos disponibles en Docsity


Consigue puntos base para descargar
Consigue puntos base para descargar

Gana puntos ayudando a otros estudiantes o consíguelos activando un Plan Premium


Orientación Universidad
Orientación Universidad


TIPOS DE DATOS ESTRUCTURADOS, Apuntes de Fundamentos de Electrónica

Asignatura: Fundamentos de la Programación, Profesor: , Carrera: Grado en Ingeniería de Computadores, Universidad: UMA

Tipo: Apuntes

2016/2017

Subido el 09/02/2017

elen_ak47
elen_ak47 🇪🇸

1 documento

1 / 23

Toggle sidebar

Esta página no es visible en la vista previa

¡No te pierdas las partes importantes!

bg1
UNIVERSIDAD DE MALAGA
DPTO. DE LENGUAJES Y C. DE LA COMPUTACION
E.T.S. DE INGENIERIA INFORMATICA
FUNDAMENTOS DE LA PROGRAMACIÓN
T
TE
EM
MA
A
I
IV
V
TIPOS DE DATOS ESTRUCTURADOS
IV.1. Registros.
IV.1.1. Tipo de Datos struct
IV.1.2. Registros como Parámetros.
IV.1.3. Ejemplo con registros.
IV.2. Arrays.
IV.2.1. Tipo de Datos array.
IV.2.2. Arrays como Parámetros.
IV.2.2.1. Ejemplo con arrays unidimensionales.
IV.2.3. Problemas comunes al trabajar con arrays.
IV.2.4. Utilidad de los arrays.
IV.2.5. Arrays Multidimensionales.
IV.2.5.1.Ejemplo con Arrays Multidimensionales.
IV.2.6. Arrays Abiertos como Parámetros.
IV.2.6.1. Ejemplo de Arrays Abiertos.
IV.3. Cadenas de caracteres.
IV.3.1. Tipo de datos string.
IV.3.2. Strings como Parámetros.
IV.3.2.1. Ejemplo con string
IV.4. Resolución de Problemas usando Tipos Estructurados
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17

Vista previa parcial del texto

¡Descarga TIPOS DE DATOS ESTRUCTURADOS y más Apuntes en PDF de Fundamentos de Electrónica solo en Docsity!

UNIVERSIDAD DE MALAGA

DPTO. DE LENGUAJES Y C. DE LA COMPUTACION E.T.S. DE INGENIERIA INFORMATICA

FUNDAMENTOS DE LA PROGRAMACIÓN

T TEEMMAA IIVV

TIPOS DE DATOS ESTRUCTURADOS

IV.1. Registros.

IV.1.1. Tipo de Datos struct

IV.1.2. Registros como Parámetros.

IV.1.3. Ejemplo con registros.

IV.2. Arrays.

IV.2.1. Tipo de Datos array.

IV.2.2. Arrays como Parámetros.

IV.2.2.1. Ejemplo con arrays unidimensionales.

IV.2.3. Problemas comunes al trabajar con arrays.

IV.2.4. Utilidad de los arrays.

IV.2.5. Arrays Multidimensionales.

IV.2.5.1 .Ejemplo con Arrays Multidimensionales.

IV.2.6. Arrays Abiertos como Parámetros.

IV.2.6.1. Ejemplo de Arrays Abiertos.

IV.3. Cadenas de caracteres.

IV.3.1. Tipo de datos string.

IV.3.2. String s como Parámetros.

IV.3.2.1. Ejemplo con string

IV.4. Resolución de Problemas usando Tipos Estructurados

_______________________________________

En el tema 2 de esta asignatura Fundamentos de la Programación hemos estudiado los tipos

de datos simples en C++. En este tema abordaremos los tipos de datos estructurados, es decir,

aquellos que se definen como composición de otros tipos de datos ya definidos, ya sean

simples o estructurados. En C++ los tipos estructurados son el registro, el tipo array y la

cadena de caracteres.

IV.1. Registros

Un registro es una colección de elementos que pueden ser de tipos distintos. O lo que es lo

mismo, en la estructura registro no existe un único tipo base. A cada componente de la

estructura se le llama campo, y podrá ser de cualquier tipo (simple o estructurado).

IV.1.1 Tipo de Datos struct

Para definir un tipo registro se utilizará la palabra reservada struct seguida del

identificador del tipo y de la relación de componentes entre llaves, terminada en ';'. Para cada

componente se indica el tipo e identificador del componente terminado en ';'. Ejemplo:

// tipo enumerado enum Tmes { enero, febrero, marzo, abril, mayo, junio, Julio, agosto, sepiembre, octubre, noviembre, diciembre }; // tipo registro struct TFecha { unsigned dia; Tmes mes; unsigned agno; };

Una vez definido un tipo registro se pueden declarar variables y constantes de dicho

tipo:

const TFecha HOY={16, diciembre, 2010} TFecha f_nac,f_ant;

Los identificadores dia, mes y agno representan los nombres de los elementos

componentes del registro TFecha, denominados campos. Los nombres de los campos de un

registro son locales a él, por lo que no hay conflicto con otros nombres en el programa.

Una referencia a un campo de un registro consiste en el nombre de la variable (o

constante) registro y el nombre del campo, separados por un punto.

_______________________________________

// escritura del registro campo a campo }

Un registro también puede ser el valor devuelto por una función. Pero por las mismas

razones de eficiencia expuestas anteriormente respecto al paso de parámetros, es conveniente

que el valor devuelto por una función no sea de un tipo estructurado. En ese caso, será

preferible construir un procedimiento y que el valor se devuelva como parámetro de salida

mediante paso por referencia.

void leer_fecha(TFecha& fech) { // lectura del registro campo a campo }

En resumen, las operaciones que se pueden realizar sobre registros completos son la

asignación, la inicialización de una variable o constante de tipo registro, y el paso como

parámetro a subprogramas, bien por referencia si el parámetro es de salida o entrada/salida o

por referencia constante, caso de ser parámetro de entrada

IV.1.3 Ejemplo con registros

Suponemos definida la siguiente estructura registro que representa un instante de tiempo:

struct TTiempo{ unsigned horas,minutos,segundos;

};

Ejemplo: Función para calcular los segundos transcurridos entre dos instantes de

tiempo dados

unsigned convsegundos ( const TTiempo& t) { return t.horas3600 + t.minutos60 + t.segundos; } unsigned calcsegundos ( const TTiempo& t1, const TTiempo& t2) { return convsegundos(t1)-convsegundos(t2); }

Ejemplo: Procedimiento para convertir un tiempo expresado en segundos a formato de

horas, minutos, segundos.

void convtie mpo ( unsigned seg, TTiempo& t) { t.horas= seg /3600; seg= seg % 3600; t.minutos = seg /60; t.segundos= seg % 60; }

_______________________________________

IV.2. ARRAYS

El array es un tipo de datos estructurado formado por un número fijo de elementos del

mismo tipo. El tipo de los elementos del array se llama tipo base y puede ser cualquier tipo.

Una estructura array se caracteriza porque se puede acceder de manera directa a sus

elementos, a través de los valores de un tipo denominado índice. El tipo índice debe ser un

ordinal de cardinalidad finita. El tipo base puede ser tanto simple como estructurado. En

resumen, un array es una colección finita de datos homogéneos y ordenados:

Homogéneos: Todos los elementos que hay dentro de un array son del mismo tipo

(tipo base)

Finita: El número de elementos de un array es finito

Tamaño fijo (Dimensión): El número de elementos de un array se establece en su

definición y se conoce como dimensión del array. Esta dimensión establece también los

valores del tipo índice del array (valores desde 0 hasta dimensión).

Ordenados: Los elementos de un array mantienen una posición concreta en función

de los valores del tipo índice del array.

IV.2.1 Tipo de Datos array.

Para definir un tipo array se usa la palabra reservada typedef seguida por el tipo de

los elementos (tipo base ), el identificador del nuevo tipo array , y entre corchetes el número

de elementos que lo componen (dimensión).

const int MAX_CARACTERES = 30; typedef char TNombre[MAX_CARACTERES]; // Tipo Array de 30 char typedef int TVector[10]; // Tipo Array de 10 int TVector v1; // variable de tipo Vector TNombre nom; // variable de tipo Nombre

Para acceder a cada elemento de una variable declarada de tipo array se usa su

nombre seguido por una expresión entre corchetes (índice). El valor de dicha expresión

indicará la posición en el array del elemento al que se quiere acceder.

El primer elemento de un array ocupa la posición 0 (v1[0] y nom[0] en el

ejemplo), y el último elemento ocupa la posición dimensión– 1 (v1[9] y

nom[MAX_CARACTERES–1] en el ejemplo). Así mismo, es posible que el índice de acceso al

elemento sea una expresión: nom[i], nom[i+1], v1[i*2], etc.

_______________________________________

using namespace std; typedef int TVector[10]; // indexado desde la posición 0 a la 9

void LeerVector (TVector& v) // lee valores para cada componente del vector { for ( unsigned i=0; i<10;i++){ cout<<"Introduzca v["<<i<<"]: "; cin>>v[i]; } } void ImprimirVector ( const TVector& v) // muestra por pantalla los valores del vector { for ( unsigned i=0; i<10;i++){ cout<<"v["<<i<<"]: "; cout<<v[i]<<endl;; } } int main () { TVector v1; LeerVector(v1); ImprimirVector(v1); return 0;

}

IV.2.3 Problemas comunes al trabajar con arrays:

Inicialización: Las variables de tipo array , al igual que cualquier variable, deben ser

inicializadas, bien mediante lectura por teclado de cada una de sus componentes o bien

mediante asignaciones componente a componente.

Índice fuera de rango: Siempre hay que comprobar que se accede a una posición

válida dentro del array. El lenguaje de programación C++ no comprueba que el valor del

índice se encuentre dentro del rango válido para acceder a un elemento de un array. En caso

de acceso (tanto para consultar su valor, como para modificarlo) fuera del rango válido,

pueden ocurrir errores inesperados durante la ejecución del programa. De hecho, puede

suceder que el error se manifieste en otro punto del programa, e incluso que no se manifieste

visiblemente, y que permanezca oculto. Este hecho puede dar lugar a errores muy difíciles de

detectar.

IV.2.4 Utilidad de los arrays

Consideremos el siguiente ejemplo: Una empresa tiene en plantilla 20 agentes de

ventas (identificados por números del 1 al 20) que cobran comisión sobre la parte de sus

operaciones comerciales que excede los 2/3 del promedio de ventas del grupo.

_______________________________________

Se necesita un algoritmo que lea el valor de las operaciones comerciales de cada

agente e imprima el número de identificación de aquellos que deban percibir comisión así

como el valor correspondiente a sus ventas.

Este problema tiene 2 aspectos que juntos lo hacen difícil de programar con los

mecanismos vistos hasta ahora:

Procesamiento similar sobre los datos de cada agente:

 leer ventas

 calcular promedio de ventas

 comparar niveles

 decidir si debe o no recibir comisión

Se necesita almacenar durante la ejecución del programa los valores de las ventas de

cada agente: para el cálculo del promedio y para la comparación de niveles. Esto implica que

necesitamos 20 variables para retener los valores de las ventas.

Un posible algoritmo sería:

#include using namespace std; const float PORCION=2.0/3.0; int main () { float ventas1,ventas2,ventas3, ventas4,...ventas20; // ventas realizadas por cada agente float suma=0.0; // acumulado de ventas float umbral; // valor minimo para obtener comision cout<<"Introduzca las ventas del agente: "<<endl; cin>>ventas1; suma= suma+ventas1; cout<<"Introduzca las ventas del agente: "<<endl; cin>>ventas2; suma=suma+ventas2; cout<<"Introduzca las ventas del agente: "<<endl; cin>>ventas3; suma= suma+ventas3; cout<<"Introduzca las ventas del agente: "<<endl; cin>>ventas4; suma= suma+ventas4; ... cout<<"Introduzca las ventas del agente: "<<endl; cin>>ventas20; suma= suma+ventas20; umbral= PORCION*(suma/20.0); if (ventas1>umbral) { cout<<"Ventas del Agente 1: "<<ventas1; } if (ventas2>umbral)

_______________________________________

float calcMedia ( const TVentas& ventas) { float suma=0.0; for ( unsigned i=0; i<NUMAGENTES; i++) { suma= suma+ventas[i]; } return suma/NUMAGENTES; } void imprimir ( const TVentas& ventas, float umbral) { for ( unsigned i=0; i<NUMAGENTES; i++) { if (ventas[i]>umbral) { cout<<"Ventas del Agente "<<i+1<<" :"<<ventas[i]; } } }

int main () { TVentas ventas; float umbral; leerVentas(ventas); umbral= PORCION*calcMedia(ventas); imprimir(ventas,umbral); return 0; }

IV.2.5 Arrays Multidimensionales

Al definir el tipo array intervienen siempre 2 tipos : el tipo indice y el tipo base. El

tipo indice ha de ser un ordinal de cardinalidad finita, pero sobre el tipo base no existe

restricción alguna. Al poder usarse cualquier tipo como tipo base de un array , esto incluye la

posibilidad de usar tipos estructurados como tipo base de un array. De esta forma, en caso de

que el tipo base de un array sea a su vez otro array , obtendremos array s multidimensionales.

Por ejemplo:

const unsigned Filas=5; const unsigned Columnas=3; typedef int TVectorFila[Columnas]; typedef TVectorFila TMatriz[Filas]; // matriz de 5 Vectores Fila

También es posible declararlo de la siguiente forma:

const unsigned Filas=5; const unsigned Columnas=3; typedef int TMatriz[Filas][Columnas]; // matriz 6x

Si declaramos la variable

_______________________________________

TMatriz a;

“a” será una estructura que puede contener 5 elementos de tipo TVectorFila, o lo que

es lo mismo, 15 elementos de tipo int. Gráficamente:

5 filas

3 columnas

Elementos de tipo

TVectorFila

Elementos de tipo int

A este tipo de estructuras se les denomina Array s bidimensionales. Los array s

bidimensionales se utilizan a menudo para representar matrices matemáticas, de igual forma

que un array (unidimensional) puede emplearse para representar un vector.

Podemos declarar una variable del tipo especificado anteriormente, y acceder a los

componentes, tanto individualmente como por filas:

TMatriz a; a[2] // fila 2, es decir, un array de 3 elementos de tipo int a[2][3] // un elemento del tipo base int del array a, en concreto el // entero almacenado en la fila 2, columna 3 del array

De igual forma, si hemos definido el array bidimensional TMatriz, podríamos

construir un nuevo tipo array cuyo tipo base sea TMatriz, y obtendríamos un array de 3

dimensiones. Y así sucesivamente.

const unsigned Profundidad=3; const unsigned Filas=5; const unsigned Columnas=3; typedef int TVectorFila[Columnas]; typedef TVectorFila TMatriz[Filas]; // array de 6 Vectores Fila

_______________________________________

int resultado=0; for ( unsigned co=0; co<Columnas; co++) { resultado+= fila[co]; } return resultado; }

int sumarCol ( const TMatriz& mat, unsigned co) { int res=0; for ( unsigned fi=0; fi<Filas; fi++) { res=res+ mat[fi][co]; } return res; }

int main () { TMatriz a; TVectorColumna b; TVectorFila c; leerMatriz(a); for ( unsigned fi=0; fi<Filas; fi++) { b[fi]= sumarFila(a[fi]); } for ( unsigned co=0; co<Columnas; co++) { c[co]= sumarCol(a,co); } for ( unsigned fi=0; fi<Filas;fi++) { escribirFila(a[fi]); cout<<b[fi]; cout<<endl; } escribirFila(c); return 0; }

IV.2.6 Arrays Abiertos como Parámetros

Hay situaciones en las que deseamos implementar un subprograma que trabaje con

array s, independientemente de su tamaño. De forma tal que el tamaño del array en el

subprograma (parametro formal) se adecue al tamaño del array pasado durante la invocacion

al mismo (parametro real). Para ello, el parámetro formal se declara especificando su tipo

base, el identificador y el símbolo [] que indica que dicho parámetro es un array sin tamaño

especificado, su tamaño dependerá del tamaño del parámetro real especificado en cada

invocación al subprograma. El tipo base del parámetro real debe coincidir con el del

parámetro formal. La información sobre el tamaño del array se pierde al pasarlo como array

abierto, por lo que dicho tamaño se deberá también pasar como parámetro.

_______________________________________

En caso de pasar array s multidimensionales como parámetros abiertos, sólo es posible

poner la primera dimensión sin especificar.

El paso se realiza siempre por referencia sin necesidad de especificar el símbolo & , y

para asegurar que no sea modificado en caso de información de entrada, se realizará el paso

de parámetros constante.

IV.2.6.1 Ejemplo de Arrays Abiertos

#include using namespace std;

const unsigned TAMANO_1 = 10; const unsigned TAMANO_2 = 20; typedef int Tvector_1[TAMANO_1]; typedef int Tvector_2[TAMANO_2];

void imprimir ( int n, // numero de elementos const int vct[]) // Parámetro de entrada: vector de enteros // paso por referencia constante { for ( int i = 0; i < n; ++i) { cout<<" v["<< i <<"]: "; cout << vct[i] << " " ; } cout << endl; }

void valores ( int n, // numero de elementos int vct[]) // vector de enteros (paso por referencia) { for ( int i = 0; i < n; ++i) { cout<<"Introduzca componente v["<<i<<"]: "; cin >> vct[i]; } }

int main () { Tvector_1 vector_1; Tvector_2 vector_2; cout<<"Lectura de valores para el array 1: "<<endl; valores(TAMANO_1, vector_1); cout<<"Escritura de los valores del array 1: "<<endl; imprimir(TAMANO_1, vector_1); cout<<"Lectura de valores para el array 2: "<<endl; valores(TAMANO_2, vector_2); cout<<"Escritura de los valores del array 2: "<<endl; imprimir(TAMANO_2, vector_2); return 0; }

Sólo es válido declarar array s abiertos como parámetros. No es posible declarar

variables como array s abiertos.

_______________________________________

string cadena; string nmb; cadena = nombre; // asigna el valor de nombre a cadena

 Concatenación de dos cadenas ( + ):

En la concatenación, al menos uno de los dos primeros operandos debe estar

declarado de tipo string.

La operación de concatenación será imprescindible para añadir caracteres a una

cadena porque no es posible acceder fuera del rango de la misma.

cadena += ' '; // añade un espacio al final de cadena cadena += "garcia"; // cadena valdra "jose garcia" nmb = cadena + ' ' + "lopez"; // nmb = "jose garcia lopez" nmb = "pepe" + "luis"; // ERROR

  • Comparación lexicográfica:

Es posible comparar variables y constantes de tipo string mediante los operadores

relaciones (== != > >= < <=) siempre y cuando al menos uno de los operandos esté

declarado como de tipo string :

if (nombre == "jose") { ... } if (nombre != "jose") { ... } if (cadena > nombre) { ... } if (nombre >= "jose") { ... } if (cadena < nombre) { ... } if (nombre <= "jose") { ... } if ("pepe" == "pepe") { ... } // ERROR

También se puede utilizar la función compare que devuelve tres posibles

valores:

int res; res = cadena.compare(nombre); // si cadena < nombre - > res < 0 // si cadena == nombre -> res == 0 // si cadena > nombre -> res > 0

 Longitud:

Para saber el número de caracteres de un string se utiliza size

int n = cadena.size();

 Acceso al i-ésimo carácter de una cadena ([i]), donde i  [0..nombre.size() - 1]

Se accede a los caracteres que la componen mediante indexación donde el primer

elemento se encuentra en el índice 0 , y el último elemento en el índice size()-1:

string cadena = "pepe garcia"; // string constante char primera_letra = cadena[0]; // toma valor 'p' char ultima_letra = cadena[cadena.size()-1]; // toma valor 'a' cadena[0] = ‘P’; // pone el primer carácter de cadena a ‘P’

_______________________________________

  • NOTA IMPORTANTE: C++ no comprueba que el acceso a los elementos de una

cadena mediante la indexación (vista anteriormente) se realiza dentro del rango

correcto, por lo que un error en dicha indexación puede dar lugar a errores

inesperados durante la ejecución del programa.

  • Obtener una subcadena a partir de una cadena ([i,t]).

i  [0..cadena.size() - 1] y t  [0..cadena.size() - i]

Para obtener una subcadena a partir de una cadena dada se utiliza la operación substr

de la siguiente forma. Dada una cadena cad, obtenemos una subcadena a partir de la posición

i de la misma y con un tamaño t mediante:

cad.substr(i,t)

Por ejemplo:

string cadena = “Jose Antonio”; string seg_nombre; seg_nombre = cadena.substr(5,7); // obtenemos “Antonio” // subcadena de tamaño 7 a partir de la posición 5

 Realizar la entrada y salida de string mediante los operadores habituales:

cout << "Introduce nombre: "; cin >> cadena; // salta espacios y lee hasta siguiente espacio cout << " Nombre: " << cadena << endl;

El operador de entrada (>>) salta los espacios en blanco (y saltos de línea) hasta

encontrar una cadena de caracteres, dicha cadena se leerá hasta encontrar un espacio en

blanco o un salto de línea. Así mismo, tambien es posible leer una línea entera hasta el salto

de línea, u otro delimitador que se especifique:

getline(cin, cadena); // lee una linea completa getline(cin, cadena, ';'); // lee hasta ';'

Una cuestión importante a tener en cuenta son las situaciones en las que se puede

quedar la información en el buffer dando lugar a errores en la toma de datos.

La lectura de datos mediante flujos (>>) ignora los separadores existentes entre los

diferentes elementos de entrada. Sin embargo, esto no es así para la operación getline. Esta

operación lee del buffer de teclado la información que se encuentre sin diferenciar entre

separadores y otros datos.

Por ejemplo, supongamos que tenemos la siguiente combinación de operaciones:

string nombre, apelidos; cin >> nombre; getline(cin, apellidos);

y la entrada para estas operaciones es:

_______________________________________

IV.3.2.1 Ejemplo con string

Se desea leer una cadena de caracteres, y copiarla en orden inverso en otra cadena.

#include #include using namespace std; void invertirCadena ( const string& palabra, string& invertida) {

for ( int i=palabra.size()-1;i>=0;i--) { invertida= invertida+palabra[i]; } } int main () { string entrada, invertida; cout<<"Escribir la palabra: "; cin>>entrada; invertirCadena(entrada, invertida); cout<<"La palabra "<<entrada<<" invertida es: "<<invertida<<endl; return 0; }

IV.4. Resolución de Problemas usando Tipos Estructurados

Implementación de una Agenda personal: Se pretende diseñar un programa para la gestión de

una 'agenda'. La información personal que será almacenada es la siguiente:

Nombre

Teléfono

Dirección

Calle

Número

Piso

Código Postal

Ciudad

Las operaciones a realizar con dicha agenda serán:

1. Añadir los datos de una persona

2. Acceder a los datos de una persona a partir de su nombre.

_______________________________________

3. Borrar una persona a partir de su nombre.

4. Modificar los datos de una persona a partir de su nombre.

#include #include using namespace std; unsigned const MAXPERSONAS = 50; int const NO_VALIDA = -1; // Indica posición no valida del array struct TDireccion { unsigned num; string calle; string piso; string cp; string ciudad; };

struct TPersona { string nombre; string tel; TDireccion direccion; };

typedef TPersona TPersonas[MAXPERSONAS]; / Array de 50 registros TPersona

struct TAgenda { unsigned num_pers; //número real de personas almacenada TPersonas pers; //datos de dichas personas };

void Inicializar (TAgenda& ag) { ag.num_pers=0; // agenda con 0 registros TPersona almacenados }

void LeerDireccion (TDireccion& dir) { cout<<"Introduzca calle: "; cin>>dir.calle; cout<<"Introduzca número: "; cin>>dir.num; cout<<"Introduzca piso: "; cin>>dir.piso; cout<<"Introduzca código postal: "; cin>>dir.cp; cout<<"Introduzca ciudad: "; cin>>dir.ciudad; }

void LeerPersona (TPersona& per) { cout<<"Introduzca nombre: "; cin>>per.nombre; cout<<"Introduzca telefono: "; cin>>per.tel; LeerDireccion(per.direccion); } void EscribirDireccion ( const TDireccion& dir)