Ingenierı́a en Informática Relaciones de Estructuras de Datos. Curso 2008/2009 J. Fdez-Valdivia Departamento de Ciencias de la Computación e I.A. ETS Ingenierı́a Informática Universidad de Granada. 18071 Granada. Spain. Email: [email protected] http://decsai.ugr.es/˜jfv/ed1/REL/rel0.pdf Resumen En este documento se presentan la primera relación de problemas que se proponen para la asignatura de estructura de datos de primer curso de Ingenierı́a en Informática . El documento se divide en 2 secciones: punteros y funciones. 1. Problemas sobre Punteros. Problema 1.1 Escriba un trozo de código donde se declara un vector de 100 enteros y, mediante un bucle, se asigne el valor 1 a todas las posiciones, sin usar el “operador []”. Problema 1.2 Declare una variable numeros como una vector de 1000 enteros. Escriba un trozo de código que recorra el vector y modifique todos los enteros negativos cambiándolos de signo. No se debe usar el operador ’[]’, es decir, se deberá usar aritmética de punteros. El bucle se controlará mediante un contador entero. Problema 1.3 Modifique el código del problema anterior para controlar el final del bucle con un puntero a la posición siguiente a la última. Problema 1.4 Considere la figura 1. Se presentan gráficamente un conjunto de estructuras de datos. Se puede observar que las matrices se representan indicando los ı́ndices y las estructuras indicando los nombres de los campos. Escriba los trozos de código que corresponden a su creación. Nota: No se debe usar memoria dinámica (para cada caso se incluye el nombre de las variables necesarias). Problema 1.5 Supongamos tres vectores v1,v2,res de valores reales. En v1,v2 se almacenan, respectivamente, n,m valores ordenados de menor a mayor. Escribir un trozo de código para mezclar, de manera ordenada, los valores en el vector res que tiene capacidad para almacenas al menos n+m valores. No se debe usar el operador ’[]’, es decir, se debe usar aritmética de punteros. 1 2. Problemas sobre Funciones. Problema 2.1 Indique el efecto de la siguiente función void intercambia (int ∗p, int ∗q) { int &temp= p; p=q; q=temp; } Problema 2.2 Indique el efecto de la siguiente función void intercambia (int ∗p, int ∗q) { int ∗temp= p; p=q; q=temp; } Problema 2.3 Implemente una función swap puntero que intercambie el valor de dos punteros usando paso por referencia. Muestre un ejemplo de llamada. Problema 2.4 Implemente la función del problema anterior sin usar paso por referencia. Deberá usar un paso de parámetros al “estilo C”, es decir, por medio de un puntero al valor a modificar. Reescriba el ejemplo de llamada. Problema 2.5 Consideremos que en un proyecto, un programador tiene la tarea de crear una función que determine si un valor entero, indicado por un puntero, es par. Crea la siguiente función bool par(int ∗p) { return (∗p %2==0); } Considere otra función, realizada por otro programador, que usa la primera. int numero pares (const int ∗v, int n) { int res=0; for (int i=0;i<n;i++) if (par(v+i)) res++; return res; } ¿Qué problema se va a encontrar la persona encargada de integrar ambos códigos? Si es necesario, incluya las dos funciones en un fichero fuente e intente compilarlo. ¿Qué error es de esperar? Problema 2.6 Considere la siguiente función void copiar (float ∗∗m, int f, int c, float ∗∗& res) { // modifica res, para apuntar a una nueva zona y // copia la matriz fxc m a res } ¿Qué posible problema nos podemos encontrar al ejecutar Copiar(mat,f,c,mat) ? J. Fdez-Valdivia página 2 ¿Cómo podrı́amos asegurarnos de resolver ese problema? Problema 2.7 Las cadenas de caracteres representan un ejemplo clásico en el uso de punteros. El tipo correspondiente para almacenarlas es un vector de caracteres 1 . Implemente las siguientes funciones: Función copia cadena. Copia una cadena de caracteres en otra. Función encadenar cadena. Añade una cadena de caracteres al final de otra. Función longitud cadena. Devuelve un entero con la longitud (número de caracteres sin contar el nulo) de la cadena. Función comparar cadena. Compara dos cadenas. Devuelve un valor negativo si la primera es más “pequeña”, positivo si es más “grande” y cero si son “iguales”. Teniendo en cuenta que se supone que hay suficiente memoria en las cadenas de destino y no es necesario pasar el tamaño de las cadenas (controlado por la terminación en caracter nulo). Problema 2.8 En la tabla 1 se muestran posibles pasos de parámetros. Indique si son correctos y por qué. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 Declaración int v int m[] float mat[5] const int v[10] int m[] int m[3][5][7] float v[5] int m[] float f float f bool mat[5][7] char mat[3][5] int *m[10] const double v int **m int mat[5][7][9][11] int *p float *p int m[3][5][7] int mat[5][7][9][11] float *p double *p int m[5][10] int *mat[5] const bool *mat Parámetro Actual v m mat v m m v+2 m f &f &mat[3][2] mat[0] m &v m &mat[0][0][0][0] &p p m mat[2][4][3] p+5 p+2 m &mat[5] mat+4 5 Parámetro formal float v int *mat float *& mat int *mat int mat[10] int mat[][5][7] const float mat[] int mat[][5] double f double& f const bool mat[] char *mat int **mat double v[] int mat[][] int *p int *mat[] float *& p int *mat[5][7] const int *m float *& p float *p int *mat[] const int **p bool *p int& val Cuadro 1: Problema 2.8. Lista de posibles pasos de parámetros 1 Recordemos que un literal de cadena, es una secuencia de caracteres entre comillas. Por ejemplo, ”Hola”. El tipo de este ejemplo es const char [5] (incluye el ’\0’). J. Fdez-Valdivia página 3 Problema 2.9 Considere las siguientes funciones int& primera () { int local; . . . return local; } int& segunda () { static int local=0; . . . return local; } ¿Cree que son correctas? Razone la respuesta. Problema 2.10 Suponga que ejecutamos el siguiente programa #include <iostream> using namespace std; struct Par{ int ∗p1,∗p2; }; void intercambia(Par p) { int ∗paux; paux=p.p1; p.p1=p.p2; p.p2=paux; int aux; aux=∗p.p1; ∗p.p1=∗p.p2; ∗p.p2=aux; } int main() { Par p; int x=0,y=1; p.p1=&x; p.p2=&y; intercambia(p); if (p.p1==&x) cout ‘‘Los punteros están igual’’endl; if (∗p.p1==0) cout ‘‘El primero sigue teniendo 0’’endl; } ¿Cuál cree que será la salida? Razone la respuesta. J. Fdez-Valdivia página 4 Problema 2.11 Suponga que ejecutamos el siguiente programa #include <iostream> using namespace std; struct Par{ int vec[2]; }; void intercambia(Par p) { int aux; aux=p.vec[0]; p.vec[0]=p.vec[1]; p.vec[1]=aux; } int main() { Par p; p.vec[0]=0; p.vec[1]=1; intercambia(p); if (p.vec[0]==0) cout ‘‘El primero sigue teniendo 0’’endl; } ¿Cuál cree que será la salida? Razone la respuesta. J. Fdez-Valdivia página 5 elemento ant sig letra sig entero ´z´ 5 doble s ant caracter numero sig ant caracter ´z´ 1 doble1 s pareja doble2 psing real caracter psig caracter ´a´ otro 2.0 psig real ´b´ 0 pri seg real v2 1 real otro v3 2.0 v4 mat_celdas encadenado 5.0 val 3 2 3 3 4 4 5 5 6 6 6 7 7 7 8 8 8 9 9 valor next next s 9 0 1 10 98 980 99 990 0 1 pun 5 valor 98 p 99 next val 6 p 15.0 next vec 17.0 vec1 first second 4 s2 5 first second val next 5.0 val 7.0 s4 6 7 s3 next 8 ’z’ ’z’ ’z’ ’z’ 99 next 3.0 89 90 3 val p2 0 1 2 3 4 5 6 7 8 9 2 s1 ’z’ ’z’ ’z’ 1 0 1 2 3 4 5 6 7 8 9 1.0 20 1 ’z’ ’z’ 9 10 11 0 vec2 0 1 0 p3 val 5 2 5 13.0 val 2 0 val 4 1 5 11.0 val 1 4 next 9.0 val 1 3 7.0 2 0 p 1 next 0 vec1 val val 0 p 0 next vec1 vec2 val vec val first second otro 3.0 1.0 v1 anidado p1 sig ´z´ matriz2D 9 2 3 4 5 6 7 8 9 Figura 1: Ejemplos de estructuras. J. Fdez-Valdivia página 6