Introducción - Manuela Beltrán University

54
Introducción La computadora fue diseñada como una herramienta mediante la cual podemos realizar operaciones de cálculo complejas en un mínimo lapso de tiempo, también para almacenar y acceder a grandes cantidades de información. La información útil para nosotros nunca se encuentra de forma aislada y desorganizada, por el contrario siempre la encontraremos de forma estructurada y organizada. Imaginemos un diccionario, o una enciclopedia con la información desordenada o sin algún tipo de regla determinada para su organización. De este punto parte la necesidad de organizar la información de forma estructurada y que siga ciertas reglas que nos facilitan el acceso y el manejo de los datos. El segundo módulo de este curso está orientado a ofrecerle a los estudiosos diferentes conceptos relacionados con el manejo y la administración de las estructuras de programación, así como también el uso de datos de memorias y variables denominadas punteros. 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. A continuación se hace un breve recorrido por el tipo de arreglos de estructuras para luego conocer los parámetros y requisitos necesarios en procesos de uniones, enumeraciones y la función ‘typedef’. La parte final del módulo se enfoca en el estudio de los apuntadores o punteros, desde su declaración hasta sus funciones básicas como variables útiles para la manipulación de las estructuras de datos. Nombre de la asignatura ESTRUCTURAS DE DATOS Créditos académicos de la asignatura 3 Número y Nombre del módulo Módulo 2: ESTRUCTURAS Autor del contenido Carlos Alberto Torres Sastoque Cel:304 6407052

Transcript of Introducción - Manuela Beltrán University

Page 1: Introducción - Manuela Beltrán University

Introducción

La computadora fue diseñada como una herramienta mediante la cual podemos realizar operaciones de cálculo complejas en un mínimo lapso de tiempo, también para almacenar y acceder a grandes cantidades de información. La información útil para nosotros nunca se encuentra de forma aislada y desorganizada, por el contrario siempre la encontraremos de forma estructurada y organizada. Imaginemos un diccionario, o una enciclopedia con la información desordenada o sin algún tipo de regla determinada para su organización. De este punto parte la necesidad de organizar la información de forma estructurada y que siga ciertas reglas que nos facilitan el acceso y el manejo de los datos.

El segundo módulo de este curso está orientado a ofrecerle a los estudiosos

diferentes conceptos relacionados con el manejo y la administración de las

estructuras de programación, así como también el uso de datos de memorias y

variables denominadas punteros.

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.

A continuación se hace un breve recorrido por el tipo de arreglos de estructuras

para luego conocer los parámetros y requisitos necesarios en procesos de

uniones, enumeraciones y la función ‘typedef’. La parte final del módulo se enfoca

en el estudio de los apuntadores o punteros, desde su declaración hasta sus

funciones básicas como variables útiles para la manipulación de las estructuras de

datos.

Nombre de la asignatura

ESTRUCTURAS DE DATOS

Créditos académicos de la asignatura

3

Número y Nombre del módulo

Módulo 2: ESTRUCTURAS

Autor del contenido Carlos Alberto Torres Sastoque Cel:304 6407052

Page 2: Introducción - Manuela Beltrán University

Estructura temática

5.1 Definición de Estructuras

5.2 Declaración de una estructura

5.3 Declaración variable en Estructuras

5.4 Inicialización de una declaración de Estructuras

5.5 Tamaño de un Estructura

5.6 Acceso a una Estructura

5.7 Lectura de información de una Estructura

5.8 Recuperación de información de una Estructura

6. Uso de las estructuras en la programación

6.1 Estructuras añadidas

6.2 Arreglos de Estructuras

6.3 Arreglos con miembros

6.4 Uniones

6.5 Enumeraciones

6.6 Typedef

7. Apuntadores

7.1 Declaración de Punteros

7.2 Inicialización de Punteros

7.3 Indirección de Punteros

7.4 Punteros a Punteros

7.5 Punteros a Arrays

7.6 Arrays de Punteros

7.7 Punteros de cadenas

7.8 Aritmética de Punteros

7.9 Punteros a funciones

Page 3: Introducción - Manuela Beltrán University
Page 4: Introducción - Manuela Beltrán University

5. Estructuras

5.1 Definición de estructuras

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 datos, es una colección de datos organizados (lógicamente) de

un modo particular con el objetivo de facilitar su manipulación. Cada estructura

ofrece ventajas y desventajas en relación a la simplicidad y eficiencia para la

realización de cada operación. De esta forma, la elección de la estructura de datos

apropiada para cada problema depende de factores como la frecuencia y el orden

en que se realiza cada operación sobre los 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.

Una estructura es una colección de uno o más tipos de elementos llamados

miembros, cada uno de los cuales puede ser un tipo de dato diferente.

Se llamara a un dato de tipo estructurado a una entidad, con un solo identificador,

constituida por datos de otro tipo, de acuerdo con las reglas que definen cada una

de las estructuras de datos.

Ejemplo:

Una cadena formada por una sucesión de caracteres.

Page 5: Introducción - Manuela Beltrán University

Una matriz por datos simples organizados en forma de filas y columnas.

Un archivo, está constituido por registros, estos por campos, que se

componen a su vez, de datos de tipo simple.

Niklaus Wirth, inventor del lenguaje de programación PASCAL, planteo la

siguiente ecuación:

La anterior ecuación indica que un programa se obtiene tras el diseño correcto de

un algoritmo y la elección adecuada de la estructura de datos.

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.

Supongamos que deseamos almacenar los datos de un almacén, los datos a

almacenar serán los siguientes:

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:

Nombre de miembro Tipo de dato

Algoritmos + Estructura de Datos = Programas

Page 6: Introducción - Manuela Beltrán University

