• No se han encontrado resultados

Tema N° 3.- Apuntadores y Estructuras

N/A
N/A
Protected

Academic year: 2018

Share "Tema N° 3.- Apuntadores y Estructuras"

Copied!
25
0
0

Texto completo

(1)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 1 En los cursos de programación el estudio de los punteros siempre se ha considerado un reto para los alumnos, tanto en el aprendizaje como en su aplicación. En el lenguaje de programación C, los apuntadores son una de las características más poderosas y útiles, en el desarrollo de programas. El manejo de punteros requiere que el alumno modifique su forma de pensar con respecto al uso de los identificadores. Los punteros son variables que almacenan como valor la dirección de memoria que ocupa otro dato (una variable, constante, elementos de arreglos, funciones, entre otras); en otras palabras, los punteros hacen referencia a un tipo de dato almacenado en memoria.

Esta capacidad de los punteros permite que referencias a funciones, puedan ser utilizadas como argumentos en el llamado a otra función.

Los punteros guardan una relación muy estrecha con los arreglos y cadenas, proporcionando una vía alternativa para acceder a los elementos individuales del arreglo. Los punteros son el elemento fundamental en la creación de estructuras de datos dinámicas (listas, pilas, colas, listas enlazadas, árboles y grafos), a través de la asignación dinámica de memoria.

Aquí desarrollaremos los siguientes ítems:

Definición

Naturaleza de los Punteros

Declaración

Inicialización

Operaciones de Dirección e Indirección

Aritmética de Punteros

Relación entre Arreglos y Punteros

Punteros y Funciones

(2)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 2 Definición

Un puntero o un apuntador es una variable que almacena como dato la dirección de memoria de otro identificador como puede ser un arreglo, una función u otra variable. Los punteros son variables que almacenan como valor la dirección de memoria que ocupa otro dato (una variable, constante, elementos de arreglos, funciones, entre otras); en otras palabras, los punteros hacen referencia a un tipo de dato almacenado en memoria. Esta capacidad de los punteros permite que referencias a funciones, puedan ser utilizadas como argumentos en el llamado a otra función.

Hasta los momentos habíamos visto variables cuyos datos podían ser valores de tipo numérico, alfanumérico y lógico o booleanos, ahora estamos conociendo otro tipo de dato, como lo son las direcciones de memoria, que son capaces de almacenarlas en una variable especial conocida como apuntador.

Los punteros pueden ser usados para:

• Fundamentalmente son usados para el manejo de memoria en forma dinámica, permitiendo un uso más eficiente de este recurso. • Comunicar información entre una función y sus puntos de llamada. • Permite devolver varios datos desde una función mediante los

argumentos de la función.

• Permiten que referencias a otras funciones puedan ser especificadas como argumentos de otra función. (pasar funciones como argumentos).

(3)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 3 • Representan de una forma más conveniente los arreglos multidimensionales, permitiendo que un arreglo multidimensional sea reemplazado por un array de punteros de menor dimensión.

• Son el soporte de enlace que utilizan estructuras avanzadas de datos en memoria dinámica como las listas, pilas, colas y árboles.

Naturaleza de los Punteros

Entender cómo trabajan los punteros requiere un repaso de cómo se almacenan los datos en memoria. Primero debemos recordar que la memoria está compuesta por celdas de memoria y cada celda posee dos áreas, una que es la dirección (valor fijo permite identificar la posición de dicha celda) y la otra es la información (dato almacenado en la celda). Al momento de declarar una variable, por ejemplo int x, el compilador le asigna a x una dirección de memoria, fija, donde almacenará su valor. Los valores almacenados en memoria ocupan una o más celdas contiguas de memoria (palabras o bytes adyacentes). El número de celdas de memoria requeridas para almacenar un valor depende del tipo de dato. Por ejemplo, un carácter será almacenado en 1 byte (8 bits) de memoria; un entero normalmente necesita 2 bytes continuos. Un valor punto flotante puede necesitar 4 u 8 bytes. Para acceder a un valor de una variable, almacenado en memoria, se hace mención al nombre de la variable.

int x; x = 4;

printf("%d",x);

Hay dos operadores de apuntadores: & y *. & es un operador monario que devuelve la dirección de memoria de su operando. (Recuérdese que un operador monario sólo necesita un operando.)

