viernes, 8 de abril de 2011

Capitulo 11. Estructuras

Fuente:
Programación en C++ / Principios y Aplicaciones (resumen)
Carlos Romero Shollande

1.        Organización de datos

Los datos procesados por computadoras digitales se reducen a combinaciones de ceros y unos, debido a que estas son construidas con dispositivos electrónicos que pueden asumir dos estados estables, uno representa a 0 y el otro a 1 (ejemplo: 10011101).
Esto da origen al elemento de datos más pequeño en una computadora, al cual se le llama bit (“dígito binario”, un dígito que sólo puede asumir uno de dos valores).
En vez de ello, los programadores prefieren trabajar con los datos en formas tales como dígitos decimales (es decir, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9), letras (es decir, de la “A” a la “Z” y de la “a” a la “z”) y símbolos especiales (es decir, $, @, %, &, *, # y otros). A los dígitos, letras y símbolos especiales se les conoce como caracteres.
Un computador sólo puede procesar unos y ceros, cada carácter del conjunto de caracteres de la computadora esta representado como una secuencia de unos y ceros, llamada byte. Los bytes se componen de 8 bits.
Los datos pueden organizarse jerárquicamente:

-       Los datos elementales vienen a ser los caracteres.
-       Un grupo de caracteres forma un campo.
-       Un agrupamiento de campos es un registro.
-       Una colección de registros es un archivo y
-       Un grupo de archivos es una base de datos.

Gráfica 1. Organización de datos.


2.        Definición de Estructuras

El C++ permite crear los siguientes tipos de datos:

-       Estructuras
-       Campos de bits
-       Uniones
-       Enumeraciones

Una estructura es una colección de campos de tipos de datos distintos (a diferencia de los arreglos que contienen solamente elementos del mismo tipo de datos), lógicamente relacionados y referenciados bajo el mismo nombre.
Las estructuras se utilizan comúnmente para definir registros de datos que se almacenarán en archivos.

2.1. Creación del Tipo Estructura

Sintaxis      : struct nombre_tipo_estructura   {
                        tipo1 campo1;
                        tipo2 campo2;
                        ….
                        tipon campon;
                        };
Propósito    : Crear una estructura bajo la denominación nombre_tipo_estructura y definir el formato de los campos. Los campos de una misma estructura deben tener nombres únicos, pero dos estructuras diferentes pueden contener campos con el mismo nombre sin que haya conflicto.
Ejemplo      : struct trabajador   {
                        int codigo;
                        char nombre[30];
                        char puesto[10];
                        float salario;    };

El C++ asigna automáticamente suficiente memoria para acomodar todas las variables que configuran una variable estructurada; en el ejemplo, cada campo tiene reservado en la memoria las siguientes capacidades.

Código  = 2 bytes
Nombre = 30 bytes
Puesto   = 10 bytes
Salario  =  4 bytes

2.2.  Declaración de Variables Tipo Estructura

Sintaxis     : struct nomb_tip_estruc nomb_var_estruc;
Propósito   : Declarar una variable de tipo estructura.
Ejemplo     : struct trabajador obrero

La declaración anterior puede escribirse también:

struct trabajador   {
int codigo;
char nombre[30];
char puesto[10];
float salario;    }   obrero;

En este caso se hacen dos operaciones al mismo tiempo, la primera define un tipo estructura llamado trabajador y la segunda declara a la variable obrero.

Gráfica 2. Organización de una estructura.


Gráfica 3. Almacenamiento de una variable tipo estructura:


Si solamente se requiere una variable estructurada, no se necesita incluir el nombre de la estructura, por ejemplo:

struct      {
int codigo
char nombre[35];
char dirección[18];
float compras;
}   cliente;

2.3.  Acceso a un Campo

Sintaxis     : nomb_variable_estructura.nomb_campo
Propósito   : Referenciar campos individuales de una estructura usando el operador de punto(.).
Ejemplo     : obrero.salario=85.37;
                        gets(cliente.direccion);
                        cout<<cliente.compras;

2.4.  Inicialización de Estructuras

Sintaxis      : struct nomb_tipo_estruc nomb_var_estruc = {lista variables};
Propósito    : Inicializar estructuras mediante una lista de inicialización separada por comas y encerrada entre llaves como con los arreglos.
Ejemplo      : struct ventas x = {“Rodríguez”, “Trujillo”};

Crea x de tipo struct ventas e inicializa el primer campo como “Rodríguez” y el segundo como “Trujillo”.
Si en la lista aparecen menos inicializadores que en la estructura, los miembros restantes quedaran inicializados como 0 (o NULL si el campo es un puntero).
Es un error de sintaxis comparar estructuras, debido a diferentes requisitos de alineación en los sistemas.

2.5.  Operaciones con Estructuras

Sobre las estructuras se pueden utilizar las mismas operaciones que se realizan sobre una variable individual, es decir lectura, escritura, asignación, comparaciones, etc.
Ejemplos:

cin>>obrero.salario;
obrero.pago=obrero.salario*obrero.horas*(1–obrero.afp);
cout<<obrero.pago;
if(obrero.pago > 1000) cout<<”Obrero calificado”;

2.6.  Estructuras Anidadas

Se denomina así cuando una estructura es un campo de otra estructura. Ejemplo:

struct tiempo      {
            long int hora, minuto, segundo;
            };
struct periodo     {
            char apellido[25];
            char nombre[12];
            struct tiempo reloj;
            };
struct periodo corredor;

Este ejemplo define a la variable corredor.

Gráfica 4. Estructuras anidadas.


Para tener acceso a un campo de una estructura anidada, se debe indicar el camino a seguir en orden jerárquico desde el nombre de la estructura raíz hasta el campo específico, por ejemplo:

corredor.reloj.minuto = 37;

2.7.  Arreglo de Estructuras

En un arreglo de estructuras o arreglo de registros los elementos son de tipo estructura.
Un ejemplo de declaración de un arreglo de estructuras es:

struct dato    {
            unsigned codigo;
            char nombre[10];
            int nota;    }  alumnos[40];

Para acceder a una estructura específica, se indexa el nombre de la estructura, por ejemplo:

cout<<alumnos[7].nota;

Esta sentencia imprime la nota de la estructura 8, ya que los arreglos de estructuras comienzan el índice en cero.

2.8.  Uso de Estructuras con Subprogramas

Hay dos formas para pasar la información en estructuras hacia los subprogramas:

a)        Pasar los campos individuales de una variable estructura a una función.

