Estructura de Datos y de la Información I, 2005-2006 :: Práctica 2 Página 1 de 7 Estructura de Datos y de la Información I, 2008-2009 Escuela Politécnica Superior, UAM Práctica 2: Manipulación de cadenas de caracteres en C y definición de nuevos TADs Objetivos 1. Profundizar en elementos básicos de programación (control de bucles, gestión de errores, I/O básicos, reusabilidad del código). 2. Iniciarse en la organización multiarchivo del código y en el uso de proyectos en MSVC++. 3. Iniciarse en la definición de nuevos tipos abstractos de datos (TADs) y en su implementación y uso. 4. Manejar diversos aspectos esenciales de la programación C: { Gestión de cadenas de caracteres: operaciones elementales. { Definición y manejo de estructuras. { Uso de punteros. Normas Los programas que se entreguen deben: z z z z z Estar escritos en ANSI C siguiendo las normas de programación establecidas. Utilizar las plantillas de código suministradas para los ficheros de código "*.c" y las cabeceras "*.h". Compilar sin errores ni "warnings" con el máximo nivel de advertencias en Microsoft Visual C++ 6.0. Ejecutarse sin problema en una ventana de comandos de Windows. Incorporar un adecuado control de errores, es justificable que un programa no admita valores inadecuados, pero no que se comporte de forma anómala con dichos valores. La memoria que se entregue debe: z Elaborarse siguiendo las normas sobre elaboración de memorias. z Utilizar la plantilla para la memoria suministrada. La entrega se realizara en dos fases, siguiendo escrupulosamente las instrucciones indicadas en la normas de entrega de prácticas: z Entrega electrónica mediante la Página de Entregas Web de la Escuela de todos los fuente, el proyecto y la memoria de la práctica, antes del comienzo de la clase o examen correspondiente al día de entrega (sin olvidar seguir normas de entrega de prácticas). Estructura de Datos y de la Información I, 2005-2006 :: Práctica 2 z Página 2 de 7 Entrega física de una copia impresa de la memoria incluida en la entrega electrónica, al comienzo de la clase o al final del examen correspondiente al día de entrega. Las fechas de entrega son las siguientes: z z Los alumnos de Evaluación Continua, según el calendario establecido, cada pareja el día de prácticas correspondiente a su grupo. Los alumnos de Evaluación Final, el día del examen final de la asignatura en junio. Preliminares Cadenas de caracteres en C Empleando K&R como referencia, una cadena de caracteres constante es una secuencia de cero o más caracteres encerrados entre comillas. "una cadena", "otra cadena\n", "" (cadena vacía) Las comillas no forman parte de las cadenas y sólo sirven para delimitarlas, mientras que las secuencias de escape de caracteres (\n, \t,…) sí pueden aplicarse en ellas. Técnicamente, una cadena es una tabla (array) de caracteres, cuya representación interna tiene un carácter nulo '\0' al final, de modo que el almacenamiento físico requerido es 1 más del número de caracteres escritos entre comillas. "una cadena" (longitud = 10 caracteres) u n a c a d e n a \0 a \n (almacenamiento = 11 posiciones de memoria) "otra cadena\n" (longitud = 12 caracteres) o t r a c a d e n \0 (almacenamiento = 13 posiciones de memoria) De este modo, hay que tener cuidado al distinguir entre un carácter y una cadena que contiene un solo carácter: 'x' no es lo mismo que "x". El primero es un carácter, es decir, un entero utilizado para producir el valor numérico de la letra x, mientras que el segundo es un array de 2 caracteres: 'x' y '\0'. Ejercicios 1. Funciones de manipulación de cadenas de caracteres. Estructura de Datos y de la Información I, 2005-2006 :: Práctica 2 Página 3 de 7 Implementar las siguientes funciones de manipulación de cadenas (afines a las de string.h) en un archivo myString.c y guardar sus prototipos en otro archivo myString.h. Para ello: z z z Suponer que las cadenas se almacenan en tablas de tamaño fijo MAX_STR (establecer el #define apropiado). Pensar cuáles son los parámetros de entrada y el tipo de retorno de cada función. Implementar las funciones, efectuando en cada una de ellas el control de errores apropiado para evitar desbordamientos en las cadenas. No se podrán emplear las funciones de manejo de cadenas de la librería de C (string.lib) Funciones a implementar: z z z z myStrlen: recibe una cadena de caracteres y devuelve su longitud (-1 en caso de error). myStrcpy: recibe dos cadenas, copia el contenido de la 2ª en la 1ª, y devuelve 1 en caso de ejecución correcta ó -1 en caso de error. myStrcmp: compara el contenido de dos cadenas, devolviendo un número negativo (la diferencia que las separa) si la primera es menor que la segunda, un número positivo si la primera es mayor que la segunda y 0 si ambas son iguales. Los caracteres deben compararse uno a uno. myStrncat: recibe dos cadenas y un entero "n", y concatena hasta "n" caracteres de la 2ª cadena al final de la 1ª, devolviendo la 1ª (modificada) si la ejecución es correcta, o NULL en caso de error. 2. Manipulación de cadenas de caracteres. Desarrollar un programa con una función main que, empleando 3 cadenas sobre tablas de un tamaño fijo MAX_STR y las funciones de mystring.h: z Pida al usuario y lea por teclado el contenido de las tres cadenas (mediante la función estándar gets). z Concatene la primera y la segunda z Copie el contenido de la tercera en la segunda. z Imprima por pantalla (usando printf) el contenido y la longitud de todas ellas. z Imprima el resultado de comparar la tercera con el resto. Entrega: proyecto correspondiente correspondientes a los ejercicios 1 y 2. al ejercicio 2, incluyendo los ficheros 3. Definición de nuevos TADs e implementación mediante estructuras. Un profesor de la EPS desea manejar de forma cómoda los datos de su grupo de EDI. Para facilitarle dicha tarea, se van a definir 2 nuevos tipos abstractos de datos: grupo y alumno. El profesor desea manejar los siguientes datos: Estructura de Datos y de la Información I, 2005-2006 :: Práctica 2 z z Página 4 de 7 Para cada alumno, su nombre y su nota. Para el grupo, su nombre, el número de alumnos que lo forman, los datos de los alumnos, la nota media del grupo, la mejor nota, la peor nota, el mejor alumno y el peor alumno. Definir los TADs grupo y alumno e implementarlos definiendo las correspondientes estructuras de datos en C. Crear los correspondientes ficheros grupo.h y alumno.h Para que el profesor pueda trabajar con los datos de los alumnos, se van a definir una serie de primitivas asociadas a cada TAD. En relación con cada alumno, las primitivas permitirán (cada una de estas funcionalidades se corresponden con una primitiva diferente): 1. Almacenar nombre y nota del alumno: estos datos se solicitan al profesor en esta primitiva con un mensaje en la pantalla y el profesor los introducirá por teclado. 2. Conocer la nota del alumno: quien llame a esta función desea conocer la nota del alumno, por lo que esta función debe devolver dicha nota. 3. Conocer el nombre del alumno: quien llame a esta función desea conocer el nombre del alumno, por lo que esta función debe devolver dicho nombre. 4. Comparar dos alumnos: serán iguales si su nombre es el mismo, sean cuales sean sus notas, y distintos si difieren en el nombre. 5. Imprimir datos de un alumno: se mostrarán por pantalla 6. Copiar datos de un alumno a otro En cuanto al grupo, se desea poder: 1. Inicializar datos del grupo, asignándole un nombre e inicializando los valores de la nota mejor, peor y media, así como los del mejor y peor alumno. 2. Comprobar si un alumno está en un grupo. 3. Comprobar si un grupo está lleno. 4. Comprobar si un grupo está vacío. 5. Añadir alumno al grupo. Comprobar previamente que el grupo no está lleno, y que el alumno no estaba ya en el grupo (si estaba, no hay que añadirlo de nuevo, aunque la nota sea distinta). 6. Calcular mejor nota, peor nota, nota media, mejor alumno, peor alumno 7. Imprimir datos del grupo (sólo si el grupo no está vacío), incluyendo su nombre, el número de alumnos que lo forman, la información de cada uno de ellos y los demás datos sobre notas (media, mejor, peor, mejor alumno, peor alumno). Implementar las primitivas correspondientes a los TADs alumno y grupo en los ficheros grupo.c y alumno.c correspondientes. Usar la biblioteca mystring para el trabajo con cadenas de caracteres. Para facilitar esta implementación, se proporcionan los prototipos de las primitivas de: alumno: Estructura de Datos y de la Información I, 2005-2006 :: Práctica 2 Página 5 de 7 1. status leeAlumno (alumno * al); 2. float getAlumnoNota (alumno * al); 3. char * getAlumnoNombre (alumno * al); 4. status printAlumno (alumno * al); 5. int alumnoCmp (alumno * al1, alumno * al2); 6. alumno * alumnoCopy (alumno * al1, alumno * al2); grupo: 1. status iniGrupo (grupo * a, char * nombre); 2. boolean estaAlumnoGrupo (alumno * al, grupo * gr); 3. boolean grupoLleno (grupo * gr); 4. boolean grupoVacio (grupo * gr); 5. status addAlumnoGrupo (alumno al, grupo * gr); 6. status calculaNotas (grupo * gr); 7. status printGrupo (grupo * gr); Notas: z z Suponed que hay un número máximo de alumnos en cada grupo, MAX_ALUMNOS (establecer el #define apropiado). Definid los tipos de datos: { status: valores posibles OK y ERROR { z boolean: valores posibles TRUE y FALSE Implementad las funciones efectuando en cada una de ellas el control de errores apropiado. 4. Utilización de los nuevos TADs definidos en un programa principal Desarrollar un programa con una función main que, utilizando los TADs definidos en el ejercicio anterior en grupo.h y alumno.h: z z z Reciba como argumentos en línea de comandos el nombre de un grupo y el número de alumnos del mismo. Inicialice el grupo. Pida al profesor los datos de cada alumno, almacenándolos y añadiéndolos al grupo uno por uno. z Calcule los datos. z Imprima por pantalla todos los datos del grupo. Estructura de Datos y de la Información I, 2005-2006 :: Práctica 2 Entrega: proyecto correspondiente correspondientes a los ejercicios 3 y 4 al ejercicio 4, Página 6 de 7 incluyendo los ficheros 5. Modificación del programa anterior para lectura/escritura de datos de/en ficheros Crear un nuevo proyecto inicialmente igual al anterior y modificar los ficheros necesarios para permitir la lectura y escritura de datos a través de ficheros. Modificaciones en biblioteca de alumnos: 1. status leeAlumno (alumno * al, FILE * pf); //Lee los datos del alumno de un fichero ya abierto 2. status printAlumno (alumno * al, FILE *pf); // Escribe los datos del alumno en un fichero ya abierto Modificaciones en biblioteca de grupo: 1. status printGrupo (grupo *gr, FILE * pf); // Escribe los datos de todo el grupo en un fichero ya abierto Modificaciones en la función main: z z z z Recibe 2 argumentos de entrada en línea de comandos: nombre del fichero de entrada y nombre del fichero de salida. Lee del fichero de entrada el nombre del grupo y el número de alumnos (en la misma línea) Inicializa el grupo Lee del fichero de entrada los datos de cada alumno, almacenándolos y añadiéndolos al grupo uno por uno. z Calcula los datos de notas mejores, peores, media, etc. z Imprime en el fichero de salida todos los datos del grupo. Ejemplo de fichero de entrada: Grupo-1B 3 Alicia 7.28 Antonio 3.75 Lucia 6.00 Ejemplo de fichero de salida: Grupo-1B 3 alumnos: Alicia 7.28 Antonio 3.75 Lucia 6.00 Nota media: 5.68 Estructura de Datos y de la Información I, 2005-2006 :: Práctica 2 Página 7 de 7 Mejor nota: 7.28, alumno: Alicia Peor nota: 3.75, alumno: Antonio Entrega: proyecto correspondiente al ejercicio 5 incluyendo los ficheros correspondientes al ejercicio 5 (main) y a los creados a partir del 3 y 4 modificados.