Celda de Memoria

Dirección x Valor x

(4)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 4 El segundo operador de apuntadores, *, es el complemento de &. Es un operador monario que devuelve el valor que se encuentra en la dirección que le sigue.

Ejemplo:

Supongamos que v es una variable que representa un determinado dato.

El compilador automáticamente asignará celdas de memoria para este dato. Podemos acceder a los datos si conocemos su localización (la dirección) de la primera celda de memoria. La dirección de memoria de v puede se determinada mediante la expresión &v. Ahora vamos asignar la dirección de v a otra variable llamada, pv. Así, pv = &v

Esta nueva variable (pv) es un puntero a v, puesto que <<Apunta>> a la posición de memoria donde se almacena v, pv representa la dirección de v y no su valor, pv es referida como una variable apuntadora, La relación entre v y pv está ilustrada en la figura siguiente

Dirección de v Valor de v

pv v

El dato representado por v (es decir, el dato almacenado en las celdas de memoria de v) puede ser accedido mediante la expresión *pv, donde * es el operador indirección, que opera sólo sobre una variable puntero. Por tanto; *pv y v representa el mismo dato (el contenido de las mismas celdas de memoria).

Declaración

(5)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 5 debe ser igual al tipo de dato de la variable que ocupa la dirección de memoria que el puntero almacena. Para declarar un puntero se realiza igual que el resto de las variables, pero al nombre del puntero le precede el símbolo * (asterisco), que leeremos “puntero a”. Entonces se dice que un puntero apunta a un tipo de datos específico.

Sintaxis:

<Tipo_dato>* <nombre_puntero>;

equivale a

<Tipo_dato> *<nombre_puntero>;

Donde:

Tipo_dato: Es el tipo de dato del puntero.

Nombre_puntero: Es el nombre del puntero

Ejemplo:

int* : es un tipo de dato puntero a enteros.

float *: es un tipo de dato puntero a datos tipo float.

float* ptry; ptry, es un puntero que apunta a tipos de datos float. int *ptrx; ptrx, es un puntero que apunta a tipos de datos enteros.

También se puede decir:

*ptrx, es una variable que almacena direcciones de memoria que

contienen tipos de datos int (enteros).

*ptry, es una variable que almacena direcciones de memoria que

contienen tipos de datos float.

(6)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 6 Declaraciones de Punteros

int *PuntAInt; // Tipo puntero a enteros (int) char *PuntACar; // Tipo puntero a caracteres (char) double *punto; // Tipo puntero a double

Un puntero, puede apuntar a cualquier tipo de dato definido por el usuario, no sólo a tipos simples. Es muy importante tener en cuenta que primero debe declararse el tipo de datos al que apunta (un array, clase, función, etc.) y después el tipo de datos puntero.

Inicialización

Como pasa con todas las variables en C, cuando se declara un puntero sólo se reserva el espacio de memoria para almacenarlo, pero no se asigna ningún valor inicial, el contenido de la variable puntero permanecerá sin cambios, de modo que el valor inicial del puntero será aleatorio e indeterminado

(denominado comúnmente como basura). Debemos suponer que contiene una

dirección no válida de memoria. Al intentar realizar operaciones con punteros NO INICIALIZADOS, ocurrirá un error no sólo en el programa, sino también en el

sistema operativo, porque se intenta acceder a una dirección de memoria NO EXISTENTE o NO VÁLIDA. Todos los punteros deben ser inicializados antes de ser

utilizados.

A las variables de tipo punteros sólo pueden asignárseles: • el valor cero (0 o la constante NULL ),

• otro puntero con el mismo tipo de dato,

• una dirección de memoria de una variable que posea el mismo tipo de dato que el puntero. Las direcciones de memoria deben ser asignadas sólo con el operador de dirección & (ampersand).

Punteros Nulos:

(7)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 7 float *ptry = NULL;

int *ptrz;

Es posible realizar la asignación de un puntero a otro, si ambos son del mismo tipo de datos.

ptrz = ptrx; //el puntero ptrz recibe la dirección de memoria que tiene almacenada el puntero ptrx.

Operadores de Dirección e Indirección