De manera predeterminada, los datos (a excepción de los campos individuales de arreglos) se pasan mediante una llamada por valor (función). Por ejemplo:

struct   {
int n;
char w[20];
}   grupo;

funcion1(grupo.n);                      // Pasa el valor entero de n
funcion2(grupo.w);                 // Pasa el valor de la cadena w
funcion3(grupo.w[5]);                 // Pasa el valor del quinto carácter de w

Los campos de estructuras también se pueden pasar mediante llamadas por referencia (procedimiento), pasando referencias o apuntadores. Para pasar una estructura mediante una llamada por referencia, se pasa la dirección de la variable de estructura o una referencia a la variable de estructura. Por ejemplo:

Procedimiento1(&grupo.n);         // Pasa la dirección del entero n
Procedimiento2(&grupo.w);        // Pasa la dirección de la cadena w
Procedimiento3(grupo.w[5];        // Pasa la dirección del quinto carácter w

El operador & siempre precede al nombre de la variable estructura y no al nombre del campo individual. Por otro lado, el quinto elemento de la cadena w ya significa una dirección de forma que el uso de & no se requiere en esa línea de código.
Los arreglos de estructuras (al igual que los demás arreglos) se pasan automáticamente mediante llamadas por referencia.

b)        Pasar la estructura completa a una función.

Cuando se usa una estructura como parámetro se debe tener en cuenta que el tipo de argumento debe coincidir con el tipo de parámetro. Por ejemplo:

struct dato  {
int x, y;
char w;   };

main()  {
struct dato numero
numero.x = 220;
procedimiento(numero);
}

procedimiento(struct dato valor)  {
cout<<valor.x;
}

En este caso se recomienda definir una estructura globalmente y después usar su nombre para declarar variables y parámetros de estructura que se necesite.

3.        Campos de Bits

Un campo de bit es un tipo especial de estructura que define la longitud en bits que tendrá cada elemento, esto permitirá el acceso a un único bit en un byte.

Sintaxis      : struct nombre_tipo_estructura   {
                        tipo1 nombre1 : longitud1;
                        tipo2 nombre2 : longitud2;
                        ……..
                        tipon nombren : longitudn;      };
