UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1....

28
UNIDAD IV ESTRUCUTRAS DE DATOS Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que está formado de una colección finita y ordenada de datos del mismo tipo. Es la estructura natural para modelar listas de elementos iguales. El tipo de acceso a los arreglos unidimensionales es el acceso directo, es decir, podemos acceder a cualquier elemento del arreglo sin tener que consultar a elementos anteriores o posteriores, esto mediante el uso de un índice para cada elemento del arreglo que nos da su posición relativa. Para implementar arreglos unidimensionales se debe reservar espacio en memoria, y se debe proporcionar la dirección base del arreglo, la cota superior y la inferior. La declaración de arreglos sigue la estructura general de las declaraciones, es decir consta de un especificador de clase de almacenamiento opcional, un especificador de tipo de dato, el identificador del arreglo, el operador u operadores de arreglo con su respectiva dimensión y el inicializador es opcional. Sintaxis: Tipo de dato nombre_del_arreglo [dimensión]; Como ejemplo se tiene: int a[5]; float arre[50]; char vector[20]; El tipo de acceso a los arreglos unidimensionales es el acceso directo, es decir, podemos acceder a cualquier elemento del arreglo sin tener que consultar a elementos anteriores o posteriores, esto mediante el uso de un índice para cada elemento del arreglo que nos da su posición relativa. Para implementar arreglos unidimensionales se debe reservar espacio en memoria, y se debe proporcionar la dirección base del arreglo, la cota superior y la inferior. Figura 13. Arreglo Unidimensional Un arreglo (array) matriz o vector es un conjunto ordenado de elementos homogéneos; esto es, un arreglo unidimensional va de uno en uno empezando en la localidad número cero y de esta manera se puede accesar en cualquier instante a la localidad que se desee. Un arreglo se Elemento 1 Elemento 2 Elemento 3 Elemento 4 . . . Elemento N

Transcript of UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1....

Page 1: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que está formado de una colección finita y ordenada de datos del mismo tipo. Es la estructura natural para modelar listas de elementos iguales. El tipo de acceso a los arreglos unidimensionales es el acceso directo, es decir, podemos acceder a cualquier elemento del arreglo sin tener que consultar a elementos anteriores o posteriores, esto mediante el uso de un índice para cada elemento del arreglo que nos da su posición relativa. Para implementar arreglos unidimensionales se debe reservar espacio en memoria, y se debe proporcionar la dirección base del arreglo, la cota superior y la inferior. La declaración de arreglos sigue la estructura general de las declaraciones, es decir consta de un especificador de clase de almacenamiento opcional, un especificador de tipo de dato, el identificador del arreglo, el operador u operadores de arreglo con su respectiva dimensión y el inicializador es opcional. Sintaxis: Tipo de dato nombre_del_arreglo [dimensión]; Como ejemplo se tiene: int a[5]; float arre[50]; char vector[20]; El tipo de acceso a los arreglos unidimensionales es el acceso directo, es decir, podemos acceder a cualquier elemento del arreglo sin tener que consultar a elementos anteriores o posteriores, esto mediante el uso de un índice para cada elemento del arreglo que nos da su posición relativa. Para implementar arreglos unidimensionales se debe reservar espacio en memoria, y se debe proporcionar la dirección base del arreglo, la cota superior y la inferior.

Figura 13. Arreglo Unidimensional Un arreglo (array) matriz o vector es un conjunto ordenado de elementos homogéneos; esto es, un arreglo unidimensional va de uno en uno empezando en la localidad número cero y de esta manera se puede accesar en cualquier instante a la localidad que se desee. Un arreglo se

Elemento 1

Elemento 2

Elemento 3

Elemento 4 . . .

Elemento N

Page 2: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

dice que es homogéneo porque todos sus elementos son del mismo tipo, por eso nunca podremos encontrar un arreglo que contenga en su interior valores enteros conjuntamente con valores de tipo carácter o veceversa. Los arreglos están formados por un conjunto de elementos de un mismo tipo de datos que se almacenan bajo un mismo nombre, y se diferencian por la posición que tiene cada elemento dentro del arreglo de datos. Al declarar un arreglo, se debe inicializar sus elementos antes de utilizarlos. Para declarar un arreglo tiene que indicar su tipo, un nombre único y la cantidad de elementos que va a contener. Por ejemplo, las siguientes instrucciones declaran tres arreglos distintos:

float costo_partes[50];

int edad_empleados [100];

float precios_acciones [25];

int calificaciones [100];

tipo nombre_arreglo tamaño del arreglo

Figura 14. Estructura de un arreglo

Para acceder a valores específicos del arreglo, use un valor de índice que apunte al elemento deseado. Por ejemplo, para acceder al primer elemento del arreglo calificaciones debe utilizar el valor de índice 0 (calificaciones[0]). Los programas en C siempre indican el primer elemento de un arreglo con 0 y el último con un valor menor en una unidad al tamaño del arreglo.

El índice siempre va entre corchetes e indica la posición y orden de un vector, por ejemplo estos serían ejemplos de arreglos y sus índices.

A[1], A[2], A[3], … , A[N]

Arr[0], arr[1], arr[2], … , arr[n]

Calificaciones [0]

Calificaciones [1]

Calificaciones [2] . . .

Calificaciones [99]

Page 3: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

La inicialización de arreglos se realiza por medio del conjunto de valores iniciales de los distintos elementos del arreglo, agrupado por medio de llaves. La asignación de valores al arreglo unidimensional es en orden de secuencia con respecto al valor del índice [0] a [N]. Asignación de un arreglo de tipo entero llamado “ a “ y uno de tipo real llamado “ datos “: int a[5] = {1,2,3,5,6}; float datos[6] = { 3.4, 6.8, 2.2, 10, 6.6, 9.9 } En el siguiente ejemplo se muestra el llenado de un arreglo (vector) con valores de cero a 10, empezando a llenar en la localidad cero y terminando en la localidad nueve. Algoritmo: inicio constante Tam 10 declarar variables

entero i, a[Tam] para (i = 0; i < Tam; i++) hacer a[i] ← 0 fin_para para (i = 0; i < Tam; i++) hacer escribir ( ‘ a[i] ‘ ) fin_para return 0; fin Programa: #include <stdio.h> #define Tam 10 int main(void) { int i, a[Tam]; for(i = 0; i < Tam; i++) a[i] = 0; for(i = 0; i < Tam; i++) printf ("%d\n", a[i]); return 0; }

Cuando se usan arreglos, una operación común es usar una variable índice para acceder a los elementos de un arreglo. Suponiendo que el arreglo se llamará valores, y la variable índice i contiene el número 3, la siguiente instrucción asignará el valor 400 a dicho vector, como si fuera una variable simple al ocupar una posición de memoria:

Valores [3] ← 400

Valores [3] = 400;