Nombre Arreglo de caracteres de tamaño 20

Proveedor Arreglo de caracteres de tamaño 25

Cantidad Entero

Precio Decimal

Fecha de la compra Arreglo de caracteres de tamaño 8

En la siguiente tabla podemos observar que cada miembro de la estructura de

datos almacén es un tipo de dato diferente:

Nombre de miembro Tipo de dato

Nombre Lata de atún

Proveedor Atunes y Mariscos

Cantidad 1000

Precio 1520.23

Fecha de la compra 12-05-2013

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.

5.2 Declaración de una estructura

Page 7: Introducción - Manuela Beltrán University

La estructura es un tipo de dato definido por el usuario, la cual se deberá declarar

antes de que se pueda utilizar. La sintaxis correcta para declarar una estructura es

la siguiente:

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>

};

struct: es una palabra reservada de C que nos indicara que los

elementos que vienen agrupados a continuación entre llaves

componen una estructura de datos.

nombre de la estructura: es el nombre de la estructura.

tipo de dato miembro: es el tipo de dato que corresponde a cada

miembro.

nombre del miembro: son los campos que conformaran la

estructura de datos, deben estar precedidos por el tipo de dato al que

pertenecen.

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.

Page 8: Introducción - Manuela Beltrán University

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;

};

En el anterior ejemplo declaramos la estructura tarjetas en la que almacenaremos

los siguientes datos:

Nombre: Nombre de la persona a quien pertenece la tarjeta.

identificación: número de identificación de la persona propietaria de la tarjeta.

Page 9: Introducción - Manuela Beltrán University

Código: un código compuesto por números que identificara la tarjeta.

Valor_aprobado: Valor o cupo aprobado en la tarjeta.

Constantes: Una constante es un dato cuyo valor no puede cambiar durante la

ejecución del programa, recibe un valor en el momento de la compilación y este

permanece inalterado durante todo el programa.

Las constantes se declaran con la palabra reservada const. Después de declarar

una constante ya se podrá utilizar en el cuerpo principal del programa. Tienen

varios usos:

Ser miembro de una expresión.

En una comparación.

Asignar su valor a una variable.

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

Page 10: Introducción - Manuela Beltrán University

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.

El resultado de ejecutar este programa sería una impresión en pantalla de los

números: 0, 10, 20, 30, 40, 50, 60, 70, 80, y 90.

Las constantes se puedes dividir en tres grupos:

Constantes literales (sin nombre).

Constantes declaradas (con nombre).

Constantes expresión.

Constantes Literales:

Son valores de cualquier tipo que se utilizan directamente, no se declaran ya que

no tienen nombre.

Ejemplo:

valor_esfera = 4/3 * 3.1416 * radio * radio * radio;

En el ejemplo tenemos un par de constantes literales:

El 3, y el 4.

Page 11: Introducción - Manuela Beltrán University

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:

Están también son declaradas en la sección const, la diferencia es que a estas no

se les asigna un valor directamente, sino que se les asigna una expresión.

Esta expresión se evalúa en tiempo de compilación y el resultado se le asigna a la

constante.

Ejemplo:

const

Min = 0;

Max = 100;

Rango = 10;

N = (Max – Min) div Rango;

Mitad = (Max - Min) div 2;

Page 12: Introducción - Manuela Beltrán University

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.

Cuando hablamos de bucle nos estamos refiriendo a las estructuras de control

repetitivo.

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.

Declaración: La declaración especifica simplemente el nombre y el formato de la estructura de dato, pero no reversa un espacio en memoria.

Definición: Cada definición de variable creara un espacio en memoria en donde almacenara los datos de acuerdo al formato estructurado dado en la declaració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:

La declaración de variables en una estructura se podrá realizar de dos maneras:

Primera: Las variables que serán utilizadas en el programa se podrán listar

inmediatamente después de la llave de cierre de la declaración de la estructura.

struct almacen

Page 13: Introducción - Manuela Beltrán University

{

char nombre[20];

char proveedor[25];

int cantidad;

float precio;

charfecha_compra[8];

} producto1, producto2, producto 3;

Segunda: Las variables se podrán listar seguidas del nombre de la estructura.

struct almacen producto1, producto2, producto 3;

{

char nombre[20];

char proveedor[25];

int cantidad;

float precio;

charfecha_compra[8];

};

Ejemplo: Supongamos que un programa procesa gestiona los siguientes datos de

un automóvil: concesionario, modelo, color, precio.

La estructura info_automovil quedaría de la siguiente manera:

struc tinfo_automovil

{

charconcesionario[20];

intmodelo;

char color[10];

Page 14: Introducción - Manuela Beltrán University

float precio;

};

La definición de la estructura info_automovil quedaría de la siguiente manera: Primera forma:

struc tinfo_automovil

{

char concesionario[20];

int modelo;

char color[10];

float precio;

} automovil1, automovil2, automovil3, automovil4;

Segunda forma:

struc tinfo_automovil automovil1, automovil2, automovil3, automovil4;

{

char concesionario[20];

int modelo;

char color[10];

float precio;

};

5.4 Inicialización de una declaración de estructuras

Page 15: Introducción - Manuela Beltrán University

Las estructuras, al igual que las matrices, almacenan sus miembros de forma

contigua, razón por la cual, se les pueden aplicar punteros y una cierta aritmética.

Por la misma razón, se pueden crear matrices de estructuras e incluso estructuras

de matrices (sus miembros son matrices). Estas últimas no se diferencian gran

cosa de las matrices de matrices (a no ser en la notación de acceso a sus

miembros).

También se puede calcular su tamaño en bytes con la expresión sizeof, aunque a

este respecto debe tenerse en cuenta algunas posibles discrepancias respecto a