Propósito    : Definir un campo de bit. Se debe declarar un campo de bit como int, unsigned o signed. Se debe declarar los campos de bit de longitud 1 como unsigned, por que un bit único no puede tener signo.

Este tipo es muy útil por las siguientes razones:

-       Si el almacenamiento es limitado, se pueden almacenar varias variables boolean (verdad o falso) en un byte. Es decir, permiten un mejor uso de la memoria, almacenando datos en la mínima cantidad de bits requeridos.
-       Ciertas interfaces de dispositivo transmiten información que se codifican en bits en un byte.
-       Ciertas rutinas de encriptación necesitan acceder a los bits de un byte.

Aunque se pueden realizar todas estas operaciones con operadores de modo bit, un campo de bit puede añadir más estructuración y eficacia al código, así mismo, puede hacer más transportable un programa.

Tabla 1. Operadores a nivel de bits:

 OPERADOR
 ACCION
&
|
Ù
-
>> 
<< 
Y Lógico (AND)
O lógico (OR)
Operador OR exclusivo
Operador complemento
Desplaza un lugar a la derecha
Desplaza un lugar a la izquierda

Los operadores AND a nivel de bits (&), OR inclusivo a nivel de bits (|) y OR exclusivo a nivel de bits (^) comparan sus dos operandos bit por bit.
El operador AND a nivel de bits establece a 1 cada bit del resultado si los dos bits correspondientes en ambos operandos son 1.
El operador OR inclusivo a nivel de bits establece a 1 cada bit del resultado si el bit correspondiente el alguno (o ambos) operandos es 1.
El operador OR exclusivo a nivel de bits establece a 1 cada bit del resultado si el bit correspondiente en solamente un operando es 1.
El operador de desplazamiento a la izquierda (<<) desplaza los bits de su operando izquierdo hacia la izquierda el número de bits especificado por su operando derecho.
El operador de desplazamiento a la derecha (>>) desplaza los bits de su operando izquierdo hacia la derecha el número de bits especificado por su operando derecho.
El operador de complementos a nivel de bits establece a 1 todos los bits 0 del operando del resultado, y establece a 0 todos los bits 1 en el resultado.

4.        Unión

Una unión es una posición de memoria que es compartida por varias variables similares, que pueden ser de diferentes tipos, denominados miembros.

4.1.  DECLARACION DE UNA UNION

Sintaxis      : union nombre_union     {
                        tipo1 miembro1;
                        tipo2 miembro2;
                        …….
                        tipok miembrok;
                        };
Propósito    : Definir a una unión.
Ejemplo      : union perfil    {
                        int x;
                        char carácter;     };

4.2. Declaración de Variables Tipo Unión

La definición de una unión tiene la misma forma que la definición de una estructura.
Por tanto, todo lo expuesto para las estructuras es aplicable a las uniones, excepto la forma de almacenamiento de sus miembros.

Sintaxis      : union nombre_union var1, var2, … ;
Propósito    : Declarar una o más variables de tipo unión.
Ejemplo      : union perfil proy;

4.3.  Acceso a un Miembro

Sintaxis      : variable.miembro
Propósito    : Referenciar a un determinado miembro de una unión.
Ejemplo      : proy.x = 25;

Para almacenar los miembros de una unión se requiere una zona igual a la que ocupa el miembro cuyo tipo ocupa el mayor número de bytes de la unión.
Todos los miembros son almacenados en el mismo espacio de memoria y comienza en la misma dirección. Las uniones ahorran almacenamiento.
El valor almacenado es sobreescrito cada vez que se asigna un valor al mismo miembro o a un miembro diferente, debido a que únicamente un miembro y, por lo tanto, únicamente un tipo de dato puede ser referenciado en un momento dado. Son errores de sintaxis:

-       Referenciar con el tipo equivocado, datos en una unión almacenados en un tipo distinto.
-       Comparar uniones, por las razones expresadas en las estructuras.
-       Inicializar una unión en una declaración con un valor cuyo tipo sea distinto al del primer miembro de la unión.

5.        Enumeración

Una enumeración es un conjunto de constantes enteras con nombre, y especifica todos los valores legales que puede tener una variable. 

5.1.  Creación de una Enumeración

Sintaxis      : enum nombre_tipo_enum   {
                     lista_enumeraciones    } lista_variables;