Partes de un arreglo:

Page 4: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

Nombre X[0] X[1] X[2] X[3] X[4] X[5] X[6] e índice Elemento1 Elemento2 Elemento3 Elemento7

Figura 15. Elementos de un arreglo Los componentes. Hacen referencia a los elementos que forman el arreglo, es decir, a los valores que se almacenan en cada una de las casillas del mismo. Los índices, permiten hacer referencia a los componentes del arreglo, en forma individual especifican cuántos elementos tendrá el arreglo y además, de qué modo podrán accesarse a esos componentes.

Componentes

Figura 16. Componentes de un arreglo

Las operaciones que se pueden realizar con vectores durante el proceso de resolución de un problema son: · Lectura/ escritura · Asignación · Actualización (inserción, eliminación, modificación) · Recorrido (acceso secuencial) · Ordenación · Búsqueda Ejemplos: Sea arre un arreglo de 70 elementos enteros con índices enteros. Su representación nos queda:

23 778 10 51 100 ……. 11 99

“0” “1” “2” “3” “4” …….. “68” “69”

Figura 17. Arreglo de enteros

S1 S2 S3 . . . SN

14.0 8.0 10.5 4.5 12.0 5.5 10.0

Page 5: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

Lectura El proceso de lectura de un arreglo consiste en leer y asignar un valor a cada uno de sus elementos. Normalmente se realizan con estructuras repetitivas, aunque pueden usarse estructuras selectivas. Usamos los índices para recorrer los elementos del arreglo: Algoritmo: para ( i = 1; i <= 70; i++ ) hacer leer ( arre[i]) fin_desde Programa: for ( i = 1; i <= 70; i++ ) scanf ( “%d” , & arre [i]);

Escritura: Es similar al caso de lectura, sólo que en vez de leer el componente del arreglo, lo escribimos. Algoritmo: leer (N) para ( i = 1 ; i <= N ; i++ ) hacer escribir ( arre[i] ) fin_para Programa: scanf ( “%d” , & N); for ( i = 1; i <= N; i++ ) printf ( “ %d \n ” , arre [i]);

Asignación: No es posible asignar directamente un valor a todo el arreglo; sino que se debe asignar el valor deseado en cada componente. Con una estructura repetitiva se puede asignar un valor a todos los elementos del vector.

Por ejemplo:

arre[1] = 120;(asignación de un valor constante único a una casilla del vector) arre[3] = arre[1] / 4; (asignar una operación) Se puede asignar un valor constante a todos los elementos del vector: Algoritmo: para ( i = 1; i <= 5; i++ ) hacer arre[i] ← 3 fin_desde Programa: for ( i = 1; i <= 5; i++ ) arre [i] = 3; O bien

Page 6: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

arre = 3 (con arre del tipo arreglo) Inicialización Para inicializar con cero todos los elementos del arreglo: Algoritmo: para ( i = 1; i <= 70; i++ ) hacer arre[i] ← 0 fin_para Programa: for ( i = 1; i <= 70; i++ ) arre [i] = 0;

0 0 0 0 0 ……. 0 0

1 2 3 4 5 ........ 69 70

Arre [ 70 ]

Figura 18. Arreglo con for

Acceso Secuencial. (Recorrido)

El acceso a los elementos de un vector puede ser para leer en él o para escribir (visualizar su contenido). Recorrido del vector es la operación de efectuar una acción general sobre todos los elementos de ese vector.

Actualización. Incluye añadir (insertar), borrar o modificar algunos de los ya existentes. Se debe tener en cuenta si el arreglo está o no ordenado. Añadir datos a un vector consiste en agregar un nuevo elemento al final del vector, siempre que haya espacio en memoria.

Ejemplo. Algoritmo:

inicio declarar variables entero i entero a[ 5 ] para ( i = 0; i < 4; i++ ) hacer excribir ( ‘ Ingrese el elemento: ‘ ) leer ( a [ i ] ) fin_para para ( i = 0; i < 4; i++ ) hacer excribir ( ‘ Elemento: ‘ , a [ i ] ) fin_para pausa fin

Page 7: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

Programa: #include<stdio.h> #include<conio.h> void main() { int a[5]; // Definición de un arreglo de 5 posiciones int i; // Pedimos el ingreso de 5 números for(i=0; i<4; i++)

//No olvidar que los arreglos van de 0 a longitud-1 { printf(“ Ingrese el elemento: ”); scanf(“%d”,&a[i]); }

// Para imprimir será for(i=0; i<4; i++) { printf(“ Elemento: %d ”,a[i]); }

getch(); } 4.1.2. Arreglos numéricos y de caracteres Un vector a de 10 enteros de tipo int se declara así: int a[10]; El vector a comprende los elementos a[0], a[1], a[2], . . . , a[9], todos de tipo int. Los índices de los vectores en C empiezan en cero. Al igual que ocurría con las variables “normales”, podemos dar valor a los elementos de un arreglo al principio del programa. Esta vez los indicaremos todos entre llaves, separados por comas Algoritmo: inicio declarar variables entero numero [ 5 ] = { 200, 150, 100, -50, 300 } entero suma suma = numero [0] + numero[1] + numero [2] + numero[3] + numero [4] escribir ( ‘ Su suma es ‘, suma ) pausa fin Programa: #include <stdio.h> main() { int numero[5] ={200,150,100,-50,300}; //Un array de 5 números enteros int suma; // Un entero que será la suma

Page 8: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

suma = numero[0]+numero[1]+numero[2]+numero[3]+numero[4]; printf("Su suma es %d", suma);

getch(); } En una misma línea puedes declarar más de un vector, siempre que todos compartan el mismo tipo de datos para sus componentes. Las cadenas en C son vectores de caracteres (elementos de tipo char) con una peculiaridad: el texto de la cadena termina siempre en un carácter nulo. El carácter nulo tiene código ASCII 0 y podemos representarlo tanto con el entero 0 como con el carácter ’\0’. Declaración de cadenas Las cadenas se declaran como vectores de caracteres, así que debes proporcionar el número máximo de caracteres que es capaz de almacenar: su capacidad. Esta cadena, por ejemplo, se declara con capacidad para almacenar 10 caracteres: char a[10]; Puedes inicializar la cadena con un valor en el momento de su declaración: char a[10] = "cadena";

Se muestra la declaración como un vector de 10 caracteres y lo hemos inicializado asignándole la cadena "cadena". Es decir, es como si hubiésemos inicializado la cadena de este otro modo, equivalente: char a[10] = { ’c’, ’a’, ’d’, ’e’, ’n’, ’a’, ’\0’ };

4.2. Arreglos bidimensionales

