Documentos de Académico
Documentos de Profesional
Documentos de Cultura
En la primera parte del módulo se aborda el tema de estructuras desde una visión
amplia en su definición; se acerca a los estudiosos a la iniciación de la declaración
de estructuras, teniendo en cuenta sus tamaños y formas de acceso; para
finalmente puntualizar en la recuperación de información de la estructura y su uso
en la programación.
Una estructura permite almacenar diferentes tipos de datos con el único fin de
facilitar su manipulación y su acceso. La estructura también agrupa una o más
variables, ya sea de un mismo tipo o de diferentes tipos de datos.
Una estructura de dato simple puede ser de: caracteres, números enteros o
decimales, etc, mientras que una estructura de dato compuesto puede ser de:
vectores, estructuras, listas, etc. Los elementos o componentes de una estructura
se llaman miembros.
Ejemplo:
Una estructura puede ser compuesta por cualquier cantidad de miembros, donde
cada uno de ellos tendrá un único nombre, al que se denomina nombre del
miembro.
Nombre
Proveedor
Cantidad
Precio
Fecha de la compra
La estructura de datos almacén contendrá cinco miembros, una vez decididos los
miembros definiremos los tipos de datos a utilizar para cada miembro, a
continuación se muestra en representación gráfica:
Las estructuras de datos pueden ser de dos tipos: estructuras de datos estáticas y
estructuras de datos dinámicas:
Estáticas: Son aquellas en las que se asigna una cantidad fija de memoria
cuando se declara la estructura. Es decir, su tamaño en memoria no
pueden aumentar ni disminuir mientras que el programa se encuentra en
ejecución.
Dinámicas: Son aquellas estructuras cuya operación en memoria puede
aumentar y disminuir en su tiempo de ejecución.
struct<nombre de la estructura>
{
<tipo de dato miembro1><nombre del miembro1>
<tipo de dato miembro2><nombre del miembro2>
<tipo de dato miembro3><nombre del miembro3>
……………….
<tipo de dato miembron><nombre del miembron>
};
Cabe recordar que la estructura define un tipo de dato, y no una variable, esto
quiere decir que no se reserva un espacio en memoria cuando el compilador este
analizando la estructura. Para que se puedan almacenar y manipular los datos se
deberán declarar las variables del tipo definido por la estructura.
Para nuestra estructura de datos almacén la declaración quedaría de la siguiente
manera:
struct almacen
{
char nombre[20];
char proveedor[25];
int cantidad;
float precio;
charfecha_compra[8];
};
Ejemplo:
struct tarjetas
{
char nombre[20];
int identificacion;
int codigo;
float valor_aprobado;
};
Ejemplo:
const
Min = 0;
Max = 100;
Sep = 10;
var
i = integer;
begin
i = Min;
while i < Max do begin
wirteln(i);
i = i + sep
end
end
En el ejemplo anterior tenemos que se declararon tres constantes:
Min
Max
Sep
En la primera línea del cuerpo del programa se asigna una constante a una
variable.
En la segunda, se usa una constante en una comparación.
En la tercera, la constante Sep se usa en una expresión que se asigna a una
variable.
Constantes Literales:
Ejemplo:
El 3, y el 4.
3.1416
Constantes Declaradas:
También son conocidas como constantes con nombre, son las que se declaran en
la sección const asignándoles un valor directamente.
Ejemplo:
const
pi = 3.141592; (* valor real *)
Min = 0 (* entero *)
Max = 99 (* entero *)
Saludo = ‘Hola Mundo’; (* cadena carácter *)
Constantes Expresión:
Ejemplo:
const
Min = 0;
Max = 100;
Rango = 10;
N = (Max – Min) div Rango;
Mitad = (Max - Min) div 2;
5.3 Declaración de variables en estructuras
Por más pequeño que sea un programa, casi siempre se hará uso de variables.
Por ejemplo, si se utiliza algún bucle en el programa, se tendrá mínimo una
variable para el avance de este.
Para acceder a una estructura lo hacemos por medio de una o varias variables, las
cuales deberán ser definidas después de la declaración de la estructura. De la
misma forma que sucede en otros lenguajes de programación, en C debemos
considerar dos conceptos similares: declaración y definición.
La forma de declarar variables es muy sencilla, Esta sección debe comenzar con
la palabra reservada var, seguida de una lista de parejas
lista_de_variables=tipo_al_que_pertenecen. Cada par debe ir seguido por un
punto y coma. La lista_de_variables es uno o más nombres de variables
separados por comas:
struct almacen
{
char nombre[20];
char proveedor[25];
int cantidad;
float precio;
charfecha_compra[8];
} producto1, producto2, producto 3;
struc tinfo_automovil
{
charconcesionario[20];
intmodelo;
char color[10];
float precio;
};
Primera forma:
struc tinfo_automovil
{
char concesionario[20];
int modelo;
char color[10];
float precio;
} automovil1, automovil2, automovil3, automovil4;
Segunda forma:
struct info_automovil
{
char concesionario[20];
int modelo;
char color[10];
float precio;
} automovil1 = {“Renault”,2013,”Azul”,30000000};
struct info_automovil
{
char concesionario[20];
int modelo;
char color[10];
float precio;
} automovil2 {
“Renault”,
2013,
”Azul”,
30000000
};
Cuando hablamos del tamaño de una estructura nos estamos refiriendo al espacio
que ocupa en memoria una estructura de datos, para determinar el tamaño
utilizamos el operador sizeof el cual se aplicara sobre una variable o sobre un tipo
de datos.
#include<stduio.h>
/* declarar una estructura niña */
struc niña
{
char nombre[20];
int edad;
float altura;
float peso;
};
Voidmain()
{
struc niña mar;
printf(“Sizeof (niña): %d \n”,|sizeof(mar));
}
Sizeof (niña): 30
Memoria Dinámica
Supongamos que nuestro programa debe manipular estructuras de datos de
longitud desconocida. Un ejemplo simple podría ser el de un programa que lee las
líneas de un archivo y las ordena. Por tanto, deberemos leer un número
indeterminado de líneas, y tras leer la última, ordenarlas. Una manera de manejar
ese número indeterminado, sería declarar una constante MAX_LINEAS, darle un
valor grande, y declarar un array de tamaño MAX_LINEAS. Esto, obviamente, es
muy ineficiente (y feo). Nuestro programa no sólo quedaría limitado por ese valor
máximo, sino que además gastaría esa enorme cantidad de memoria para
procesar hasta el más pequeño de los ficheros.
Su sintaxis es:
<nombre de la variable estructura> . <nombre miembro> = datos;
Ejemplos:
A continuación veremos un ejemplo en el que se lee del teclado los datos de una
variable estructura ciclista:
Su sintaxis es:
Ejemplos:
struc trabajador;
{
char nombre[30];
intnum_trabajador;
intanyo_de_ingreso;
float sueldo;
};
Ejemplo:
struct complejo
{
float pr;
float pi;
float modulo;
};
struct complejo z;
printf(“\nParte real: “)
scanf(“%f”,&z.pr);
printf(“\nParte imaginaria: “);
scanf(“%f”,&z.pi);
/* cálculo del modulo */
z.modulo = sqrt(z.pr*z.pr + z.pi*z.pi);
Operador de asignación.
Sentencia de salida (printf(), puts(),…..).
Operador punto.
Operador flecha (puntero).
<nombre variable> =
<nombre variable estructura>.<nombre miembro>;
<nombre variable> =
<puntero de estructura> -><nombre miembro>;
Para salida:
o printf(“ “,<nombre variable estructura>.<nombre miembro>);
o printf(“ “,<nombre variable estructura> -><nombre miembro>);
Ejemplos:
floatx,y;
struct complejo z;
struct complejo *pz;
pz = &z;
x = z.pr;
y = z.pi;
….
printf(“\número complejo (%.1f,%.1f), modulo: %.2f”, pz->pr,pz->pi,pz
->modulo);
struct trabajador
{
Char nombre_trabajador[40];
char dirección[20];
char ciudad[25];
char localidad[25];
longint código_postal;
double salario;
};
struct clientes
{
char nombre_cliente[40];
char dirección[20];
char ciudad[25];
char localidad[25];
longint código_postal;
double saldo;
};
Estas dos estructuras contienen varios datos comunes, de esta forma podría
disponerse de una estructura, info_direccion, que contenga estos miembros
comunes.
struct info_direccion
{
char dirección[20];
char ciudad[25];
char localidad[25];
longint código_postal;
};
struct trabajador
{
char nombre_trabajador[40];
struct info_direccion direccion_trabajador;
double salario;
};
struct clientes
{
char nombre_cliente[40];
struc tinfo_direccion direccion_cliente;
double saldo;
};
Así como las variables las estructuras también pueden formar parte de un arreglo,
tendremos que definir primero la estructura y luego declarar una variable arreglo
de dicho tipo.
struct Nombre_estructura
{
Tipo_Variable1 Nombre_Variable1;
……
Tipo_VariableN Nombre_VariableN;
};
struct Nombre_EstructuraVariable_Arreglo[Numero_Elementos];
struct entero
{
int N,
int D;
};
Un arreglo dentro de una estructura pueden ser los mismos miembros que la
componen. Debemos tener mucho cuidado al acceder a los elementos
individuales del arreglo.
struct nomina
{
char nombre[40];
int dependientes;
charcentro_de_costos[15];
floathoras_diarias[15]; /* arreglo de tipo float */
float sueldo;
} empleado[200]; /* un arreglo de 200 empleados */
6.4 Uniones
6.5 Enumeraciones:
Forma 1
enum
{
enumerador1, enumerador2,……,enumerador
};
Forma 2
enum nombre
{
enumerador1, enumerador2,…..,enumerador
};
enum nombre
{
enumerador1, = expresion1_constante,
enumerador2, = expresion2_constante,
…
enumerador, = expresión_constante,
};
Ejemplo 1:
enum switch
{
On,
Off
};
enum Boolean
{
falso,
verdadero
};
Ejemplo 2:
enum autos
{
ford,
chevy,
mazda,
renault,
nissan
};
Ejemplo 3:
enum sexo
{
femenino,
masculino
};
6.6 Typedef
Muchas ocasiones nos será útil definir nombres para tipos de datos, que nos
hagan más fácil declarar variables y parámetros, o que nos faciliten la portabilidad
de nuestros programas.
Para esto disponemos de la palabra reservada typedef.
Sintaxis:
typedef<tipo><identificador>;
Ejemplos:
typedefstructstpuntotipopunto;
typedef struct
{
int x;
int y;
int z;
}Punto3D;
Una de las ventajas de typedef es que nos permite utilizar y dar nombres de tipos
de datos más acordes con lo que representan en una determinada aplicación.
7. Apuntadores (Punteros)
Los apuntadores son una herramienta útil e importante en los lenguajes de
programación ya que nos permite hacer los programas más eficientes y flexibles.
Creo que todos sabemos lo que es un puntero, fuera del ámbito de la
programación, los usamos para señalar cosas sobre las que queremos llamar la
atención, como marcar puntos en un mapa o detalles en una presentación en
pantalla. Con frecuencia usamos el dedo índice para señalar direcciones o lugares
sobre los que estamos hablando o explicando algo. Cuando un dedo no es
suficiente, podemos usar punteros. Antiguamente esos punteros eran una vara de
madera, pero actualmente se usan punteros laser, aunque la idea es la misma.
Un puntero también es el símbolo que representa la posición del ratón en una
pantalla gráfica. Estos punteros también se usan para señalar objetos: enlaces,
opciones de menú, botones, etc. Un puntero sirve, pues, para apuntar a los
objetos a los que nos estamos refiriendo.
Direcciones en memoria:
Nombre
Tipo
Dirección en memoria
Ejemplo:
El siguiente cuadro representa la posición de almacenamiento en memoria de una
variable, en nombre de la variable es z y su dirección en memoria es0x4fffd34, si
conocemos el valor de la variable lo pondremos dentro del cuadro.
0x4fffd34
z
int
printf (“%d”,z);
printf (“%p”,&z);
Ejemplo:
#include <stdio.h>
void main()
{
int n = 100;
printf(“n = %d/n” ,n); /*Visualiza el valor de n */
printf(“&n = %p/n”, &n); /*Visualiza la dirección de n */
}
n = 100
&n = 0x4fffd34, dirección en memoria en hexadecimal.
Ejemplo
int a = 1, b = 2, *p;
# include<stdio.h> #include<string.h>
&x = 101
char *p = NULL;
char x = ‘a’; P
p = &x; apunt
aa x
Es importante tener en cuenta que el puntero debe apuntar a una variable del
mismo tipo
char x = ‘a’;
Er
int *p = &x; ro
r!
int edad;
int * p_edad;
p_edad = &edad;
*p_edad = 20;
printf(“%d”,*p_edad); /* Indirecciónp_edad */
#include“stdio.h”
#include“conio.h”
void main()
{
intvar = 1, *apunt;
apunt = &var; /* Inicialización del apuntador
printf(“\n Acceso directo,var = %d”,var);
printf(“\n Acceso indirecto, var = %d”,*apunt);
getch();
}
Ejemplo:
intvalor_unidad = 200;
int *puntero1 = &valor_unidad;
int **puntero5 = &puntero1;
float v[10];
float *p;
float x = 100.5;
int j;
/* Se indexa a partir de v */
for (j=0; j<10; j++)
*(v+j) = j*10.0;
Para poder modificar el valor de este puntero, este tendría que apuntar a una
dirección que no sea una constante, como un array.
Esta vez nos dimos cuenta que si pudimos remplazar el valor del nombre, pero
aun la cantidad de caracteres está limitada por el array original.
7.8 Aritmética de punteros
Por ejemplo suponiendo una matriz doble con 100 elementos, si ptr es un puntero
a dicha matriz, la sentencia ptr++; supone incrementar el Rvalue de ptr en 6400
bits, porque el tamaño de la matriz es precisamente 100 x 64 bits.
Las operaciones que implican dos punteros exigen que sean del mismo tipo o se
realice previamente un modelado apropiado.
Operaciones permitidas:
Sean ptr1 y ptr2 punteros a objetos del mismo tipo, y n un tipo entero o una
enumeración; las operaciones permitidas y los resultados obtenidos con ellas son:
Del mismo modo, la diferencia entre dos punteros resulta ser el número de objetos
tipoX que separa a dos punteros tipoX.
Ejemplo:
Si puntero1 apunta al tercer elemento de una matriz, y puntero2 apunta al decimo
elemento, el resultado puntero2 - puntero1 es 7(en realidad, la diferencia de dos
punteros solo tiene sentido cuando ambos apuntan a la misma matriz).
Observe que no está definida la suma entre punteros.
Si ptr apunta a uno después del último, ptr1 es legal (puntero al último elemento).
Sin embargo, aplicando el operador de indirección * a un puntero después del
último conduce a una indirección. Informalmente puede pensarse en ptr + n como
avanzar el puntero en (n * sizeof(tipoX)) bytes, siempre que ptr se mantenga en su
rango legal(entre el primer elemento y uno después del último).
Los punteros a funciones se utilizan como cualquier otro tipo de punteros; pueden
ser pasados como argumentos de otras funciones, usados en arreglos, retornados
por funciones, etc. La única diferencia es que lo que se encuentra al tomar el
contenido de (operador *) estos punteros, no es un dato sino un pedazo de código
ejecutable.
Al igual que en los arreglos estáticos, el nombre de una función que ya existe
puede ser utilizada donde se requiera un puntero a función.
Su utilización permite implementar funciones genéricas que operen sobre otras
funciones (búsqueda de ceros, integración, etc.)
Declaración:
Ejemplo:
Las dos últimas sentencias son equivalentes (de la misma manera que cuando
trabajamos con punteros a arreglos, era indistinto decir p[i] o *(p+i)), la primera
forma es más cómoda, pero la segunda muestra explícitamente que p es un
puntero.
Por ejemplo:
x = f[0](3.14); /* x = sin(3.14) */
x = f[1](3.14); /* x = inversa(3.14) */
x = f[2](3.14); /* x = cos(3.14) */
#include <stdio.h>
#include <math.h>
int main()
{
double s;
double (*f[2])(double) = {sin, inversa}; /*declaración e inicialización */