Operador de Dirección o Referencia. (Operador &). Es un operador monario (sólo requiere un operando) que devuelve la dirección de memoria del operando, es decir, lo que hace es devolver la dirección que en memoria ocupa el objeto sobre el que se aplica. Literalmente significa “la dirección de”.

Un ejemplo de su uso para inicializar un puntero es: int x =10;

int *ptrx = &x;

ptrx, posee como valor la dirección de memoria que ocupa la variable x.

Entonces se dice que ptrx apunta a x

Celda de Memoria ptrx

Dirección Valor

0xF8E 0xF8A

Celda de Memoria x

Dirección Valor

(8)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 8 La representación gráfica

Este operador NO es aplicable a expresiones constantes, pues éstas no se almacenan en ninguna dirección de memoria específica sino que se incrustan en las instrucciones. Por ello, no es válido hacer directamente:

int px = &10; // Error 10 no es una variable con dirección propia

Tampoco es válido aplicar & a variables declaradas con la clase de almacenamiento register, ni campos de sólo lectura (readonly), pues si éstos pudiesen ser apuntados por punteros se correría el riesgo de poderlos modificar ya que a través de un puntero se accede a memoria directamente, sin tenerse en cuenta si en la posición accedida hay algún objeto, por lo que mucho menos se considerará si éste es de sólo lectura.

NOTA: El operador & puede aplicarse sólo a operandos lvalue (algo a lo

que se puede asignar un valor, como una variable).

Operador de Indirección o Desreferencia de memoria. (Operador *): Es un

operador monario que actúa sólo sobre operandos de tipo puntero. Este operador devuelve el valor de la variable a la que apunta el puntero. Es decir, devuelve el valor almacenado en la dirección de memoria apuntada por el puntero. Literalmente significa “el valor de”.

Ejemplo:

int x = 10; int *ptrx = &x; int z ;

z = *ptrx ; // se asigna a la variable z el valor 10.

Puntero Variable

ptrx x

(9)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 9 Con el operador de Indirección (*), también se pueden asignar valores a una dirección de memoria apuntada por un puntero, es decir, se puede alterar el valor de la variable a la que apunta un puntero.

Ejemplo:

int x = 10; int *ptrx = &x;

*ptrx = 30; // se asigna a la variable x el valor 30.

NOTA: No debemos confundir el operador * en la declaración

del puntero (int *p), con el operador * (asterisco) en las instrucciones (*p=10 o z=*p).

No se puede desreferenciar un puntero NULL, produce un error en tiempo de ejecución.

Ejemplo referenciando:

#include<stdio.h>

int main(void) {

int x = 99; int *p1, *p2;

p1 = &x; p2 = p1;

/* imprimir el valor de x dos veces */

printf(“Valores apuntados por p1 y p2: %d %d\n”, *p1, *p2);

/* imprimir la dirección de x dos veces */

printf(“Direcciones en p1 y p2: %p %p\n”, p1, p2);

return 0; }

Tras la secuencia de asignaciones p1 = &x;

(10)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 10

tanto p1 como p2 apuntan a x. Por tanto, tanto p1 como p2 se refieren al mismo objeto. A continuación se muestra un ejemplo de salida del programa, confirmando esto.

Valores apuntados por p1 y p2: 99 99 Direcciones en p1 y p2: 0063FE00 0063FE00

Obsérvese que las direcciones se muestran usando el modificador de formato de printf( ) %p. que hace que printf( ) muestre una dirección en el formato utilizado por la computadora en cuestión.

Ejemplo desreferenciando:

{

int* puntero; int variable;

puntero = &variable;

*puntero = 33; /* mismo efecto que variable=33 */ }

Varios apuntadores pueden apuntar a la misma variable: int* puntero1;

int* puntero2; int var;

puntero1 = &var; puntero2 = &var;

*puntero1 = 50; /* mismo efecto que var=50 */

var = *puntero2 + 13; /* var=50+13 */

Aritmética de Punteros

Los Apuntadores pueden ser utilizados como operandos válidos en los siguientes tipos de expresiones:

(11)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 11

• Relacionales.

Los apuntadores no pueden ser utilizados como operandos válidos con todos los operadores. Los apuntadores sólo pueden realizar:

Operaciones Aritméticas:

o Sumarle o restarle un valor entero: Incremento/Decremento.

Ejemplo:

ptrx++; ptrx--; ++ptrx; --ptrx;

ptrx=ptrx+5 ; ptrx=ptrx-4; ptrx+=3; ptrx-=2;

o Restar un apuntador de otro. Resta de direcciones de

memoria.

Ejemplo:

ptrx = ptrx – ptry;

Operaciones Relacionales: Es posible comparar dos variables de tipo

puntero en una expresión relacional, usando operaciones relacionales de igualdad (= =), desigualdad (!=) y comparación (<, >, =<, >=).

La aritmética de punteros, tiene sentido sólo cuando el puntero posee asignado varias direcciones continuas de memoria, es decir, cuando se ejecuta sobre un arreglo. Es muy poco probable que dos variables de un mismo tipo de datos posean direcciones contiguas de memoria a no ser que sean elementos adyacentes que formen parte de un arreglo.

Ejemplo

# include <stdio.h> void main()

{

(12)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 12

static int a[6]= { 1, 2, 3, 4, 5, 6]; px=&a[0]:

py=&a[5]:

printf (“px=%x py%x”, px, py); printf (“\n\npy- px=%x”, py - px); }

La ejecución del programa produce la siguientes salida:

px=52 py=5c

py – px=5

Relación entre Arreglos y Punteros

Los nombres de los arreglos, son un tipo especial de punteros, que apuntan a la dirección de memoria del primer elemento del arreglo. Recordemos que los arreglos poseen elementos almacenados en direcciones contiguas de memoria. Cada elemento del arreglo posee una dirección de memoria.

Ejemplo:

int v[10] = {0,1,2,3,4,5,6,7,8,9,}; int *ptrv;

ptrv = &v[0]; //se le asigna al puntero ptrv, la dirección de memoria del primer elemento del arreglo v;

//equivale a ptrv = v;

ptrv = v; //se asigna la dirección de v a ptrv.

Como dijimos anteriormente, el nombre del arreglo (v) es un puntero, que apunta, a la primera dirección de memoria del arreglo. Por lo tanto se está realizando una asignación de punteros. Cualquier posición de un elemento en el arreglo se puede obtener con el operador de dirección.

ptrv = &v[4]; //ptrv apunta a la posición 4 del arreglo. ptrv = &v[7]; //ptrv apunta a la posición 7 del arreglo.

Con aritmética de punteros, es posible acceder a la dirección de cada elemento del arreglo.

Ejemplo:

int v[10] = {0,1,2,3,4,5,6,7,8,9,}; int *ptrv;

(13)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 13

//Aritmética

ptrv + 2; //equivale a &v[2] ptrv + 6; //equivale a &v[6]

En ambos casos, ptrv no modifica la dirección de memoria a la que apunta.

En la aritmética de punteros la sumatoria de enteros a memorias (ptrv + n) se realiza en base a la cantidad de bytes del tipo de datos del puntero (ptrv + n* t_bytes).

Tipos Datos Tamaño Byte (máquina 16 bits) Tamaño Byte (máquina 32 bits)

char 1 byte 1 byte

int 2 bytes 4 bytes

long 4 bytes 4 bytes

float 4 bytes 4 bytes

Si el arreglo es de tipo int, cada posición del arreglo ocupa 2 bytes de memoria (máquinas de 16 bits), por lo tanto avanza (ptrv + (2 * 2))

En el siguiente ejemplo se inicia en la primera posición

int *ptrv, v[3] = {15, 18, 20, 46};

ptrv = v;//ptrv apunta a la dirección 2000

printf(“%d”, *ptrv); //valor 15

ptrv = ptrv + 1;//avanza a la posición de dirección 2002 //ptrv = 2000 + (1 * 2) = 2000 + 2 = 2002 printf(“%d”, *ptrv); //valor 18

ptrv+=2; //avanza a la posición de dirección 2006 //ptrv = 2000 + (2 * 2) = 2000 + 4 = 2006 printf(“%d”, *ptrv); //valor 46

1 5 1 8 2 0 4 6

(14)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 14

Resumen de las Operaciones con Punteros

1. A una variable puntero se le puede asignar la dirección de memoria de una variable ordinaria (pv=&p).

2. A una variable puntero se le puede asignar el valor de otra variable puntero (pv=py), siempre y cuando ambos punteros apunten al mismo tipo de datos o que el puntero pv sea un puntero genérico (puntero a void).