Propósito    : Definir enumeraciones. Aquí la lista de enumeraciones es una lista de nombres separados por comas, representando los valores que una variable de tipo enumeración puede tener.
Ejemplo      : enum dinero   { decimo, quinto, medio, sol };

5.2.  Declaración de Variables Tipo Enumeración

Sintaxis      : enum nombre_tipo_enum variables;
Propósito    : Declarar una o más variables de tipo enum.
Ejemplo      : enum dinero moneda;

5.3.  Acceso a una Variable

El acceso a una variable tipo unión se realiza con la siguiente sintaxis:

Sintaxis      : variable
Propósito    : Acceder a una variables.
Ejemplo      : moneda = quinto;
                    If(moneda==medio) cout<<”Es medio sol \n”);

6.        Tamaño de Tipo o Variable

Sintaxis       : sizeof(tipo o variable);
Propósito    : Calcular el tamaño de cualquier tipo o variable.
Ejemplo      :union datos    {
                        char caracter;
                        int entero;
                        float flotante;   }   informe;

Tabla 2. Tamaños para los tipos de datos en el C++.

Tipo
Tamaño (bytes)
char
int
long int
float
doublé
1
2
4
4
8

El sizeof(informe) será 4, ya que toma el tamaño más grande que puede guardar porque la unión debe ser tan grande como el elemento más grande.


Ejemplo: 
Crear un arreglo de estructuras para un zoológico, que permita realizar el control de los animales ahí instalados, y que contenga los campos: clase, orden, genero, raza, número de ejemplares, fecha de nacimiento y edad en días. Ordene el arreglo en forma descendente de acuerdo a la edad, ingresando previamente la fecha actual.

Codificación:
#include <iostream.h> // Control de zoológico