los valores "teóricos", debidas a las alineaciones internas realizadas por el

compilador, que se comentan

Para inicializar una estructura se puede realizar de dos formas:

Se podrá realizar dentro de la sección de código de su programa.

Siendo parte de la definición de la estructura, se deberá especificar los valores iníciales, entre llaves, después de la definición de variable estructura.

La sintaxis correcta es: struct<tipo><nombre variable estructura> =

{ valor miembro,

valor miembro,

valor miembro,

……...

valor miembro

};

Para nuestro ejemplo de automóviles se inicializara durante la declaración:

struct info_automovil

{

Page 16: Introducción - Manuela Beltrán University

char concesionario[20];

int modelo;

char color[10];

float precio;

} automovil1 = {“Renault”,2013,”Azul”,30000000};

Otra forma puede ser:

struct info_automovil

{

char concesionario[20];

int modelo;

char color[10];

float precio;

} automovil2 {

“Renault”,

2013,

”Azul”,

30000000

};

5.5Tamaño de una estructura

La forma más fácil de almacenar el contenido de una variable en memoria en

tiempo de ejecución es en memoria estática o permanente a lo largo de toda la

ejecución del programa. No todas las variables pueden ser almacenadas

estáticamente. Para que un variable pueda ser almacenado en memoria estática

su tamaño (número de bytes necesarios para su almacenamiento) debe ser

conocido en tiempo de compilación, como consecuencia de esta condición no

podrán almacenarse en memoria estática:

Page 17: Introducción - Manuela Beltrán University

Los objetos correspondientes a procedimientos o funciones

recursivas, ya que en tiempo de compilación no se sabe el número

de variables que serán necesarias.

Las estructuras dinámicas de datos tales como listas, árboles, etc. ya

que el número de elementos que las forman no es conocido hasta

que el programa se ejecuta.

Las técnicas de asignación de memoria estática son sencillas.

A partir de una posición señalada por un puntero de referencia se aloja la variable

X, y se avanza el puntero tantos bytes como sean necesarios para almacenar la

variable X. La asignación de memoria puede hacerse en tiempo de compilación y

las variables están vigentes desde que comienza la ejecución del programa hasta

que termina. En los lenguajes que permiten la existencia de subprogramas, y

siempre que todas las variables de estos subprogramas puedan almacenarse

estáticamente se aloja en la memoria estática un registro de activación

correspondiente a cada uno de los subprogramas.

Estos registros de activación contendrán las variables locales, parámetros

formales y valor devuelto por la función.

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.

A continuación veremos un ejemplo de la forma en que se utiliza el operador

sizeof:

#include<stduio.h>

/* declarar una estructura niña */

struc niña

Page 18: Introducción - Manuela Beltrán University

{

char nombre[20];

int edad;

float altura;

float peso;

};

Voidmain()

{

struc niña mar;

printf(“Sizeof (niña): %d \n”,|sizeof(mar));

}

Cuando ejecutemos este programa el resultado de salida será el siguiente:

Sizeof (niña): 30

El 40 representa el tamaño en bytes que ocupa en memoria la estructura.

Niña Miembros dato Tamaño (bytes)

nombre[20] char(1) 20

Edad int(2) 2

Altura float(4) 4

Peso Float(4) 4

Total 30

Memoria Dinámica

Page 19: Introducción - Manuela Beltrán University

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.

La solución consiste en utilizar memoria dinámica. La memoria dinámica es un espacio de almacenamiento que se solicita en tiempo de ejecución. De esa manera, a medida que el proceso va necesitando espacio para más líneas, va solicitando más memoria al sistema operativo para guardarlas. El medio para manejar la memoria que otorga el sistema operativo, es el puntero, puesto que no podemos saber en tiempo de compilación dónde nos dará huecos el sistema operativo (en la memoria de nuestro PC).

5.6 Acceso a estructuras

Debido a que los miembros de una estructura de datos se procesan generalmente

de modo individual, se deberá poder acceder a cada uno de los miembros

individuales de una variable estructura. Cuando tenemos almacenada información

dentro de una estructura podremos acceder a los miembros de ella de dos

maneras:

Utilizando el operador punto (.).

Utilizando el operador puntero ().

Acceso a una estructura de datos mediante el operador punto:

La asignación de datos a los miembros de una variable estructura se hace

mediante el operador punto.

Su sintaxis es:

Page 20: Introducción - Manuela Beltrán University

<nombre de la variable estructura> . <nombre miembro> = datos;

Ejemplos:

cancion1.artista = “Andres Cepeda”;

cancion1.duracion = 350;

cancion2.titulo = “celos”;

cancion2.fecha = {8,12,1983};

cancion2.fecha.anho = 1990;

El operador punto nos brinda el camino directo al miembro correspondiente.

Debemos tener en cuenta que los datos que se almacenan en un miembro dato

deberán ser del mismo tipo declarado para ese miembro.

A continuación veremos un ejemplo en el que se lee del teclado los datos de una

variable estructura ciclista:

struct ciclista cl;

printf (“nombre: ”);

gets(cl.nombre);

printf(“edad: “);

scanf(“%d”,&cl.edad);

printf(“sexo: “);

scanf(“%c”,&cl.sexo);

printf(“club: “);

gets(cl.club);

if (cl.edad<= 18)

cl.categoria = “Juvenil”;

Page 21: Introducción - Manuela Beltrán University

elseif(cl.edad<= 40)

cl.categoria = “Senior”;

else

cl.categoria = “Veterano”;

Acceso a una estructura de datos mediante el operador flecha o puntero:

El operador puntero sirve para acceder a los datos de la estructura a partir de un