3. A una variable puntero se le puede asignar un valor nulo (cero) (pv=NULL, NULL es una constante simbólica con valor cero).

4. Una cantidad entera puede ser sumada o restada a una variable puntero (px+3, pv++).

5. Una variable puntero puede ser restada de otra siempre y cuando ambas apunten a elementos del mismo arreglo.

6. Dos variables punteros pueden ser comparadas siempre que ambas apunten a datos del mismo tipo de datos.

Punteros y Funciones

Un área en la cual desempeñan un papel prominente los apuntadores, en el lenguaje C, es en la transmisión de parámetros a funciones. Por lo común, los parámetros se transmiten por valor a una función en C, es decir, se copian los valores transmitidos en los parámetros de la función llamada en el momento en que se invoca. Si cambia el valor de un parámetro dentro de la función, no cambia su valor en el programa que la llama. Por ejemplo considérese el siguiente fragmento:

... X=5;

printf (“%d\n”, x); funct(x);

printf(“%d\n”, x); ...

(15)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 15

++y;

printf(“%d\n,y); return;

}

La ejecución del programa sería: imprime el número 5 y después llama a funct. El valor de "x", que es 5, se copia en "y" y comienza la ejecución de funct. Después, imprime el número 6 y regresa funct. Sin embargo, cuando se incrementa el valor de "y", el valor de "x" permanece invariable. Así, imprime el número 5, "x" y "y" refieren a 2 variables diferentes.

Si deseamos usar funct para modificar el valor de "x", debemos de transmitir la dirección de "x" de la siguiente manera:

... X=5;

printf (“%d\n”, x); funct(&x); printf(“%d\n”, x); ...

void funct (int *py) {

++(*py);

printf(“%d\n, *py); return;

}

(16)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 16

Precauciones con los Apuntadores

Apuntadores No Inicializados:

Si se altera el valor al que apunta un puntero no inicializado, se estará modificando cualquier posición de la memoria.

main() {

int* puntero;

*puntero = 1200; /* Se machaca una zona cualquiera de la memoria */

}

Confusión De Tipos:

Un puntero a un tipo determinado puede apuntar a una variable de cualquier otro tipo. Aunque el compilador lo puede advertir, no es un error. (Afortunadamente, esto no ocurre en C++).

main() {

int p;

double numero; int* puntero;

p = &numero; /* incorrecto,

pero el compilador no aborta */

*p = 33; /* Un desastre */

}

Apuntadores a variables locales fuera de ámbito:

Si un puntero apunta a una variable local, cuando la variable desaparezca el puntero apuntará a una zona de memoria que se estará usando para otros fines. Si se des-referencia el puntero, los resultados son imprevisibles y a menudo catastróficos.