4.2.1. Concepto y forma general Los arreglo bidimensionales son una forma de lograr que nuestro programa pueda hacer tablas, utilizando un índice que será siempre un dato del tipo entero. La mayoría de las definiciones de qué es una tabla son como la siguiente, "Una tabla es un conjunto de variables que comparten el mismo tipo de dato y nombre y a las que se hace referencia a través de un índice" (el índice como ya se dijo antes debe ser un tipo de dato entero). Este tipo de arreglos al igual que los anteriores es un tipo de dato estructurado, finito ordenado y homogéneo. El acceso a ellos también es en forma directa por medio de un par de índices. Los arreglos bidimensionales se usan para representar datos que pueden verse como una tabla con filas y columnas. La primera dimensión del arreglo representa las columnas, cada elemento contiene un valor y cada dimensión representa una relación.

Elemento 1,1 ….. Elemento 1,n Elemento 2,1 …. Elemento 2,n Elemento 3,1 …. Elemento 3,n …. …. …. Elemento m,1 …. Elemento m,n

Page 9: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

Figura 19. Matriz M x N

También es importante mencionar que algunos autores hacen uso del termino "vector" en los lenguajes de programación (igual que en las matemáticas) para referirse a las tablas de una sola dimensión y que matriz siempre se refiere a tablas bidimensionales. Sintaxis de un arreglo bidimensional: Tipo de dato nombre del arreglo [filas][columnas]; La representación en memoria se realiza de dos formas: almacenamiento por columnas o por renglones. Un arreglo bidimensional “ a “, que contienen tres filas y cuatro columnas (es decir un arreglo de tres por cuatro). En general, a este tipo de arreglo con m filas y n columnas se le llama arreglo de n x m (bidimensional). Es un conjunto de datos homogéneo, finito y ordenado, donde se hace referencia a cada elemento por medio de dos índices. El primero se utiliza para los renglones (filas) y el segundo para las columnas. También puede definirse como un arreglo de arreglos. Internamente en memoria se reservan MxN posiciones consecutivas para almacenar todos los elementos del arreglo. Declaración de una matriz: arreglo [ liminf1, limsup1, liminf2, limsup2 ]

filas columnas Por ejemplo: 1 <= I <= M 1 <= J <= N Se representaría como se muestra a continuación en forma de una tabla 1 2 J N

1 2 I M

Figura 20. Declaración de una matriz

Algoritmo para el recorrido por filas: constantes M =valor1 N = valor2 declarar variables real Matriz [M][N] para ( i = 1; i<= M; i++ ) hacer

… …

... …

Page 10: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

para ( j = 1; j<= N; j++ ) hacer escribir ( Matriz [ i] [j ] ) fin_desde fin_desde Programa: #include <stdio.h> #define M valor1 #define N valor2 main() { float Matriz[M][N] //Un array de M x N números reales for(i=1;i<=M;i++) for ( j = 1; j<= N; j++ ) printf(" %f ", Matriz [M][N]);

getch(); } El recorrido por columnas se hace de manera similar, invirtiendo el sentido de los índices. constantes M valor1 N valor2 declarar variables real Matriz [N][M] para ( i = 1; i<= N; i++ ) hacer para ( j = 1; j<= M; j++ ) hacer escribir ( Matriz [ i] [j ] ) fin_desde fin_desde Programa: #include <stdio.h> #define M valor1 #define N valor2 main() { float Matriz[N][M] //Un array de M x N números reales for(i=1;i<=N;i++) for ( j = 1; j<= M; j++ ) printf(" %f ", Matriz [N][M]);

getch(); } Ejemplos. 1) Rellenar una matriz identidad de 4 por 4 elementos. Una matriz identidad es aquella en la que la diagonal principal está llena de unos y el resto de los elementos son cero. Para llenar la matriz identidad se debe verificar que cuando los índices i y j sean iguales, la posición vale 1, en caso contrario se asigna cero al elemento i, j.

1 0 0 0 0 1 0 0

Page 11: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

0 0 1 0 0 0 0 1

Figura 21. Matriz Identidad

Algoritmo inicio para ( i = 1; i<= 4; i++ ) hacer para ( j = 1; j <= 4; j++) hacer si ( i = j ) entonces Matriz [i] [j] 1 si_no Matriz[i] [j] 0 fin_si fin_desde fin_desde fin Programa: #include <stdio.h> void main() { for(i=1;i<=4;i++) for ( j = 1; j<= 4; j++ ) if (i == j ) Matriz [i][j] = 1; else Matriz [i][j] = 0; getch(); } Las operaciones en arreglos pueden clasificarse de la siguiente forma: a) lectura Este proceso consiste en leer un dato de un arreglo y asignar un valor a cada uno de sus componentes. La lectura se realiza de la siguiente manera: Algoritmo: escribir ( ‘ Cuantos valores deseas que tenga el arreglo ‘ ) leer ( N ) para ( i=1; i<= N; i++ ) hacer leer ( arreglo[i] ) Programa: printf ( “ Cuantos valores deseas que tenga el arreglo “); scanf (“%d”, &N); for ( i=1; i<= N; i++ ) scanf ( “%d”, & arreglo [i] ); b) escritura Consiste en después de asignarle valores a cada elemento del arreglo, mostrarlos en pantalla. La escritura se realiza de la siguiente manera:

Page 12: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

Algoritmo: escribir ( ‘ Cuantos valores deseas que tenga el arreglo ‘ ) leer ( N ) para ( i=1; i<= N; i++ ) hacer leer ( arreglo[i] ) para ( i=1; i<= N; i++ ) hacer escribir ( arreglo [i] ); Programa: printf ( “ Cuantos valores deseas que tenga el arreglo “); scanf (“%d”, &N); for ( i=1; i<= N; i++ ) scanf ( “%d”, &arreglo [i] ); for ( i=1; i<= N; i++ ) printf( “ %d “, arreglo [i] ); c) asignación No es posible asignar directamente un valor a todo el arreglo, por lo que se realiza mediante los ciclo de repetición cualquiera de ellos como el for, el do – while ó el while con cualquiera de ellos el resultado es exactamente el mismo, y es de la manera siguiente: Algoritmo: escribir ( ‘ Cuantos valores deseas que tenga el arreglo ‘ ) leer ( N ) para ( i=1; i<= N; i++ ) hacer arreglo[i] i Programa: printf ( “ Cuantos valores deseas que tenga el arreglo “); scanf (“%d”, &N); for ( i=1; i<= N; i++ ) arreglo [i] = i; En el caso anterior el arreglo es llenado propiamente con la misma variable del ciclo for, por lo tanto; el arreglo contiene valores que van del 1 al valor N que dio el usuario. d) actualización Dentro de esta operación se encuentran las operaciones de eliminar, insertar y modificar datos. Para realizar este tipo de operaciones se debe tomar en cuenta si el arreglo está o no ordenado. La definición formal del parámetro le permite al compilador determinar las características del valor del puntero que será pasado en tiempo de ejecución. 4.2.2. Arreglos numéricos y de caracteres En una cadena que definamos como “char texto[40]” lo habitual es que realmente no ocupemos las 39 letras que podríamos llegar a usar. Si guardamos 9 letras (y el carácter nulo que marca el final), tendremos 30 posiciones que no hemos usado. Pero estas 30 posiciones generalmente contendrán “basura”, lo que hubiera previamente en esas posiciones de memoria, porque el compilador las reserva para nosotros pero no las “limpia”, por lo tanto el carácter que marca el final de nuestra cadena es el nulo “/0”.