puntero, para poder utilizar este operador se deberá primero definir una variable

puntero que apunte a la estructura.

Su sintaxis es:

<puntero estructura> -><nombre miembro> = datos;

Ejemplos:

struc trabajador;

{

char nombre[30];

intnum_trabajador;

intanyo_de_ingreso;

float sueldo;

};

Ahora vamos a definir un puntero ptr_trab a la estructura trabajador.

struct trabajador *ptr_trab;

struct trabajador mejor_pago;

Page 22: Introducción - Manuela Beltrán University

Una vez la estructura tenga su espacio asignado en memoria, a los miembros de

la estructura trabajador se les podrá asignar datos de la siguiente forma:

ptr_trab = &mejor_pago; /* ptr_trab tiene la dirección (apunta a)

mejor_pago */

strcpy(ptr_trab -> Nombre , “Juan Perez”);

ptr_trab ->Num_trabajador = 4876;

ptr_trab ->mejor_pago = 5.000.000;

En el ejemplo anterior debimos previamente crear un espacio de almacenamiento

en memoria; por ejemplo, con la función malloc().

5.7 Lectura de información de una estructura

Con el operador punto o flecha (puntero) podemos acceder a los miembros de la

estructura, de esta forma introducimos la información en la estructura de datos,

esta información se puede obtener desde el teclado o ya sea desde un archivo, o

asignar valores calculados.

Ejemplo:

struct complejo

{

float pr;

float pi;

float modulo;

};

struct complejo z;

Page 23: Introducción - Manuela Beltrán University

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);

En el anterior ejemplo, tenemos la variable z de tipo estructura complejo, se lee

parte real, parte imaginaria y se calcula el modulo.

5.8 Recuperación de información de una estructura

Para recuperar la información de una estructura podemos utilizar

Operador de asignación.

Sentencia de salida (printf(), puts(),…..).

Operador punto.

Operador flecha (puntero).

La sintaxis de estos operadores es la siguiente:

<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>);

Page 24: Introducción - Manuela Beltrán University

Ejemplos:

Algunos ejemplos de las estructura complejo:

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);

6. Uso de estructuras en programación

6.1 Estructuras añadidas

Una estructura puede anidar otras estructuras, previamente definidas, como se

demuestra en el siguiente ejemplo en el que las estructuras se definen a nivel

global.

Las estructuras anidadas ahorran tiempo en la escritura de programas que utilizan

estructuras similares, se definen los miembros comunes solo una vez en su propia

estructura y a continuación utilizar esa estructura como un miembro de otra

estructura.

Page 25: Introducción - Manuela Beltrán University

Para mencionar un miembro de una estructura se indican, ordenadamente, el

nombre de la estructura principal, el nombre de la estructura anidada y el nombre

del miembro de la estructura, todos ellos separados por el operador punto.

struct autor /*Declara globalmente autor */

{

char nombre [30];

char apellido[30];

};

struct tema /*Declara globalmente tema */

{

char modulo[5];

chararea[8];

};

/*Estructura “Libros” que anida las estructuras “autor” y “tema”.

La declaración también es global.*/

structlibros

{

charnom_lib[40];

struct autoraut;

struct tema tem;

};

void main()

{

struct libros li; /*Declara li del tipo libros*/

clrscr(); /*Borra la pantalla*/

puts(“Titulo del libro”); /*Imprime en pantalla*/

Page 26: Introducción - Manuela Beltrán University

gets(li.nom_lib); /*Lee datos del teclado*/

puts(“Apellidos del autor”);

gets(li.aut.ape);

puts(“Nombre del autor”);

gets(li.aut.nomb);

puts(“Modulo: “);

gets(li.tem.modulo);

puts(“Area de conocimiento”);

gets(li.tem.area);

}

Gráficamente el anidamiento de estructuras se vera de la siguiente manera:

nom_lib nomb ape modulo area

aut tem

li

Revisemos la definición de dos estructuras:

struct trabajador

{

Char nombre_trabajador[40];

char dirección[20];

char ciudad[25];

char localidad[25];

longint código_postal;

double salario;

};

Page 27: Introducción - Manuela Beltrán University

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;

};

Esta estructura se podrá anidar a las demás estructuras.

struct trabajador

{

char nombre_trabajador[40];

struct info_direccion direccion_trabajador;

Page 28: Introducción - Manuela Beltrán University

double salario;

};

struct clientes

{

char nombre_cliente[40];

struc tinfo_direccion direccion_cliente;

double saldo;

};

EL acceso a los miembros dato de estructuras anidadas requiere el uso de

múltiples operadores punto.

Las estructuras se pueden anidar a cualquier grado, y se podrán inicializar

estructuras anidadas en la definición.

6.2 Arreglos de estructuras

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.

Para crear arreglos de estructuras se puede hacer de la misma forma en que se

hace un arreglo de cualquier tipo, son muy útiles para almacenar gran cantidad de

información que se adapte a un formato de estructura (inventarios, empleados).

La sintaxis general es:

struct Nombre_estructura

{

Page 29: Introducción - Manuela Beltrán University

Tipo_Variable1 Nombre_Variable1;

……

Tipo_VariableN Nombre_VariableN;

};

struct Nombre_EstructuraVariable_Arreglo[Numero_Elementos];

Se utilizara el operador punto para citar elementos individuales de la variable

estructura y elementos individuales del arreglo utilizando el subíndice

correspondiente.

Los arreglos de estructuras permiten almacenar en un mismo lugar valores de

diferentes tipos agrupados como estructuras, mientras que los arreglos

convencionales agrupan valores de un mismo tipo.

En algunas ocasiones se pueden utilizar los arreglos de estructura como método

para almacenar datos en un archivo de disco, una vez allí se podrán calcular sus