main() {

(17)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 17

while (...) {

int local;

puntero = &local;

/* ‘puntero’ apunta a una variable local */ ...

*puntero = 33; /* correcto */

} ...

/* ahora ‘puntero’ apunta a una zona de memoria inválida */

(18)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 18

Estructuras

El uso de estructuras como una representación o aproximación de registros de datos, ha sido una de las herramientas más idóneas usada en la Programación Estructurada para poder agrupar varios tipos de datos primitivos en un solo a la final.

Aquí desarrollaremos los siguientes ítems:

Conceptos Básicos

Acceso a los componentes de una estructura.

Arreglos de Estructuras

Estructuras Anidadas

Apuntadores a estructuras.

(19)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 19

Conceptos Básicos

Una Estructura es una colección de variables simples, que pueden contener

diferentes tipos de datos. Es un tipo de dato definido por el usuario. Son también conocidas como Registros.

Ayudan a organizar y manejar datos complicados en programas debido a que agrupan diferentes tipos de datos a las que se les trata como una sola unidad en lugar de ser vistas como unidades separadas.

En C se forma una estructura utilizando la palabra reservada struct, seguida por un campo etiqueta opcional, y luego una lista de miembros dentro de la estructura. La etiqueta opcional se utiliza para crear otras variables del tipo particular de la estructura:

struct campo_etiqueta{ tipo_miembro miembro_1; tipo_miembro miembro_2; tipo_miembro miembro_3; :

:

tipo_miembro miembro_n; };

Un punto y coma finaliza la definición de una estructura puesto que ésta es realmente una sentencia C. Algunos de los ejemplos usan la estructura:

struct stbarco{ char tipo[15]; char modelo[15]; char titular[20]; int anno;

long int horas_motor; float precioventa; };

En un programa, podemos asociar una variable con una estructura utilizando una sentencia similar a la siguiente:

(20)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 20

La sentencia define stbarco_usado de tipo struct stbarco. La declaración requiere el uso del campo etiqueta de la estructura. Si esta sentencia está contenida dentro de una función, entonces la estructura, llamada stbarco_usado, tiene un ámbito local a esa función. Si la sentencia está contenida fuera de todas las funciones de programa, la estructura tendrá un ámbito global. Es posible declarar una variable usando esta sintaxis:

struct stbarco{ char tipo[15]; char modelo[15]; char titular[20]; int anno;

long int horas_motor; float precioventa; };stbarco_usado;

Aquí la declaración de variable va antes del punto y coma final. Cuando se asocia sólo una variable con el tipo estructura, el campo etiqueta puede ser eliminado, por lo que sería posible escribir:

struct { char tipo[15]; char modelo[15]; char titular[20]; int anno;

long int horas_motor; float precioventa; };stbarco_usado;

Acceso a los Componentes de una Estructura

Para accesar a los miembros de las estructuras se usa el punto u operador miembro (.). La sintaxis es:

estructuraNombre.miembroNombre

Por ejemplo en:

(21)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 21

Aquí, stbarco_usado es el nombre asociado con la estructura, y modelo es una variable miembro de la estructura, otro ejemplo:

gets(stbarco_usado.tipo);

Esta sentencia leerá la marca del stbarco_usado en el arreglo de caracteres, mientras la próxima sentencia imprimirá el precio de venta de stbarco_usado en la pantalla.

printf(“%f”, stbarco_usado.precioventa);

Ejemplo de estructuras:

#include <stdio.h> #include <conio.h> struct datos {

char num_control[9]; char nombre[30]; int edad;

char sexo;

char domicilio[30]; };

struct datos alumno; void main ( )

{

clrscr( );

printf(“\nIntroduce los datos del alumno:”); printf(“\nNúmero de Control:”);

gets(alumno.num_control); printf(“\nNombre:”); gets(alumno.nombre); printf(“\nEdad:”);

scanf(“%d”,&alumno.edad); printf(“\nSexo:”);

alumno.sexo=getchar( ); printf(“\nDirección:”); gets(alumno.domicilio);

printf(“\nLos datos capturados fueron:”); printf(“\nNúmero de Control:”);

puts(alumno.num_control); printf(“\nNombre:”); puts(alumno.nombre); printf(“\nEdad:”);

printnf(“%d”,alumno.edad); printf(“\nSexo:”);

(22)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 22

printf(“\nDirección:”); puts(alumno.domicilio); getch ( );

}

Arreglos de Estructuras

Pueden ser construidas, es decir, conceptuar a los elementos de un arreglo como estructuras, esto se puede hacer de la siguiente manera:

struct datos {

char num_control[9]; char nombre[30]; int edad;

char sexo;

char domicilio[30]; };

struct datos alumnos[35]; /*Esta es la variable arreglo de estructura*/

Para tener acceso a una determinada estructura, se indexa el nombre de la estructura de la siguiente manera: alumnos[i].nombre; aquí sabemos el nombre del alumno que se encuentra en la posición i del arreglo, y de esta manera para todos los datos.

Estructuras Anidadas

Una estructura puede contener otras estructuras llamadas estructuras anidadas. Las estructuras anidadas ahorran tiempo en la escritura de programas

que utilizan estructuras similares. Se han de definir los miembros comunes solo una vez en su propia estructura y a continuación utilizar es estructura como un miembro de estructura. Consideremos las siguientes dos definiciones de estructuras:

struct empleado {

(23)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 23

long int cod_postal; double salario; };

struct clientes {

char nombre_cliente[30]; char direccion[25]; char ciudad[20]; char provincia[20]; long int cod_postal; double saldo; };

Estas estructuras contienen muchos datos diferentes, aunque hay datos que están solapados. Así, se podría disponer de una estructura, info_dir que contuviera los miembros comunes.