Page 13: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

Hay una función de cadena predefinida por lenguaje C que nos dice cuantas letras hemos usado realmente en nuestra cadena sin necesidad de contabilizarlo nosotros mismos, lo hace automáticamente y es “strlen”, que se usa así: Algoritmo: inicio declarar variables carácter texto[ 40 ] escribir ( ‘ Introduce una palabra: ‘ ) leer ( texto ) escribir ( ‘ Has tecleado ‘ , strlen (texto) , ‘ letras ‘ ) pausa fin Programa: #include <stdio.h> #include <string.h> main() { char texto[40]; printf("Introduce una palabra: "); scanf("%s", texto); printf("Has tecleado %d letras", strlen(texto)); getch(); } Como es de esperar, si escribimos “Hola”, esta orden nos dirá que hemos tecleado 4 letras (no cuenta el carácter nulo “\0” que se añade automáticamente al final). Si empleamos esta orden, o alguna de las otras órdenes relacionadas con cadenas de texto que veremos en este tema, debemos incluir la cabecera <string.h>, que es donde se definen todas ellas. Hemos visto que si leemos una cadena de texto con “scanf”, se paraba en el primer espacio en blanco y no seguía leyendo a partir de ese punto. Existen otras órdenes que están diseñadas específicamente para manejar cadenas de texto, y que nos podrán servir en casos como éste. Para leer una cadena de texto (completa, sin parar en el primer espacio), usaríamos la orden “gets”, así:

gets(texto); De igual modo, para escribir un texto en pantalla podemos usar “puts”, que muestra la cadena de texto y avanza a la línea siguiente:

puts(texto); Sería equivalente a esta otra orden:

printf("%s\n", texto); Cuando queremos dar a una variable el valor de otra, normalmente usamos construcciones como a = 2, o como a = b. Pero en el caso de las cadenas de texto, esta NO es la forma correcta, no podemos hacer algo como saludo = "hola" ni algo como texto1 = texto2. Si hacemos algo así, haremos que las dos cadenas estén en la misma posición de memoria, y que los cambios que hagamos a una de ellas se reflejen también en la otra. La forma correcta de guardar en una cadena de texto un cierto valor es:

Page 14: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

strcpy (destino, origen);

Es decir, debemos usar una función llamada strcpy (cadena destino, cadena origen), que se encuentra también en <string.h>. Vamos a ver dos ejemplos de su uso:

strcpy (saludo, "hola"); strcpy (textoDefinitivo, textoProvisional);

En este ejemplo el mensaje cadena “hola” es copiado en la variable llamada saludo. Es nuestra responsabilidad que en la cadena de destino haya suficiente espacio reservado para copiar lo que queremos. Si no es así, estaremos sobrescribiendo direcciones de memoria en las que no sabemos qué hay. Para evitar este problema, tenemos una forma de indicar que queremos copiar sólo los primeros n bytes de origen, usando la función strncpy, así:

strncpy (destino, origen, n);

Vamos a ver un ejemplo, que nos pida que tecleemos una frase y guarde en otra variable sólo las 4 primeras letras: Algoritmo: inicio declarar variables carácter texto1[ 40 ] carácter texto2[ 40 ] carácter texto3[ 10 ] limpiar pantalla escribir ( ‘ Introduce una frase: ‘ ) leer ( texto1 ) copiar_cadena (text2, texto1) escribir ( ‘ Una copia de tu texto es: ‘, texto2 ) copiar_cadena_n ( texto3, texto1, 4) escribir ( ‘ Y sus cuatro primeras letras son: ‘, texto3 ) pausa fin Programa: #include <stdio.h> #include <string.h> main() { char texto1[40], texto2[40], texto3[10]; clrscr(); printf("Introduce un frase: "); gets(texto1); strcpy(texto2, texto1); printf("Una copia de tu texto es: %s\n", texto2); strncpy(texto3, texto1, 4); printf("Y sus cuatro primeras letras son %s\n", texto3); getch(); } Finalmente, existe otra orden relacionada con estas dos: podemos añadir una cadena al final de otra (concatenarla), con:

Page 15: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

strcat (destino, origen); Vamos a ver un ejemplo de su uso, que nos pida nuestro nombre, nuestro apellido y cree una nueva cadena de texto que contenga los dos, separados por un espacio: Algoritmo: inicio declarar variables carácter texto1[ 40 ] carácter texto2[ 40 ] carácter texto3[ 40 ] limpiar pantalla escribir ( ‘ Introduce tu nombre: ‘ ) leer ( texto1 ) escribir ( ‘ Introduce tu apellido: ‘ ) leer ( texto2 ) concatenar ( texto1, “ “ ) concatenar (texto1, texto2 ) escribir ( ‘ Te llamas ‘, texto1 ) pausa fin Programa: #include <stdio.h> #include <string.h> main() { char texto1[40], texto2[40], texto3[40]; clrscr(); printf("Introduce tu nombre: "); gets(texto1); printf("Introduce tu apellido: "); gets(texto2); strcat(texto1, " "); /* Añado un espacio al nombre */ strcat(texto1, texto2); /* Y luego el apellido */ printf("Te llamas %s\n", texto1); getch(); }

4.3. Apuntadores Hasta ahora teníamos una serie de variables que declaramos al principio del programa o de cada función. Estas variables, que reciben el nombre de ESTÁTICAS, tienen un tamaño asignado desde el momento en que se crea el programa.

Un Apuntador es una variable que contiene una dirección de memoria, la cual corresponderá a un dato o a una variable que contiene el dato. Los apuntadores también deben de seguir las mismas reglas que se aplican a las demás variables, deben tener nombre únicos y deben de declararse antes de usarse.

Cada variable que se utiliza en una aplicación ocupa una o varias posiciones de memoria. Estas posiciones de memoria se accesan por medio de una dirección.

* h

h

Page 16: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

1000 1001 1002 1003 1004 1005

H e l l o

Figura 22. Puntero

En la figura el texto “ Hello “ esta guardado en memoria, comenzando en la dirección 1000. Cada carácter ocupa un espacio de dirección único en memoria. Los apuntadores proporcionan un método para conservar y llegar a estas direcciones en memoria. Los apuntadores facilitan el manejo de datos, debido a que conservan la dirección de otra variable o ubicación de datos.