datos de disco y posteriormente almacenarlos en memoria. Estos arreglos de

estructura se podrán utilizar también como medio para guardar datos que se leen

del disco.

La declaración de arreglos de estructuras se podrá hacer de forma similar a

cualquier arreglo:

Ejemplo: arreglo info_empleados

struc tinfo_empleados empleados[80];

Se define un arreglo empleados de 80, si queremos acceder a los miembros de

cada uno de los elementos de la estructura se utilizara una notación de arreglo, y

para la inicialización del primer elemento del arreglo estructura lo haremos e la

siguiente manera:

Page 30: Introducción - Manuela Beltrán University

strcpy(empleados[0] .nombre, “Juan”);

strcpy(empleados[0] .apellido, “Perez”);

strcpy(empleados[0] .cargo, “asesor contable”);

empleados[0] .edad = 25;

Vamos a declarar una estructura que representa un número entero, un arreglo de

números enteros es inicializado con valores al azar.

struct entero

{

int N,

int D;

};

struct entero rs[6] = {1, 3, 5, 10, 24, 32};

6.3 Arreglos como miembros

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.

Veamos un ejemplo de cómo un miembro de una estructura puede ser un arreglo.

struct nomina

{

char nombre[40];

int dependientes;

Page 31: Introducción - Manuela Beltrán University

charcentro_de_costos[15];

floathoras_diarias[15]; /* arreglo de tipo float */

float sueldo;

} empleado[200]; /* un arreglo de 200 empleados */

6.4 Uniones

Conforme los programas se vuelven más complejos, en ocasiones necesitaremos

diferentes formas de ver una parte de la información y en otras ocasiones tenemos

la necesidad de trabajar con dos o más valores, pero en un momento dado

podremos utilizar solamente uno. Para estos casos se vuelve muy útil el uso de las

uniones para guardar los datos.

Las uniones agrupan una serie de variables, pero su forma de almacenamiento es

diferente y su resultado también lo es. Una estructura permite almacenar variables

relacionadas juntas y almacenadas en posiciones contiguas en memoria. Las

uniones se declaran con la palabra reservada unión, almacenan también

miembros múltiples en un paquete, la diferencia radica en la posición en que se

guardan, es decir, todos los miembros se solapan entre sí en una misma posición

caso contrario en situar los miembros unos detrás de otro.

El tamaño ocupado por las uniones será analizado de la siguiente manera: el

tamaño de la unión será el mayor tamaño de variable.

La sintaxis de la unión es de la misma manera de una estructura:

Los miembros de una unión pueden ser datos de

cualquier tipo.

Page 32: Introducción - Manuela Beltrán University

union nombre {

tipo1 miembro1;

tipo2 miembro2;

tipo3 miembro3;

….

};

6.5 Enumeraciones:

Una enumeración es el conjunto de constantes enteras representadas por

identificadores, estas constantes de enumeración son constantes simbólicas cuyos

valores pueden ser definidos automáticamente. Una enumeración es una

colección de uno o más tipos de datos llamados miembros, cada uno de los cuales

puede ser un tipo de dato diferente. Una estructura puede contener cualquier

número de miembros, cada uno de los cuales tienen un miembro único, llamado

nombre del miembro.

Las estructuras ayudan a organizar datos complicados, particularmente en largos

programas, porque permiten que un grupo de variables relacionadas como una

unidad en vez de entidades separadas.

En la declaración de un tipo enum se escribe una lista de identificadores que

intermitentemente se asocian con las constantes enteras 0,1,2, etc.

Se utilizara la palabra reservada enum, para realizar su declaración, su sintaxis es:

Forma 1

enum

{

enumerador1, enumerador2,……,enumerador

};

Page 33: Introducción - Manuela Beltrán University

Forma 2

enum nombre

{

enumerador1, enumerador2,…..,enumerador

};

Cuando estamos declarando la enumeración de tipo enum pueden asociarse a los

identificadores valores constantes en vez de la asociación por defecto se hace (0,

1, 2, etc.) Para esta forma utilizaremos:

enum nombre

{

enumerador1, = expresion1_constante,

enumerador2, = expresion2_constante,

enumerador, = expresión_constante,

};

Ejemplo 1:

enum switch

{

On,

Off

};

enum Boolean

Page 34: Introducción - Manuela Beltrán University

{

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.

Page 35: Introducción - Manuela Beltrán University

Para esto disponemos de la palabra reservada typedef.

Sintaxis:

typedef<tipo><identificador>;

Ejemplos:

En la siguiente línea definimos un nuevo tipo como una estructura llamada

stpunto.

typedefstructstpuntotipopunto;

Definimos un nuevo tipo Punto3D, partiendo de una estructura.

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)

Page 36: Introducción - Manuela Beltrán University

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.

Cuando declaramos una variable, el compilador reserva un espacio en memoria

para ella y asocia el nombre de esta a la dirección de memoria desde donde

comienzan los datos de esa variable, las direcciones de memoria se suelen

describir como números hexadecimales.

Una variable puntero o como normalmente se le conoce puntero, es una variable

que contiene direcciones de otras variables. Un apuntador señala a la variable

cuyo valor se almacena a partir de la dirección de memoria que contiene el

apuntador. Por ejemplo, si se tiene el apuntador b que apunta a la dirección en

memoria de la variable x, se dice que b apunta a x.

Direcciones en memoria:

En el momento de declarar una variable, se asocian tres atributos fundamentales

con esta:

Nombre

Tipo

Dirección en memoria Ejemplo:

Page 37: Introducción - Manuela Beltrán University

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

Para acceder al valor de una variable lo hacemos por medio de su nombre y la

siguiente sintaxis:

printf (“%d”,z);

Para acceder a la dirección de memoria de la variable z utilizaremos el operador

de dirección &, para nuestro ejemplo será de la siguiente manera:

printf (“%p”,&z);

El operador de dirección “&” se aplica sobre el nombre de la variable para obtener

sus direcciones.

Ejemplo:

Debemos obtener el valor y la dirección de la variable n.

#include <stdio.h>

void main()

Page 38: Introducción - Manuela Beltrán University

{

int n = 100;

printf(“n = %d/n” ,n); /*Visualiza el valor de n */

printf(“&n = %p/n”, &n); /*Visualiza la dirección de n */

}

Veamos el resultado de la ejecución del programa:

n = 100

&n = 0x4fffd34, dirección en memoria en hexadecimal.

7.1 Declaración de punteros

De la misma forma que cualquier otra variable, un puntero se deberá declarar

antes de su uso, en la declaración de un puntero se indicara al compilador el tipo

de dato al que apunta el puntero, para ello se hace preceder a su nombre con un

asterisco (*), la sintaxis es de la siguiente manera:

<tipo de dato apuntado> * <identificador de puntero>

Ejemplos de la sintaxis de declaración de punteros:

Int *puntero1; /* Puntero a un tipo de dato entero (int) */

Long *puntero2; /* Puntero a un tipo de dato entero largo (longint)

*/

Char *puntero3; /* Puntero a un tipo de dato char */

Float *f; /* Puntero a un tipo de dato float */

Tener en cuenta que el operador * en una declaración indica que la variable

declarada almacenara una dirección de un tipo de dato especifico.

Page 39: Introducción - Manuela Beltrán University

De esta forma la variable puntero1 almacenara la dirección de un entero, la

variable puntero2 almacenara la dirección de un tipo de dato long, la variable

puntero3 almacenara la dirección de un tipo de dato carácter y la variable puntero4

almacenara la dirección de un tipo de dato float.

Ejemplo

Supongamos la siguiente declaración:

int a = 1, b = 2, *p;

Al ejecutar cada una de las siguientes instrucciones el resultado sería:

p = &a; /* p apunta a la variable a */

b = *p; /* ahora b es igual a 1 */

*p = 0; /* ahora a es igual a 0 */

7.2 Inicialización de punteros

Es preciso inicializar las variables de tipo puntero antes de su uso. La inicialización

proporciona al puntero una dirección a la que apuntar.

Inicializar un puntero a una dirección nula:

Una referencia de variables de

punteros es que siempre llevara el

operador asterisco (*).

Page 40: Introducción - Manuela Beltrán University

char *p = NULL;

El puntero NULL apunta a la dirección 0.

El puntero NULL no es una dirección de una variable en memoria.

El puntero nulo proporciona al programa una manera de saber si un puntero apunta a una dirección valida.

Para poder usar el puntero nulo NULL, podemos hacer una de estas dos cosas:

Definirlo en la cabecera de nuestro programa: # define NULL 0

Incluir alguno de los archivos de cabecera donde ya se encuentre definido: # include<stdio.h> #include<string.h>

Inicializar un puntero a una dirección de memoria valida:

Para asignar una dirección de memoria a un puntero, se utiliza el operador de

dirección &. El operador & aplicado a una variable, devuelve la dirección donde se

almacena dicha variable.

&x = 101

char *p = NULL;

char x = ‘a’;

p = &x;

La inicialización también se puede hacer en la declaración.

P

apunt

a a x

Page 41: Introducción - Manuela Beltrán University

char x = ‘a’;

char *p = &x;

Es importante tener en cuenta que el puntero debe apuntar a una variable del

mismo tipo

char x = ‘a’;

int *p = &x;

Otra forma de representar punteros:

7.3 Indirección de punteros

Una vez definida e inicializada una variable de tipo puntero, disponemos de un

mecanismo para obtener el dato que almacena esa dirección de memoria.

El símbolo * se llama también operador de indirección y sirve para acceder al

valor al que apunta el puntero.

int edad;

int * p_edad;

Er

ro

r !

Page 42: Introducción - Manuela Beltrán University

p_edad = &edad;

*p_edad = 20;

Si se desea imprimir el valor de edad, se puede utilizar la siguiente sentencia:

printf(“%d”,edad); /* Imprime el valor de edad */

También se puede imprimir el valor de edad indireccionando el puntero de edad:

printf(“%d”,*p_edad); /* Indirecciónp_edad */

Ejemplo del uso básico de apuntadores:

#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);

// Se despliega la dirección de la variable de dos maneras

printf(“\n La dirección de var = %d”,&var);

printf(“\n La dirección de var = %d”,apunt);

getch();

Page 43: Introducción - Manuela Beltrán University

}

7.4 Punteros a punteros

Un puntero podrá apuntar a otra variable puntero, esta funcionalidad es muy

utilizada en programas complejos, para declarar un puntero a un puntero se hace

preceder a la variable con dos asteriscos (**).

Ejemplo:

intvalor_unidad = 200;

int *puntero1 = &valor_unidad;

int **puntero5 = &puntero1;

En el ejemplo anterior puntero 5 es un puntero a un puntero.

Puntero1 y puntero5 son punteros mientras que puntero1 apunta a la variable

valor_unidad de tipo entero, puntero5 contiene la descripción de puntero1.

Al uso de punteros de llama variables con niveles de indirección, ya que no

apuntan directamente a un valor, sino que apuntan a alguien que lo tiene.

Basándonos en esto podemos decir que puntero1 es un puntero con un nivel de

indirección y puntero5 es un puntero con dos niveles de indirección.

7.5 Punteros y arrays

Estos dos conceptos están muy relacionados en los lenguajes de programación,