struct info_dir {

char direccion[25]; char ciudad[20]; char provincia[20]; long int cod_postal; };

Esta estructura se puede utilizar como miembro de las otras estructuras, es decir anidarse.

struct empleado {

char nombre_emp[30]; struct info_dir direccion_emp; double salario;

};

struct clientes {

char nombre_cliente[30]; struct info_dir direccion_clien; double saldo;

};

Apuntadores a Estructuras

(24)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 24

cualquier otro objeto y se declara un puntero estructura tal como se declara cualquier otra variable estructura: especificando un puntero en lugar del nombre de la variable estructura.

struct persona {

char nombre[30]; int edad;

int altura; int peso; };

struct persona empleado; struct persona persona *p; p = &empleado;

Cuando se referencia un miembro de la estructura utilizando el nombre de la estructura, se especifica la estructura y el nombre del miembro separado por un punto (.). Para referenciar el nombre de una persona, utilice empleado.nombre. Se referencia una estructura utilizando el puntero estructura. Se utiliza el operador -> para acceder a un miembro de ella.

Paso de Estructuras a las Funciones

C permite pasar estructuras a funciones, bien por valor o bien por referencia utilizando el operador &. Si la estructura es grande, el tiempo necesario para copiar un parámetro struct a la pila puede ser prohibitivo.

En tales casos, se debe considerar el método de pasar la dirección de la estructura. El siguiente programa muestra el pase de la dirección de una estructura a una función para entrada de datos.

La misma variable la pasa por valor a otra función para salida de los campos.

#include <stdio.h>

/*Define el tipo de estructura info_persona*/ struct info_persona

{

(25)

Recopilado por: MSc. Leonardo Javier Malavé Quijada

Unidad Curricular: Intensivo 2016.- Algorítmica y Programación – Trayecto I Página 25

char ciudad[25]; char provincia[25]; char codigopostal[6]; };

/*Prototipos de funciones*/

void entrad_pna(struct info_persona *pp); void ver_info(struct info_persona p); void main ( )

{

struct info_persona reg_dat;

entrad_pna(&reg_dat); /*Pasa por referencia la variable*/ ver_info(reg_dat); /*Pasa por valor*/

clrscr( );

printf(“\nPulsa cualquier carácter para continuar\n”); getchar( );

}

void entrad_pna (struct info_persona *pp) {

clrscr( );

puts(“\nEntrada de datos de la Persona\n”);

/*Para acceder a los campos se utiliza el selector -> */ printf(“\nNombre:”);

gets(pp->nombre); printf(“\nCalle:”); gets(pp->calle); printf(“\nCiudad:”); gets(pp->ciudad); printf(“\nProvincia:”); gets(pp->provincia); printf(“\nCódigo Postal:”); gets(pp->codigopostal); }

void ver_info (struct info_persona p) {

clrscr( );

puts(“\n\t Información relativa a la persona”); puts(p.nombre);

Referencias

Documento similar

En efecto, según la Ley Electoral 29/1948, de 6 de febrero, sobre «Normas para la elección del Senado de la República» (y las sucesivas modificaciones e inte- graciones), si por

Como se aprecia en la parte inferior del cuadro se alude a los tipos de documentos que se identifican en las instituciones, Organizaciones comunitarias y vinculadas nombradas en la

Si es cierta se ejecuta el Bloque de sentencias y luego las instrucciones de operación en ese orden y se vuelve a evaluar la condición. • Si la condición es falsa termina

Volviendo a la jurisprudencia del Tribunal de Justicia, conviene recor- dar que, con el tiempo, este órgano se vio en la necesidad de determinar si los actos de los Estados

¿De qué manera se relaciona la tecnología y los sistemas de información con la calidad de la formación profesional de los alumnos del segundo semestre del

● La condición de contador &lt; fin puede utilizar cualquier condición explicada en el tema pasado para la estructura if.. Comparadores de

En este sentido, los mencionados Autos prosiguen en el mismo Funda- mento señalando que «desconocer e inadmitir como norma generalizada los escritos de denuncias presentadas por

Tras establecer un programa de trabajo (en el que se fijaban pre- visiones para las reuniones que se pretendían celebrar los posteriores 10 de julio —actual papel de los