Los apuntadores dan flexibilidad a los programas en C y en C++; también permiten que estos crezcan dinámicamente. Utilizando un apuntador hacia un bloque de memoria que se asigna al momento de ejecución, un programa puede ser más flexible que uno que asigna toda su memoria de una sola vez. También, un apuntador es más fácil de guardar que una estructura grande o un objeto de una clase. Debido a que un apuntador sólo guarda una dirección, puede fácilmente pasarse a una función. Uno de las desventajas que pueden presentar los apuntadores es que un apuntador sin control o no inicializado puede provocar fallas en el sistema, además de que su uso incorrecto puede generar fallas muy complejas de encontrar.

Este tipo de variables son sencillas de usar y rápidas... si sólo vamos a manejar estructuras de datos que no cambien, pero resultan poco eficientes si tenemos estructuras cuyo tamaño no sea siempre el mismo. Es el caso de una agenda: tenemos una serie de fichas, e iremos añadiendo más. Si reservamos espacio para 10, no podremos llegar a añadir la número 11, estamos limitando el máximo. Una solución sería la de trabajar siempre en el disco: no tenemos límite en cuanto a número de fichas, pero es muchísimo más lento. Lo ideal sería aprovechar mejor la memoria que tenemos en el ordenador, para guardar en ella todas las fichas o al menos todas aquellas que quepan en memoria. Una solución “típica” (pero mala) es sobredimensionar: preparar una agenda contando con 1000 fichas, aunque supongamos que no vamos a pasar de 200. Esto tiene varios inconvenientes: se desperdicia memoria, obliga a conocer bien los datos con los que vamos a trabajar, sigue pudiendo verse sobrepasado, etc. La solución suele ser crear estructuras DINÁMICAS, que puedan ir creciendo o disminuyendo según nos interesen. Ejemplos de este tipo de estructuras son: Las pilas. Como una pila de libros: vamos apilando cosas en la cima, o cogiendo de la cima. Las colas. Como las del cine (en teoría): la gente llega por un sitio (la cola) y sale por el opuesto (la cabeza). Las listas, en las que se puede añadir elementos, consultarlos o borrarlos en cualquier posición. Y la cosa se va complicando: en los árboles cada elemento puede tener varios sucesores, etc. Todas estas estructuras tienen en común que, si se programan bien, pueden ir creciendo o decreciendo según haga falta, al contrario que un array, que tiene su tamaño prefijado. En todas ellas, lo que vamos haciendo es reservar un poco de memoria para cada nuevo elemento que nos haga falta, y enlazarlo a los que ya teníamos. Cuando queramos borrar un elemento, enlazamos el anterior a él con el posterior a él (para que no “se rompa” nuestra estructura) y liberamos la memoria que estaba ocupando. 4.3.1. Concepto

Page 17: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

Un puntero no es más que una dirección de memoria. Lo que tiene de especial es que normalmente un puntero tendrá un tipo de datos asociado: por ejemplo, un “puntero a entero” será una dirección de memoria en la que habrá almacenado (o podremos almacenar) un número entero.

Hay 2 operadores que se usan cuando trabajan con direcciones en un programa en C; el Operador de Indirección ( * ) y el de Dirección (&). Estos operadores son diferentes de los tratados anteriormente.

El Operador de Dirección ( &) regresa la dirección de una variable. Este operador está asociado con la variable a su derecha: &h; esta línea regresa la dirección de memoria de la variable h, la que contiene nuestra máquina internamente.

El Operador de Indirección ( * ) trabaja a la inversa del operador de Dirección. También esta asociado con la variable a su derecha, toma la dirección y regresa el dato que contiene esa dirección de memoria. Por ejemplo, la siguiente línea determina la dirección de la variable h y luego usa el operador de Indirección para accesar la variable y darle un valor de 42:

*(&h)=42;

La declaración de un puntero de manera general es:

tipo *nombre del apuntador;

Tipo : Especifica el tipo de objeto apuntado y puede ser cualquier tipo visto con anterioridad.

Nombre de apuntador: Es el identificador del apuntador.

El espacio de memoria requerido para un apuntador, es el número de bytes necesarios para especificar una dirección de memoria, debiendo apuntar siempre al tipo de dato correcto.

Considere el siguiente programa y observe a las variables de dirección e Indirección trabajar:

Algoritmo:

inicio declarar variables entero x 1, y 2 entero *ip limpiar pantalla escribir ( ‘ Antes del uso de los apuntadores ‘ ) escribir ( ‘ X = ‘, x , ‘ Y = ‘, y, ‘ *ip = ‘ , *ip ) ip &x y *ip *ip 10 escribir ( ‘ Después del uso de los operadores ‘ ) escribir ( ‘ X = ‘, x , ‘ Y = ‘, y, ‘ *ip = ‘ , *ip ) pausa fin

Programa:

#include<stdio.h> #include<conio.h> int x=1; y=2;

Page 18: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

int *ip; /* ip es apuntador a int */ void main() { clrscr(); printf(“ Antes del uso de los apuntadores “); printf(“ \n X = %d Y = %d *ip = %d “, x,y,*ip); ip = &x; /* ip ahora apunta a x */ y = *ip; /* y vale 1 */ *ip = 10; /* ahora x vale 10 */ printf (“ Después del uso de los operadores “); printf(“ \n X = %d Y = %d *ip = %d “, x,y,*ip); getch(); } La salida (corrida) del programa anterior es: Antes del uso de los operadores: X= 1 y=2 *ip = 0 Después del uso de los operadores:

X= 10 y=1 *ip = 10

Vamos a ver qué símbolo usamos en C para designar los punteros: int num; /* "num" es un número entero */ int *pos; /* "pos" es un "puntero a entero" (dirección de

memoria en la que podremos guardar un entero) */

Es decir, pondremos un asterisco entre el tipo de datos y el nombre de la variable. Ese asterisco puede ir junto a cualquiera de ambos, también es correcto escribir int* pos; esta nomenclatura ya la habíamos utilizado aun sin saber que era eso de los punteros. Por ejemplo, cuando queremos acceder a un fichero, hacemos FILE* fichero; antes de entrar en más detalles, y para ver la diferencia entre trabajar con “arrays” o con punteros, vamos a hacer dos programas que pidan varios números enteros al usuario y muestren su suma. El primero empleará un “array” (una tabla, de tamaño predefinido) y el segundo empleará memoria que reservaremos durante el funcionamiento del programa. El primero podría ser así: Algoritmo: inicio declarar variables entero datos [100] entero cuantos entero i largo suma 0 limpiar pantalla hacer escribir ( ‘ Cuantos números desea sumar ? ‘ ) leer ( cuantos ) si ( cuantos > 100 ) hacer escribir ( ‘ Demasiados. Solo se puede hasta 100. ‘ ) fin_si mientras ( cuantos > 100 ) para ( i = 0; i < cuantos; i++ ) hacer