se pueden direccionar los punteros como si fueran arrays y arrays como si fueran

punteros. La posibilidad de almacenar y acceder a punteros y array, implica que se

pueden almacenar cadena de datos en elementos de arrays. Sin punteros eso no

es posible, ya que no existe el tipo de dato cadena (string) en C. No existen

variables de cadena, únicamente constantes de cadena.

Page 44: Introducción - Manuela Beltrán University

Nombre de arrays como punteros:

Un nombre de un array es simplemente un puntero. Supongamos que se tiene la

siguiente declaración de un array.

int lista[5] = {10, 20, 30, 40, 50, 60;

Si se manda a visualizar lista[0] se verá 10. Pero, ¿Qué sucederá si se manda a

visualizar *lista?

Como un nombre de un array es un puntero, también se verá 10, eso significa que:

Lista + 0 apunta a lista[0]

Lista + 1 apunta a lista[1]

Lista + 2 apunta a lista[2]

Lista + 3 apunta a lista[3]

Lista + 4 apunta a lista[4]

En conclusión para visualizar o imprimir, almacenar o calcular un elemento de un

array, se puede utilizar la notación de subíndices o notación de punteros. Esto

debido a que un nombre de un array contiene la dirección del primer elemento del

array, se debe indireccionar el puntero para obtener el valor del elemento.

El nombre de un array es un puntero, contiene la dirección en memoria del

comienzo de la secuencia de elementos que forma el array. Es un puntero

constante ya que no se puede modificar, solo se puede acceder para indexar los

elementos del array. En el ejemplo se pone de manifestó operaciones correctas y

erróneas con nombres de arrays.

float v[10];

Page 45: Introducción - Manuela Beltrán University

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;

p = v + 4; /* Se asigna la dirección del quinto elemento */

v = &x; /*error: intento de modificar un puntero constante */

7.6 Arrays de Punteros

Cuando nace la necesidad de reservar muchos punteros a muchos valores

diferentes, se puede declarar un array de punteros. Un array de punteros es un

array que contiene como elementos punteros, cada uno de los cuales apunta a un

tipo de dato especifico.

int *puntero[10]; /* Reserva un array de 10 punteros a enteros */

Cada elemento contiene la dirección que apunta a otros valores de la memoria,

donde cada valor apuntado deberá ser un entero. Se puede asignar a un elemento

de puntero una dirección, tal como las variables puntero no arrays.

puntero[40] = &edad; /* Apunta a la dirección de edad */

puntero[4] = NULL; /* No contiene dirección alguna */

Ejemplo de arrays de punteros con tipo de dato carácter:

Page 46: Introducción - Manuela Beltrán University

char *puntos[30]; /* arrays de 30 punteros caracteres */

7.7 Punteros de cadenas

Los punteros se pueden utilizar en lugar de índices de arrays.

Un array de caracteres usando punteros:

char *nombre=”Jaime A. vasquez”; // Array de 20 caracteres

printf (“%s”,nombre);

Sin embargo al tratarse de una constante de caracters no podemos modificarla

luego de definir sus valores. Como por ejemplo no podemos reemplazar un

carácter, o leer un nuevo valor.

gets(nombre); // Error en ejecución

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.

char nombre[] = ”Jaime A. vasquez”; // Declaramos un array de caracteres

char *puntero = nombre; // Asignamos al puntero el comienzo del

array

printf(“%s \nIngrese otro nombre: “,puntero); //Escribimos en pantalla nombre…

gets(puntero); // Leemos otro nombre

printf(“%s ,puntero); // Escribimos el nuevo nombre….

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.

Page 47: Introducción - Manuela Beltrán University

7.8 Aritmética de punteros

La aritmética de punteros se limita a suma, resta, comparación, y asignación. Las

operaciones aritméticas en los punteros de tipo X (punteros-a-tipoX) tienen

automáticamente en cuenta el tamaño real de tipo X. Es decir, el número de bytes

necesario para almacenar un objeto tipo X.

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.

No confundir el puntero a matriz con un puntero a su primer elemento (que aquí

seria puntero a doble).

La aritmética realizada internamente en los punteros depende del modelo de

memoria en uso y de la presencia de cualquier modificador superpuesto.

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:

Operación Resultado Comentario

ptr1++ puntero Desplazamiento ascendente de 1

elemento

ptr1-- puntero Desplazamiento descendente de 1

elemento

Page 48: Introducción - Manuela Beltrán University

ptr1 + n puntero Desplazamiento ascendente de n

elementos

ptr1 - n puntero Desplazamiento descendente de n

elementos

ptr1 - ptr2 entero Distancia entre elementos

ptr1 == NULL booleano Siempre se puede comprobar la igualdad o

desigualdad con NULL

ptr1 != NULL booleano Siempre se puede comprobar la igualdad o

desigualdad con NULL

ptr1 <R> ptr2 booleano <R> es una expresión relacional

ptr1 = ptr2 puntero Asignación

ptr1 = void puntero genérico Asignación

La comparación de punteros solo tiene sentido entre punteros de la misma matriz;

en estas condiciones los operadores relacionales: ==, !=, <, >, <=, >=, funcionan

correctamente.

Hemos señalado que cuando se realizan operaciones aritméticas con punteros, se

tiene en cuenta el tamaño de los objetos apuntados, de modo que si un puntero es

declarado apuntando a tipoX, añadirle un entero n (al puntero) supone hacerlo

avanzar un numero n de objetos tipoX. Si tipoX tiene un tamaño de 10 bytes,

añadir 5 al puntero tipoX lo hace avanzar 50 bytes en memoria (si se trata de

punteros a elementos de una matriz, supone avanzar n elementos en la matriz).

Del mismo modo, la diferencia entre dos punteros resulta ser el número de objetos

tipoX que separa a dos punteros tipoX.

Ejemplo:

Page 49: Introducción - Manuela Beltrán University

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 es un puntero a un elemento de la matriz, desde luego no existe un

elemento tal como: “uno después del último”, pero se permite que ptr tenga dicho

valor. Si ptr1 apunta al último elemento del arreglo, ptr+1 es legal, pero ptr+2 es

indefinido (lo que a efectos prácticos significa que devolverá basura, o un runtime,

volcado de memoria, etc).

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).