#include <conio.h>
#include <stdio.h>
#include <string.h>
struct fecha     {
int dia, mes, ano;     };
struct animal    {
char clase[15],orden[15],genero[15],raza[15];
int numero,edad;
struct fecha nacim;     };
main()     {
int i, j, n, r, t, q, k;
struct animal animales[10], aux;
struct fecha actual;
long int periodo(int, int, int);
clrscr();
cout<<"Fecha actual \n\n";
cout<<"Día : "; cin>>actual.dia;
cout<<"Mes : "; cin>>actual.mes;
cout<<"Año : "; cin>>actual.ano;
cout<<"\nIngrese el número de animales : "; cin>>n;
for(i=1;i<=n;i++)     {
clrscr();
cout<<"Animal N° "<<i<<endl<<endl;
cout<<"Clase  : "; gets(animales[i].clase);
cout<<"Orden  : "; gets(animales[i].orden);
cout<<"Genero : "; gets(animales[i].genero);
cout<<"Raza   : "; gets(animales[i].raza);
cout<<"Número : "; cin>>animales[i].numero;
cout<<"\nFecha de nacimiento\n\n";
cout<<"Día : "; cin>>animales[i].nacim.dia;
cout<<"Mes : "; cin>>animales[i].nacim.mes;
cout<<"Año : "; cin>>animales[i].nacim.ano;
r = periodo(animales[i].nacim.ano,animales[i].nacim.mes,animales[i].nacim.dia);
t = periodo(actual.ano,actual.mes,actual.dia);
if(animales[i].nacim.ano == actual.ano) animales[i].edad = t - r;
else     {
if(animales[i].nacim.ano+1==actual.ano)    {
if(animales[i].nacim.ano%4==0&&(animales[i].nacim.ano%100!=0 ||
           animales[i].nacim.ano%400==0))   animales[i].edad = t + (366 - r);
else animales[i].edad = t + (365 - r);     }
else     {
q = 0;
for(k=animales[i].nacim.ano+1;k<=actual.ano-1;k++)    {
if(k%4==0 && (k%100!=0 || k%400==0))   q = q + 366;
else q = q + 365;     }
if(animales[i].nacim.ano%4==0 && (animales[i].nacim.ano%100!=0 ||
       animales[i].nacim.ano%400==0))   animales[i].edad = t + q + (366 - r);
else animales[i].edad = t + q + (365 - r);      }
}
}
for(i=1;i<=n-1;i++)     {
for(j=i+1;j<=n;j++)     {
if(animales[i].edad<animales[j].edad)    {
strcpy(aux.clase,animales[i].clase);
strcpy(animales[i].clase,animales[j].clase);
strcpy(animales[j].clase,aux.clase);
strcpy(aux.orden,animales[i].orden);
strcpy(animales[i].orden,animales[j].orden);
strcpy(animales[j].orden,aux.orden);
strcpy(aux.genero,animales[i].genero);
strcpy(animales[i].genero,animales[j].genero);
strcpy(animales[j].genero,aux.genero);
strcpy(aux.raza,animales[i].raza);
strcpy(animales[i].raza,animales[j].raza);
strcpy(animales[j].raza,aux.raza);
aux.numero=animales[i].numero;
animales[i].numero=animales[j].numero;
animales[j].numero=aux.numero;
aux.nacim.dia=animales[i].nacim.dia;
animales[i].nacim.dia=animales[j].nacim.dia;
animales[j].nacim.dia=aux.nacim.dia;
aux.nacim.mes=animales[i].nacim.mes;
animales[i].nacim.mes=animales[j].nacim.mes;
animales[j].nacim.mes=aux.nacim.mes;
aux.nacim.ano=animales[i].nacim.ano;
animales[i].nacim.ano=animales[j].nacim.ano;
animales[j].nacim.ano=aux.nacim.ano;
aux.edad=animales[i].edad;
animales[i].edad=animales[j].edad;
animales[j].edad=aux.edad;     }
}
}
for(i=1;i<=n;i++)     {
clrscr();
cout<<"Animal N° "<<i<<endl<<endl;
cout<<"Clase  : "<<animales[i].clase<<endl;
cout<<"Orden  : "<<animales[i].orden<<endl;
cout<<"Genero : "<<animales[i].genero<<endl;
cout<<"Raza   : "<<animales[i].raza<<endl;
cout<<"Número : "<<animales[i].numero<<endl<<endl;
cout<<"Fecha de nacimiento \n\n";
cout<<"Día : "<<animales[i].nacim.dia<<endl;
cout<<"Mes : "<<animales[i].nacim.mes<<endl;
cout<<"Año : "<<animales[i].nacim.ano<<endl<<endl;
cout<<"Edad (en días) : "<<animales[i].edad<<endl;  getch();     }
getch();
}
long int periodo(int a, int m, int d)     {
long int s;
switch(m)     {
case 1: {   s=d;  break;    }
case 2: {   s=31+d;  break;    }
case 3: {   if(a%4==0 && (a%100!=0 || a%400==0)) s=60+d;
                 else s=59+d;  break;    }
case 4: {   if(a%4==0 && (a%100!=0 || a%400==0)) s=91+d;
                 else s=90+d;  break;    }
case 5: {   if(a%4==0 && (a%100!=0 || a%400==0)) s=121+d;
                 else s=120+d;  break;    }
case 6: {   if(a%4==0 && (a%100!=0 || a%400==0)) s=152+d;
                 else s=151+d;  break;    }
case 7: {   if(a%4==0 && (a%100!=0 || a%400==0)) s=182+d;
                 else s=181+d; break;    }
case 8: {   if(a%4==0 && (a%100!=0 || a%400==0)) s=213+d;
                 else s=212+d; break;    }
case 9: {    if(a%4==0 && (a%100!=0 || a%400==0)) s=244+d;
                  else s=243+d; break;    }
case 10: {   if(a%4==0 && (a%100!=0 || a%400==0)) s=274+d;
                   else s=273+d; break;    }
case 11: {   if(a%4==0 && (a%100!=0 || a%400==0)) s=305+d;
                   else s=304+d; break;    }
case 12: {   if(a%4==0 && (a%100!=0 || a%400==0)) s=335+d;
                   else s=334+d; break;    }
}
return(s);
}

2 comentarios:

  1. Ola me dijeron que escriba aki para el restablecimiento de mi contraseña del sistema academico mi codigo es 3783300111 ok y mi correo es leo.2016.gbl@gmail.com para que me mandes la contraseña sii xfavor Gracias Atte.Gabriel chanduvi Cruzado de la escuelade Ing.de Sistemas

    ResponderEliminar
  2. Gabriel, tu clave del SGA ya ha sido reseteada. Ejecuta el proceso que se indica en el blog: caromerosh.blogspot.com en el siguiente enlace:
    http://caromerosh.blogspot.com/2012/04/actualizacion-de-codigo-para-ingresar.html

    ResponderEliminar