Page 19: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

escribir ( ‘ X = ‘, x , ‘ Y = ‘, y, ‘ *ip = ‘ , *ip ) pausa fin Programa: #include <stdio.h> main() { int datos[100];

/* Preparamos espacio para 100 numeros */ int cuantos;

/* Preguntaremos cuantos desea introducir */ int i;

/* Para bucles */ long suma=0;

/* La suma, claro */ clrcsr(); do { printf(" Cuantos numeros desea sumar? "); scanf(" %d ", &cuantos); if (cuantos>100)

/* Solo puede ser 100 o menos */ printf("Demasiados. Solo se puede hasta 100."); } while (cuantos>100);

/* Si pide demasiado, no le dejamos */ /* Pedimos y almacenamos los datos */

for (i=0; i<cuantos; i++) { printf(" Introduzca el dato número %d: ", i+1); scanf(" %d ", &datos[i]); }

/* Calculamos la suma */ for (i=0; i<cuantos; i++) suma += datos[i]; printf(" Su suma es: %ld\n ", suma); } Los más avispados se pueden dar cuenta de que si sólo quiero calcular la suma, lo podría hacer a medida que leo cada dato, no necesitaría almacenar todos. Vamos a suponer que sí necesitamos guardarlos (en muchos casos será verdad, si los cálculos son más complicados). Entonces nos damos cuenta de que lo que hemos estado haciendo hasta ahora no es eficiente: • Si quiero sumar 1000 datos, o 500, o 101, no puedo. Nuestro límite previsto era de 100, así que no podemos trabajar con más datos. • Si sólo quiero sumar 3 números, desperdicio el espacio de 97 datos que no uso. • Y el problema sigue: si en vez de 100 números, reservamos espacio para 5000, es más difícil que nos quedemos cortos pero desperdiciamos muchísima más memoria. La solución es reservar espacio estrictamente para lo que necesitemos, y eso es algo que podríamos hacer así: Algoritmo: inicio declarar variables entero *datos entero cuantos entero i largo suma 0 limpiar pantalla

Page 20: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

hacer escribir ( ‘ Cuantos números desea sumar ? ‘ ) leer ( cuantos ) datos (entero *) malloc (cuantos * sizeof(entero)) si (datos = NULL) escribir ( ‘ No caben tantos datos en memoria. ‘ ) fin_si mientras ( datos = NULL ) fin_hacer escribir ( ‘ Introduzca el dato número ‘, i+1 ) leer ( datos + i ) fin_para para ( i = 0; i < cuantos; i++ ) hacer suma suma + *datos + i fin_para escribir ( ‘ Su suma es: ‘, suma ) liberar (datos) pausa fin Programa: #include <stdio.h> #include <stdlib.h> main() { int* datos; /* Necesitaremos espacio para varios numeros */ int cuantos; /* Preguntaremos cuantos desea introducir */ int i; /* Para bucles */ long suma=0; /* La suma, claro */ do { printf("Cuantos numeros desea sumar? "); scanf("%d", &cuantos); datos = (int *) malloc (cuantos * sizeof(int)); if (datos == NULL) /* Solo puede ser 100 o menos */ printf("No caben tantos datos en memoria."); } while (datos == NULL); /* Si pide demasiado, no le dejamos */

/* Pedimos y almacenamos los datos */ for (i=0; i<cuantos; i++) { printf("Introduzca el dato número %d: ", i+1); scanf("%d", datos+i); }

/* Calculamos la suma */ for (i=0; i<cuantos; i++) suma += *(datos+i); printf("Su suma es: %ld \n", suma); free(datos); } Este programa funciona perfectamente si sólo queremos sumar 5 números, pero también si necesitamos sumar 120.000 (y si caben tantos números en la memoria disponible de nuestro equipo, claro). Vamos a ver las diferencias: En primer lugar, lo que antes era int datos[100] que quiere decir “a partir de la posición de memoria que llamaré datos, quede espacio para a guardar 100 números enteros”, se ha

Page 21: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