La resta de dos punteros a elementos de la misma matriz, ptr1 – ptr2, produce un

entero n del tipo ptrdiff_t definido en <stddef.h> Este número representa la

diferencia entre los subíndices i y j de los dos elementos referenciados (n = i-j).

Para esto es necesario que ptr1 y ptr2 apunten a elementos existentes, o uno

después del último.

7.9 Punteros a funciones

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.

Page 50: Introducción - Manuela Beltrán University

Su utilización permite implementar funciones genéricas que operen sobre otras

funciones (búsqueda de ceros, integración, etc.)

Declaración:

Para declarar un puntero a una función se utiliza la siguiente sintaxis:

tipo_de_retorno (* nombre_puntero) (tipo1 arg1, tipo2 arg2,…);

Los nombres de los argumentos (arg1, arg2, etc) no son necesarios, pero pueden

servir para entender cómo se usa la función.

Ejemplo:

double (* f) (double x; /* declara el puntero a función f notar que los

paréntesis son necesarios para distinguir de

(double *) f (double) */

f = sin; /* lo inicializa con la dirección de memoria de una

función double ->double */

x = f(3.14); /* utiliza el puntero como si fuera una función */

x = (* f)(3.14); /* de referencia explícitamente el puntero al

utilizarlo */

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.

Arreglos de punteros a función

Para declarar un arreglo de punteros a función la sintaxis es:

Page 51: Introducción - Manuela Beltrán University

tipo_de_retorno (* nombre_de_puntero[tamaño]) (tipo1 arg1, tipo2 arg2,…);

Por ejemplo:

double (* f[3]) (double);

f[0] = sin;

f[1] = inversa;

f[2] = cos;

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) */

En el ejemplo anterior podríamos haber utilizado un arreglo de punteros, de la

siguiente manera:

#include <stdio.h>

#include <math.h>

doublesuma_cuadrados(double (*)(double), int, int);

doubleinversa (double x) { return 1.0/x;}

int main()

{

double s;

double (*f[2])(double) = {sin, inversa}; /*declaración e inicialización */

for (i=0; i<2; 1++)

Page 52: Introducción - Manuela Beltrán University

{

s = suma_cuadrados(f[0], 1, 100);

printf(“suma de 1 a 100 de f[%d](i)^2 = %1f/n”, i, s);

}

return o;

}

doublesuma_cuadrados ( double (*f)(double x), int i0, int if )

{

double s = 0,x;

inti;

for (i=i0; i<=if; i++)

{

x = i;

s += f(x)*f(x); /* (*f)(x)* (*f)(x) en forma más explícita */

}

return s;

}

Page 53: Introducción - Manuela Beltrán University

Glosario

ESTRUCTURA: Una estructura es una colección de uno o más tipos de elementos

llamados miembros, cada uno de los cuales puede ser un tipo de dato diferente.

DECLARACIÓN: La declaración especifica simplemente el nombre y el formato de

la estructura de dato, pero no reversa un espacio en memoria.

DEFINICIÓN: Cada definición de variable creara un espacio en memoria en donde

almacenara los datos de acuerdo al formato estructurado dado en la declaración.

MEMORIA DINAMICA: La memoria dinámica es un espacio de almacenamiento

que se solicita en tiempo de ejecución.

OPERADOR PUNTO: Con el operador punto o flecha (puntero) podemos acceder

a los miembros de la estructura, de esta forma introducimos la información en la

estructura de datos, esta información se puede obtener desde el teclado o ya sea

desde un archivo, o asignar valores calculados.

UNIONES: Las uniones agrupan una serie de variables, pero su forma de

almacenamiento es diferente y su resultado también lo es. Una estructura permite

almacenar variables relacionadas juntas y almacenadas en posiciones contiguas

en memoria. Las uniones se declaran con la palabra reservada unión, almacenan

también miembros múltiples en un paquete,

ENUMERACION: Una enumeración es el conjunto de constantes enteras

representadas por identificadores, estas constantes de enumeración son

constantes simbólicas cuyos valores pueden ser definidos automáticamente. Una

enumeración es una colección de uno o más tipos de datos llamados miembros,

cada uno de los cuales puede ser un tipo de dato diferente.

Page 54: Introducción - Manuela Beltrán University

Bibliografía

Joyanes Aguilar, Luis, Algoritmos y Estructuras de Datos. Una Perspectiva En C

Editorial: McGraw-Hill(2005).

GuardatiBuemo, Silvia. Estructura de datos orientada a objetos: Algoritmos con

C++ Editorial: Pearson(2007).

Prieto A., Lloris A. y Torres J.C. Introducción a la informática Editorial McGraw-Hill (2001). Lazaro, Obenza J. C. Estructuras de datos y Algoritmos, Editorial Prentice Hall,

Madrid (2000).

Euguíluz Morán, Andoni Estructuras de datos y algoritmosEditorial McGraw-Hill

(1999).

Rodríguez Baena, Luis; Fernandez Azuela, Matilde; Joyanes Aguilar Fundamentos de programación: algoritmos, Estructuras de datos y objetos. Editorial McGraw-Hill (2003).