convertido en int * datos que quiere decir “a partir de la posición de memoria que llamaré datos voy a guardar varios números enteros (pero aún no sé cuantos)”. Luego reservamos el espacio exacto que necesitamos, haciendo datos = (int *) malloc (cuantos * sizeof ( int ); Esta orden suena complicada, así que vamos a verla por partes: • “malloc” es la orden que usaremos para reservar memoria cuando la necesitemos (es la abreviatura de las palabra “memory” y “allocate”). • Como parámetro, le indicamos cuanto espacio queremos reservar. Para 100 números enteros, sería “100*sizeof(int)”, es decir, 100 veces el tamaño de un entero. En nuestro caso, no son 100 números, sino el valor de la variable “cuantos”. Por eso hacemos “malloc (cuantos*sizeof(int))”. • Para terminar, ese es el espacio que queremos reservar para nuestra variable “datos”. Y esa variable es de tipo “int *” (un puntero a datos que serán números enteros). Para que todo vaya bien, debemos “convertir” el resultado de “malloc” al tipo de datos correcto, y lo hacemos forzando una conversión como vimos en el apartado 2.4 (operador “molde”), con lo que nuestra orden está completa: datos = (int *) malloc (cuantos * sizeof(int)); • Si “malloc” nos devuelve NULL como resultado (un “puntero nulo”), quiere decir que no ha encontrado ninguna posición de memoria en la que nos pudiera reservar todo el espacio que le habíamos solicitado. • Para usar “malloc” deberemos incluir “stdlib.h” al principio de nuestro fuente. La forma de guardar los datos que teclea el usuario también es distinta. Cuando trabajábamos con un “array”, hacíamos scanf( “ %d “, &datos[i]) (“el dato número i”), pero con punteros usaremos scanf(“ %d “, datos+i) (en la posición datos + i). Ahora ya no necesitamos el símbolo “ampersand” (&). Este símbolo se usa para indicarle a C en qué posición de memoria debe almacenar un dato. Por ejemplo, float x; es una variable que podremos usar para guardar un número real. Si lo hacemos con la orden “scanf”, esta orden no espera que le digamos en qué variable deber guardar el dato, sino en qué posición de memoria. Por eso hacemos scanf("%f", &x); En el caso que nos encontramos ahora, int* datos ya se refiere a una posición de memoria (un puntero), por lo que no necesitamos & para usar “scanf”. Finalmente, la forma de acceder a los datos también cambia. Antes leíamos el primer dato como datos[0], el segundo como datos[1], el tercero como datos[2] y así sucesivamente. Ahora usaremos el asterisco (*) para indicar que queremos saber el valor que hay almacenado en una cierta posición: el primer dato será *datos, el segundo *(datos+1), el tercero será *(datos+2) y así en adelante. Por eso, donde antes hacíamos suma += datos[i]; ahora usamos suma += *(datos+i). También aparece otra orden nueva: free. Hasta ahora, teníamos la memoria reservada estáticamente, lo que supone que la usábamos (o la desperdiciábamos) durante todo el tiempo que nuestro programa estuviera funcionando. Pero ahora, igual que reservamos memoria justo en el momento en que la necesitamos, y justo en la cantidad que necesitamos, también podemos volver a dejar disponible esa memoria cuando hayamos terminado de usarla. De eso se encarga la orden “free”, a la que le debemos indicar qué puntero es el que queremos liberar. El ejemplo anterior era “un caso real”. Generalmente, los casos reales son más aplicables que los ejemplos puramente académicos, pero también más difíciles de seguir. Por eso, antes de seguir vamos a ver un ejemplo más sencillo que nos ayude a asentar los conceptos: Reservaremos espacio para un número real de forma estática, y para dos números reales de forma dinámica, daremos valor a dos de ellos, guardaremos su suma en el tercer número y mostraremos en pantalla los resultados.

Page 22: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

Algoritmo: inicio declarar variables real n1 real *n2, *suma limpiar pantalla n1 5.0 n2 (float *) malloc (sizeof(float)) *n2 6.7 suma (float *) malloc (sizeof(float)) *suma n1 + *n2 escribir ( ‘ El valor prefijado para la suma era ‘, *suma) escribir ( ‘ Ahora es tu turno: Introduce el primer número ‘) leer ( n1 ) escribir ( ‘ Introduce el segundo número ‘ ) leer ( n2 ) *suma n1 + *n2 escribir ( ‘ Ahora la suma es ‘, *suma) liberar (n2) liberar (suma) pausa fin Programa: #include <stdio.h> #include <stdlib.h> main() { float n1; /* Primer número, estático */ float *n2, *suma; /* Los otros dos números */ n1 = 5.0; /* Damos un valor prefijado a n1 (real)

*/ n2 = (float *) malloc (sizeof(float));

/* Reservamos espacio para n2 */ *n2 = 6.7; /* Valor prefijado para n2 (puntero a

real) */ suma = (float *) malloc (sizeof(float));

/* Reservamos espacio para suma */ *suma = n1 + *n2; /* Calculamos la suma */ printf("El valor prefijado para la suma era %4.2f\n", *suma); printf("Ahora es tu turno: Introduce el primer número "); scanf("%f",&n1); /* Leemos valor para n1 (real) */ printf("Introduce el segundo número "); scanf("%f",n2); /* Valor para n2 (puntero a real) */ *suma = n1 + *n2; /* Calculamos nuevamente la suma */ printf("Ahora la suma es %4.2f\n", *suma); free(n2); /* Liberamos la memoria reservada */ free(suma); } Las diferencias son: n1 es un “float”, así que le damos valor normalmente: n1 = 0; Y pedimos su valor con scanf usando & para indicar en qué dirección de memoria se encuentra: scanf("%f", &n1).

Page 23: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

n2 (y también “suma”) es un “puntero a float”, así que debemos reservarle espacio con “malloc” antes de empezar a usarlo, y liberar con “free” el epacio que ocupaba cuando terminemos de utilizarlo. Para guardar un valor en la dirección de memoria “a la que apunta”, usamos un asterisco: *n2 = 0; Y pedimos su valor con scanf, pero sin necesidad de usar &, porque el puntero ES una dirección de memoria: scanf("%f", n2). En este ejemplo, no hemos comprobado si el resultado de “malloc” era NULL, porque sólo pedíamos espacio para dos variables, y hemos dado por sentado que sí habría memoria disponible suficiente para almacenarlas; en un caso general, deberemos asegurarnos siempre de que se nos ha concedido ese espacio que hemos pedido. 4.3.2. Tipos de Apuntadores Como se ha visto a lo largo de este manual todas las variables se enlazan a tipos específicos, con lo cual es de concluirse que una variable apuntador también; por lo cual se enlazan a tipos de datos específicos del lenguaje (apuntadores a variables de cierto tipo), de forma tal que a un apuntador sólo se le pueden designar direcciones de variables del mismo tipo, que se específico en la declaración del apuntador. Este termino es algo complejo de entender por lo tanto se verá un ejemplo de su manejo: Algoritmo: entero *apun1 real *apun2 entero a apun1 &a apun2 &a Programa: int *apun1; float *apun2; int a; apun1 = &a; // Esto es válido apun2 = &a; // Esto no es válido (ya que el puntero 2 es de

tipo float, y por lo tanto debe apuntar hacia una variable del mismo tipo y en este caso no es así, con lo cual se genera un error)

Cotidianamente, un apuntador inicializado de una manera adecuada apunta a alguna posición específica de la memoria. Sin embargo, algunas veces es posible que un apuntador no contenga una dirección válida, en cuyo caso es incorrecto desreferenciarlo (obtener el valor al que apunta) porque el programa tendrá un comportamiento impredecible y probablemente erróneo, aunque es posible que funcione bien. Un apuntador puede contener una dirección inválida debido a dos razones: 1. Cuando un apuntador se declara, al igual que cualquier otra variable, el mismo posee un valor cualquiera que no se puede conocer con anticipación, hasta que se inicialice con algún valor (dirección), por ejemplo: Algoritmo: real *apun; escribir ( ‘ El valor apuntado por apun es: ‘ , *apun ) // Incorrecto *apun 3.5 // Incorrecto Programa: float *apun;

Page 24: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

printf ( " El valor apuntado por apun es: " , *apun );// Incorrecto *apun = 3.5; // Incorrecto 2. Después de que un apuntador ha sido inicializado, la dirección que posee puede dejar de ser válida si se libera la memoria reservada en esa dirección, ya sea porque la variable asociada termina su ámbito o porque ese espacio de memoria fue reservado dinámicamente y luego se liberó1, ejemplo de esto es el siguiente: Algoritmo: entero *apun entero b function func() entero a 40 apun &a b *apun; // Correcto *apun 23; // Correcto Fin_func inicio limpiar pantalla llamar a la función func() b *apun // Incorrecto *apun 25 // Incorrecto pausa fin Programa: int *apun, b; void func() { int a = 40; apun = &a; b = *apun; // Correcto *apun = 23; // Correcto } void main() { clrscr(); func(); b = *apun; // Incorrecto *apun = 25; // Incorrecto getch(); } Si se intenta desreferenciar un apuntador que contiene una dirección inválida pueden ocurrir cosas como las siguientes: Se obtiene un valor incorrecto en una o más variables debido a que no fue debidamente inicializada la zona de memoria que se accede a través de la dirección en cuestión. Esto puede ocasionar que el programa genere resultados incorrectos. Si casualmente la dirección es la misma de otra variable utilizada en el programa, o está dentro del rango de direcciones de una zona de memoria utilizada, existe el riesgo de sobreescribir datos de otras variables. Existe la posibilidad de que la dirección esté fuera de la zona de memoria utilizada para almacenar datos y más bien esté, por ejemplo, en la zona donde se almacenan las instrucciones del programa. Al intentar escribir en dicha zona, fácilmente puede

Page 25: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

ocurrir que el programa genere un error de ejecución y el sistema operativo lo detenga, o que el programa no responda y deje al sistema operativo inestable. En muchos casos el sistema operativo detecta el acceso inadecuado a una dirección de memoria, en cuyo caso detiene abruptamente el programa. 4.3.3. Operaciones con apuntadores Si declaramos una variable como int n=5 y posteriormente hacemos n++, debería resultar claro que lo que ocurre es que aumenta en una unidad el valor de la variable n, pasando a ser 6. Pero ¿qué sucede si hacemos esa misma operación sobre un puntero? Algoritmo: Declarer variables entero *n n (int *) malloc (sizeof(int)) *n 3 n n + 1 Programa: int *n; n = (int *) malloc (sizeof(int)); *n = 3; n++; Después de estas líneas de programa, lo que ha ocurrido no es que el contenido de la posición n sea 4. Eso lo conseguiríamos modificando “*n”, de la misma forma que le hemos dado su valor inicial. Es decir, deberíamos usar (*n) ++. En cambio, nosotros hemos aumentado el valor de “n”. Como “n” es un puntero, estamos modificando una dirección de memoria. Por ejemplo, si “n” se refería a la posición de memoria número 10.000 de nuestro ordenador, ahora ya no es así, ahora es otra posición de memoria distinta, por ejemplo la 10.001. Porque, como ya sabemos, el espacio que ocupa una variable en C depende del sistema operativo. Así, en un sistema operativo de 32 bits, un “int” ocuparía 4 bytes, de modo que la operación n++. Haría que pasáramos de mirar la posición 10.000 a la 10.004. Generalmente no es esto lo que se quiere, sino modificar el valor que había almacenado en esa posición de memoria. Olvidar ese * que indica que queremos cambiar el dato y no la posición de memoria puede dar lugar a fallos muy difíciles de descubrir (o incluso a que el programa se interrumpa con un aviso de “Violación de segmento” porque estemos accediendo a zonas de memoria que no hemos reservado. 4.3.4. Relación de apuntadores con arreglos En C hay muy poca diferencia “interna” entre un puntero y un array. En muchas ocasiones, podremos declarar un dato como array (una tabla con varios elementos iguales, de tamaño predefinido) y recorrerlo usando punteros. Vamos a ver un ejemplo: Algoritmo: inicio declarar variables entero datos [ 10 ] entero i

Page 26: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

limpiar pantalla para ( i = 1; i < 10; i++ ) hacer datos [ i ] i * 2 fin_para para ( i = 1; i < 10; i++ ) hacer escribir ( datos + i ) fin_para pausa fin Programa: main() { int datos[10]; int i;

/* Damos valores normalmente */ clrscr(); for (i=0; i<10; i++) datos[i] = i*2;

/* Pero los recorremos usando punteros */ for (i=0; i<10; i++) printf ("%d ", *(datos+i)); getch(); } Pero también podremos hacer lo contrario, declarar de forma dinámica una variable usando “malloc” y recorrerla como si fuera un array: Algoritmo: inicio declarar variables entero *datos entero i limpiar pantalla datos ( entero * ) escribir ( ‘ Uso como puntero … ‘ ) para ( i = 0; i < 20; i++ ) hacer *(datos + i ) i * 2 fin_para para ( i = 0; i < 20; i++ ) hacer escribir ( *( datos + i ) ) fin_para escribir ( ‘ Uso como array … ‘ ) para ( i = 0; i < 20; i++ ) hacer datos [ i ] i * 3 fin_para para ( i = 0; i < 20; i++ ) hacer escribir ( datos [ i ] ) fin_para liberar (datos) pausa fin Programa: #include <stdio.h> #include <stdlib.h>

Page 27: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

main() { int *datos; int i;

/* Reservamos espacio */ datos = (int *) malloc (20*sizeof(int));

/* Damos valores como puntero */ clrscr(); printf(" Uso como puntero... "); for (i=0; i<20; i++) *(datos+i) = i*2;

/* Y los mostramos */ for (i=0; i<10; i++) printf ("%d ", *(datos+i));

/* Ahora damos valores como array */ printf("\n Uso como array... "); for (i=0; i<20; i++) datos[i] = i*3;

/* Y los mostramos */ for (i=0; i<10; i++) printf ("%d ", datos[i]);

/* Liberamos el espacio */ free(datos); getch(); } Existe otra posibilidad de usar punteros y arreglos, que son los arreglos de punteros, Igual que creamos “arrays” para guardar varios datos que sean números enteros o reales, podemos hacerlo con punteros, esto es podemos reservar espacio para “20 punteros a enteros” haciendo: int *datos[20]; Tampoco es algo especialmente frecuente en un caso general, porque si fijamos la cantidad de datos, estamos perdiendo parte de la versatilidad que podríamos tener al usar memoria dinámica. Pero sí es habitual cuando se declaran varias cadenas: char *mensajesError[3]={"Fichero no encontrado", "No se puede escribir", "Fichero sin datos"}; Un ejemplo de su uso sería este: Algoritmo: inicio declarar variables carácter *mensajesError[3] {"Fichero no encontrado", "No se puede escribir", "Fichero sin datos"} limpiar pantalla escribir ( ‘ El primer mensaje de error es: ‘, mensajesError[0]) escribir ( ‘ El segundo mensaje de error es: ‘, mensajesError[1]) escribir ( ‘ El tercer mensaje de error es: ‘, mensajesError[2]) pausa fin

Page 28: UNIDAD IV ESTRUCUTRAS DE DATOS · ESIME Zacatenco IPN 1 4.1. Arreglo Unidimensionales 4.1.1. Concepto y forma general Un arreglo unidimensional es un tipo de datos estructurado que

UNIDAD IV ESTRUCUTRAS DE DATOS

Autores: Alejandra Gutierrez Reyes - Enrique Martínez Roldán - Academia de Computación – Ingenieria Eléctrica ESIME Zacatenco IPN

1

Programa: #include <stdio.h> main() { char *mensajesError[3]={"Fichero no encontrado","No se puede escribir","Fichero sin datos"}; clrscr(); printf("El primer mensaje de error es: %s\n",mensajesError[0]); printf("El segundo mensaje de error es: %s\n",mensajesError[1]); printf("El tercer mensaje de error es: %s\n",mensajesError[2]); getch(); }