5 PEC4
5.1 strcmp()
¿En qué se basa strcmp()
para decidir que, por ejemplo, la letra 'O'
es mayor que la letra 'A'
?
La respuesta la tenemos en el código ASCII (numérico) que tiene asociado cada carácter. Por este motivo es normal que interprete diferente una 'A'
y una 'a'
, ya que son caracteres diferentes; de hecho según los valores ASCII, tenemos que 'A'
< 'a'
.
Por si queremos consultar la tabla ASCII por internet, la podemos generar nosotros mismos de la siguiente forma:
/* Ejemplo ES0501 */
#include <stdio.h>
int main(int argc, char **argv) {
int i;
/* Relación de caracteres ASCII (¡únicamente se trata de un subconjunto!)
ordenados de menor a mayor */
for (i=33; i<=126; i++) {
printf("%d : %c\n", i, i);
}
return 0;
}
5.2 scanf()
Cuando utilizamos scanf()
hasta ahora siempre le hemos pasado el nombre de la variable precedido por &
. Este carácter significa que le estamos pasando la posición de la memoria donde reside la variable facilitada.
Así, por ejemplo, cuando hacemos la siguiente operación scanf("%d", &numero);
estamos pasando el valor que introducimos por teclado directamente a la posición de memoria donde tenemos guardada la variable numero
. De ahí utilizar &numero
en vez de numero
. El mismo comportamiento lo encontramos en los tipos primitivos char
, float
, etc.
Los vectores de caracteres en lenguaje C tienen una característica: el nombre del array contiene la dirección de memoria donde se guarda la primera posición del array.
Por ejemplo, cuando ejecutamos scanf("%s", cadena);
el valor de cadena es la dirección de memoria inicial donde está ubicado el array. Dicho de otro modo, cadena contiene el mismo valor que &cadena[0]
(es otra forma que tenemos para referirnos a la posición inicial en memoria del array).
A continuación se adjunta un ejemplo con todos estos conceptos:
/* Ejemplo ES0502 */
#include <stdio.h>
#define MAXIMO 10
int main(int argc, char **argv) {
char cadena[MAXIMO];
int numero;
printf("Reservada la posición de memoria %p para la variable numero\n", &numero);
printf("Reservada la posición de memoria %p para la variable cadena\n", cadena);
printf("Reservada la posición de memoria %p para la variable cadena\n", &cadena[0]);
printf("\nIntroduce un número entero: ");
scanf("%d", &numero);
printf("\nIntroduce una cadena: ");
scanf("%s", cadena);
printf("\nHas asignado los siguientes valores :\n");
printf("numero = %d \n", numero);
printf("cadena = %s \n", cadena);
return 0;
}
5.3 El finalizador ‘\0’ y strcmp()
Como se vio en el módulo Cadenas de caracteres en C de la xWiki, “una cadena de caracteres o string es una secuencia de caracteres finalizada por el carácter ‘\0’”. Por lo tanto, hemos de tener en cuenta que el finalizador '\0'
debe caber en nuestra variable, ya que esta es la forma que tiene C de saber dónde termina un string en memoria.
Imaginemos que tenemos tres cadenas, con el mismo contenido pero de tamaño diferente (podemos tener posiciones vacías). ¿Qué pasa si las comparamos? ¿Y si comparamos con una cadena de mismo contenido pero sin finalizador '\0'
?
/* Ejemplo ES0503 */
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
char ciudad1[7] = "Girona";
char ciudad2[8] = "Girona";
char ciudad3[6] = "Girona"; /* no contiene el '\0' final */
/* si strcmp devuelve 0 significa que las dos cadenas son iguales */
printf ("¿Las variables ciudad1 y ciudad2 son iguales? %d\n",
strcmp(ciudad1, ciudad2));
printf ("¿Las variables ciudad1 y ciudad3 son iguales? %d\n",
strcmp(ciudad1, ciudad3));
}
La forma que tenemos para forzar que una cadena no contenga el finalizador es limitando su tamaño a los caracteres que contendrá, sin tener en cuenta reservar uno para '\0'
. En este caso lo hacemos con char ciudad3[6] = "Girona"
.
La salida generada es la siguiente:
¿Las variables ciudad1 y ciudad2 son iguales? 0
¿Las variables ciudad1 y ciudad3 son iguales? -1
De ahí la importancia del finalizador de cadenas de caracteres. Por lo tanto, si por ejemplo tenemos una variable x
de tipo string y de tamaño máximo 15, realmente en nuestro programa la definiremos con longitud 15+1, para que quepa el finalizador '\0'
en caso de que se ocupen los 15 caracteres anteriores.
5.4 El finalizador ‘\0’ y strlen()
A continuación se expone un ejemplo en el que se muestra la importancia del finalizador '\0'
en la función strlen()
de C, la que nos devuelve el tamaño de una cadena de caracteres:
/* Ejemplo ES0504 */
#include <stdio.h>
#include <string.h>
#define MAX_LETRAS 8+1
int main(int argc, char **argv) {
char nombre[MAX_LETRAS];
int numLetras;
printf("Introduce un nombre: ");
scanf("%s", nombre);
/* Ejemplo: si en este punto hemos introducido el
* nombre Quim, dentro de la cadena de caracteres nombre[]
* tendremos los siguientes datos:
*
* nombre[0] = 'Q'
* nombre[1] = 'u'
* nombre[2] = 'i'
* nombre[3] = 'm'
* nombre[4] = '\0' (finalizador del string)
* nombre[5] = valor aleatorio
* nombre[6] = valor aleatorio
* nombre[7] = valor aleatorio
* nombre[8] = valor aleatorio
*
* El finalizador '\0' se añade automáticamente
* al leer un string desde teclado mendiante scanf.
*
* El comando strlen(...) recorre el string posición
* a posición para conocer su longitud. ¿Cuándo finaliza
* este recorrido? hay dos posibles opciones:
*
* - cuando encuentra el finalizador '\0'
* - cuando llega a la última posición del string
*
* Por lo tanto, si hemos introducido Quim, el valor que
* devolverá strlen(...) será 4.
*/
numLetras = strlen(nombre);
printf("El nombre \"%s\" tiene %d letras\n", nombre, numLetras);
/* ¿Qué pasa si sobrescribimos el finalizador '\0' con
* un caracter cualquiera? por ejemplo 'X'
*/
printf("\nSobrescribimos el finalizador '\\0'.");
nombre[numLetras] = 'X';
/* Volvemos a calcular la longitud del string */
numLetras = strlen(nombre);
/* ¿Por qué motivo ahora ha cambiado la longitud de la
* variable nombre, si no la hemos vuelto a definir?
*/
printf("\nAhora el nombre \"%s\" tiene %d letras\n", nombre, numLetras);
return 0;
}
Si se ejecuta el programa, la salida obtenida será similar a la siguiente:
Introduce un nombre: Quim
El nombre "Quim" tiene 4 letras
Sobrescribimos el finalizador '\0'.
Ahora el nombre "QuimX�!��" tiene 9 letras
5.5 Ejemplo: comparacionStrings
La forma como comparamos strings en lenguaje algorítmico es diferente que la usada en lenguaje C:
- Lenguaje algorítmico: la comparación entre strings se hace con
=
. - Lenguaje C: la comparación entre strings se hace con la función
strcmp()
, la cual realiza una comparación carácter a carácter de las dos cadenas y como resultado:- Devuelve
0
: si ambas cadenas son iguales. - Devuelve un valor negativo: si la primera cadena < segunda cadena.
- Devuelve un valor positivo: si la primera cadena > segunda cadena.
- Devuelve
Un ejemplo donde realiza una comparación de dos strings puede ser el siguiente:
algorithm comparacionStrings
var
cadena1: string;
cadena2: string;
end var
cadena1:= "UOC";
cadena2:= "UAB";
if (cadena1 = cadena2) then
writeString(cadena1);
writeString(" = ");
writeString(cadena2);
else
if (cadena1 > cadena2) then
writeString(cadena1);
writeString(" > ");
writeString(cadena2);
else
writeString(cadena1);
writeString(" < ");
writeString(cadena2);
end if
end if
end algorithm
En lenguaje C, la comparación carácter a carácter entre los string "UOC"
y "UAB"
que realiza la función strcmp()
es la siguiente:
- Caracteres de la posición 0 de los dos string: UOC vs UAB. Son iguales, con lo que pasa a comparar el siguiente carácter.
- Caracteres de la posición 1 de los dos string: UOC vs UAB. Detecta que son diferentes, ya que
'O'
>'A'
según sus valores ASCII, finaliza la comparación y la funciónstrcmp()
devuelve un valor positivo.
/* Ejemplo ES0505 */
#include <stdio.h>
#include <string.h>
#define MAX_LETRAS 3+1
int main(int argc, char **argv) {
char cadena1[MAX_LETRAS] = "UOC";
char cadena2[MAX_LETRAS] = "UAB";
int resultadoComparacion = 0;
resultadoComparacion = strcmp(cadena1, cadena2);
printf("Comparación de strings \"%s\" y \"%s\" = %d\n",
cadena1, cadena2, resultadoComparacion);
if (resultadoComparacion == 0) {
printf("El resultado %d significa ", resultadoComparacion);
printf("que el string \"%s\" == string \"%s\"\n",
cadena1, cadena2);
} else {
if (resultadoComparacion < 0) {
printf("El resultado %d significa ", resultadoComparacion);
printf("que el string \"%s\" < string \"%s\"\n",
cadena1, cadena2);
} else {
/* En este punto, resultadoComparacion > 0 */
printf("El resultado %d significa ", resultadoComparacion);
printf("que el string \"%s\" > string \"%s\"\n",
cadena1, cadena2);
}
}
return 0;
}
La salida de la ejecución del programa C es:
Comparación de strings "UOC" y "UAB" = 1
El resultado 1 significa que el string "UOC" > string "UAB"
5.6 Ejemplo: nóminas
Imaginemos que queremos un programa que nos permita introducir las nóminas de todos los empleados de nuestra empresa. Un empleado lo definimos como nombre (cadena de caracteres) + nómina (real). El programa debe mostrar al final del todo la relación de nóminas de todos los empleados, la media de todas las nóminas de la empresa, y quién cobra más y menos en la empresa.
Una posible forma de programarlo en C sería la siguiente:
/* Ejemplo ES0506 */
#include <stdio.h>
#include <string.h>
#define MAX_EMPLEADOS 5
#define MAX_NOMBRE 20+1
typedef struct {
char nombre[MAX_NOMBRE];
float nomina;
} tEmpleado;
int main(int argc, char **argv) {
tEmpleado empleados[MAX_EMPLEADOS];
int posMaxNomina;
int posMinNomina;
float sumaNominas;
int i;
posMaxNomina = 0;
posMinNomina = 0;
sumaNominas = 0.0;
for (i=0; i<MAX_EMPLEADOS; i++) {
printf("\nNombre empleado : ");
scanf("%s", empleados[i].nombre);
printf("Nómina empleado : ");
scanf("%f", &empleados[i].nomina);
}
printf("\nListado de nóminas de empleados : \n\n");
for (i=0; i<MAX_EMPLEADOS; i++) {
sumaNominas = sumaNominas + empleados[i].nomina;
if (empleados[i].nomina > empleados[posMaxNomina].nomina) {
posMaxNomina = i;
}
if (empleados[i].nomina < empleados[posMinNomina].nomina) {
posMinNomina = i;
}
printf("%s --> %.2f €\n", empleados[i].nombre, empleados[i].nomina);
}
printf("\nPromedio nóminas : %.2f €", sumaNominas/MAX_EMPLEADOS);
printf("\nNómina mayor : %.2f € (%s)",
empleados[posMaxNomina].nomina, empleados[posMaxNomina].nombre);
printf("\nNómina menor : %.2f € (%s)",
empleados[posMinNomina].nomina, empleados[posMinNomina].nombre);
}
Como se puede ver, se utiliza un vector de tEmpleado
de manera que, dada una longitud máxima del vector, iremos introduciendo los tEmpleado
uno a uno dentro de él. Una vez hecho, volvemos a recorrer el vector de tEmpleado
, realizamos todos los cálculos que nos piden y mostramos por pantalla las nóminas de todos los empleados.
En este ejemplo la variable i
hace de índice para recorrer el vector, y las variables posMaxNomina
y posMinNomina
también son índices: indican en qué posición están los empleados con la nómina más alta y más baja respectivamente.
5.7 Ejemplo: brisca
Ejemplo con diferentes recorridos realizado sobre tuplas guardadas en un vector, utilizando el juego de cartas de la brisca. Para explicar mejor el planteamiento de cada implementación, se han añadido comentarios detallados dentro del código.
/* Ejemplo ES0507 */
#include <stdio.h>
#include <stdbool.h>
/* Punto de partida: sabemos jugar perfectamente
* a la brisca (https://es.wikipedia.org/wiki/Brisca),
* pero en cambio somos un desastre contando
* la puntuación de todas las cartas ganadas. Por
* este motivo queremos hacer un programa que nos ayude
* en esta tarea (y también para practicar diferentes
* iteraciones con bucles). El programa pedirá por
* teclado carta a carta y finalizará cuando se introduzca
* un tipo de palo distinto de los definidos.
* Deberá generar las siguientes salidas:
* 1. Listar todas las cartas introducidas.
* 2. Mostrar la carta con una puntuación más alta.
* 3. Mostrar la puntuación total alcanzada.
* 4. Comparar parejas de cartas (1a vs 2a, 2a vs 3a,
* 3a vs 4a, ...) e indicar si son del mismo palo.
*/
#define MAX_NUM_CARTAS 48
#define NUM_VALORES 13
#define MAX_NUM_PALOS 4
typedef enum {OROS, COPAS, BASTOS, ESPADAS, FINALIZAR} tPalo;
typedef struct {
tPalo palo;
int numero;
int valor;
} tCarta;
int main(int argc, char **argv) {
tCarta cartaAux;
tCarta cartaDeMayorValor;
tCarta cartas[MAX_NUM_CARTAS];
int valores[NUM_VALORES];
char* nombres[MAX_NUM_PALOS];
bool isFinalizado;
int puntuacion;
bool isMismoPalo;
int i, j;
/* Se inicializa el vector valores con las
* puntuaciones de todas las cartas. El nombre
* de la carta hace de índice del vector, y el
* valor guardado en aquella posición es su
* puntuación. Ejemplo:
* - una carta con un 1 devolverá 11 puntos,
* correspondientes al valor de la posición 1.
* - una carta con un 5 devolverá 0 puntos,
* correspondientes al valor de la posición 5.
*/
valores[0] = 0;
valores[1] = 11;
valores[2] = 0;
valores[3] = 10;
valores[4] = 0;
valores[5] = 0;
valores[6] = 0;
valores[7] = 0;
valores[8] = 0;
valores[9] = 0;
valores[10] = 2;
valores[11] = 3;
valores[12] = 4;
/* El siguiente vector nos ayudará a mostrar
* por pantalla de forma automática la descripción
* asociada a cada uno de los valores definidos en
* el enumerativo tPalo
*/
nombres[0] = "Oros";
nombres[1] = "Copas";
nombres[2] = "Bastos";
nombres[3] = "Espadas";
/* La variable booleana se utilizará para
* finalizar el primer bucle de introducción
* de cartas desde teclado
*/
isFinalizado = false;
i = 0;
j = 0;
puntuacion = 0;
printf("Tipo de carta: 0=OROS, 1=COPAS, 2=BASTOS, 3=ESPADAS\n");
while (!isFinalizado) {
printf("\nIntroduce tipo de carta: ");
scanf("%u", &cartaAux.palo);
/* Si el palo introducido no corresponde a ninguno de los
* cuatro definidos, significa que no se quiere
* entrar otra carta desde teclado
*/
if (cartaAux.palo != OROS && cartaAux.palo != COPAS
&& cartaAux.palo != BASTOS && cartaAux.palo != ESPADAS) {
isFinalizado = true;
} else {
printf("Introduce número de carta: ");
scanf("%d", &cartaAux.numero);
/* Se valida que el número de la carta
* introducida sea válido: valor comprendido
* entre 1 y 12
*/
if (cartaAux.numero < 1 || cartaAux.numero > 12) {
printf("Error: número de la carta incorrecto!\n");
} else {
/* Se calcula el valor de la carta y
* asigna al campo valor de la tupla
* cartaAux (de tipo tCarta)
*/
cartaAux.valor = valores[cartaAux.numero];
cartas[i] = cartaAux;
/* La variable 'i' contendrá el número
* de cartas válidas introducidas por
* teclado.
*/
i = i + 1;
}
}
}
/* Salida 1:
* Recorremos el vector de cartas para mostrar
* por pantalla todos los elementos (cartas)
* que contiene.
*/
printf("\nRelación de cartas introducidas: \n");
for (j = 0; j < i; j++) {
printf("\t%d de %s (%d puntos) \n", cartas[j].numero,
nombres[cartas[j].palo], cartas[j].valor);
}
/* Salida 2:
* Recorremos el vector de cartas y buscamos
* la que tiene una mayor puntuación. En caso
* de empate, mostramos la última introducida.
*/
/* Inicializamos el valor de cartaDeMayorValor
* a valor = 0
*/
cartaDeMayorValor.valor = 0;
printf("\nCarta de mayor puntuación: \n");
for (j = 0; j < i; j++) {
/* En cada iteración del bucle nos aseguramos
* de que cartaDeMajorValor sea la carta
* con un valor mayor. Comparamos la carta
* que estamos tratando actualmente con la carta
* que hasta ahora hemos considerado de mayor valor.
*/
if (cartas[j].valor >= cartaDeMayorValor.valor) {
cartaDeMayorValor.palo = cartas[j].palo;
cartaDeMayorValor.numero = cartas[j].numero;
cartaDeMayorValor.valor = cartas[j].valor;
}
}
printf("\t%d de %s (%d puntos) \n", cartaDeMayorValor.numero,
nombres[cartaDeMayorValor.palo], cartaDeMayorValor.valor);
/* Salida 3:
* Recorremos el vector de cartas y vamos sumando
* todos los valores, a fin de obtener la
* puntuación total.
*/
printf("\nPuntuación total: \n");
for (j = 0; j < i; j++) {
puntuacion = puntuacion + cartas[j].valor;
}
printf("\t%d puntos \n", puntuacion);
/* Salida 4:
* Recorremos el vector de cartas y vamos comparando
* parejas de carta: la que estamos tratando con
* la que viene a continuación. Mostramos por pantalla
* si son del mismo palo o no.
*/
printf("\nComparación de cartas: \n");
/* Importante: en este recorrido del vector
* de cartas vamos comparando la carta de la
* posición actual j con la carta que está
* en la siguiente posición j+1. Esto significa
* que el límite de las iteraciones del
* bucle pasa a ser i-1 (un elemento antes
* del final), ya que cuando tratamos este
* elemento lo compararemos con el siguiente,
* que es el último del vector. Si en vez
* tener i-1 tuviéramos solo i, en
* la última iteración daría error, ya
* que se estaría accediendo a una posición
* incorrecta del vector de cartas (i+1).
*/
for (j = 0; j < i-1; j++) {
/* Para comparar la carta de la posición actual
* con la que hay en la siguiente posición,
* utilizamos los índices j y j+1 respectivamente.
*/
isMismoPalo = (cartas[j].palo == cartas[j+1].palo);
printf("\t%d de %s vs %d de %s: ", cartas[j].numero,
nombres[cartas[j].palo], cartas[j+1].numero,
nombres[cartas[j+1].palo]);
if (isMismoPalo) {
printf("¡son del mismo palo!\n");
} else {
printf("¡son de palos distintos!\n");
}
}
return 0;
}
Un ejemplo de ejecución sería:
Tipo de carta: 0=OROS, 1=COPAS, 2=BASTOS, 3=ESPADAS
Introduce tipo de carta: 0
Introduce número de carta: 1
Introduce tipo de carta: 0
Introduce número de carta: 10
Introduce tipo de carta: 0
Introduce número de carta: 5
Introduce tipo de carta: 2
Introduce número de carta: 10
Introduce tipo de carta: 2
Introduce número de carta: 1
Introduce tipo de carta: 3
Introduce número de carta: 4
Introduce tipo de carta: 9
Relación de cartas introducidas:
1 de Oros (11 puntos)
10 de Oros (2 puntos)
5 de Oros (0 puntos)
10 de Bastos (2 puntos)
1 de Bastos (11 puntos)
4 de Espadas (0 puntos)
Carta de mayor puntuación:
1 de Bastos (11 puntos)
Puntuación total:
26 puntos
Comparación de cartas:
1 de Oros vs 10 de Oros: ¡son del mismo palo!
10 de Oros vs 5 de Oros: ¡son del mismo palo!
5 de Oros vs 10 de Bastos: ¡son de palos distintos!
10 de Bastos vs 1 de Bastos: ¡son del mismo palo!
1 de Bastos vs 4 de Espadas: ¡son de palos distintos!
5.8 Ejemplo: revisionITV
A continuación se plantea un ejemplo en el que se modifica el comportamiento que tienen por defecto los enumerativos en C.
En este caso, tenemos un centro autorizado para realizar revisiones de la ITV para diferentes tipos de vehículos. Queremos que nuestro programa lea desde teclado el valor de los tres campos que definen la tupla tRevisionITV
: la matrícula del vehículo, el tipo y el resultado de la revisión. Al final de todo, debe mostrar por pantalla el detalle de todas las revisiones realizadas.
Una posible codificación del programa es la siguiente:
/* Ejemplo ES0508 */
#include <stdio.h>
#include <string.h>
#define MAX_MATRICULA 10+1
#define MAX_REVISIONES 3
#define MAX_RESULTADO 3
const int MAX_CATEGORIA = 10;
/* Por defecto el valor que se asigna
* al primer elemento de un enumerativo es 0,
* y se va incrementando en +1 por cada
* elemento sucesivo. Este comportamiento
* lo podemos modificar.
*
* Opción 1: le podemos asignar directamente
* un valor entero a cada elemento de la
* siguiente forma:
*/
typedef enum {FAVORABLE = 1, DESFAVORABLE = 2, NEGATIVA = 0} tResultado;
/*
* Opción 2: podemos asignar valores a unos
* pocos elementos, y el resto de elementos
* sin valor toman como valor el último
* conocido incrementado en +1; en el
* siguiente caso, FURGONETA = 5 y CAMION = 6, ya
* que el anterior valor conocido es COCHE = 4:
*/
typedef enum {MOTO = 2, COCHE = 4, FURGONETA, CAMION} tCategoria;
typedef char tMatricula[MAX_MATRICULA];
typedef struct {
tMatricula matricula;
tCategoria categoria;
tResultado resultado;
} tRevisionITV;
int main(int argc, char **argv) {
tRevisionITV revisionITV;
tRevisionITV revisionesITV[MAX_REVISIONES];
int i;
/* Utilizaremos los siguientes dos vectores
* para mostrar por pantalla el literal
* correspondiente al valor del enumerativo.
*/
char* resultados[MAX_RESULTADO];
char* categorias[MAX_CATEGORIA];
resultados[0] = "negativa";
resultados[1] = "favorable";
resultados[2] = "desfavorable";
categorias[2] = "moto";
categorias[4] = "coche";
categorias[5] = "furgoneta";
categorias[6] = "camión";
/* Lectura de datos desde teclado */
for (i=0; i<MAX_REVISIONES; i++) {
printf("Matrícula: ");
scanf("%s", revisionITV.matricula);
printf("Categoría (2=moto, 4=coche, 5=furgoneta, 6=camión): ");
scanf("%u", &revisionITV.categoria);
printf("Resultado (1=favorable, 2=desfavorable, 0=negativa): ");
scanf("%u", &revisionITV.resultado);
/* Importante: en lenguaje C no haremos una asignación directa
* entre estructuras de datos complejas (tuples). En su lugar
* realizaremos asignaciones campo a campo.
*/
strcpy(revisionesITV[i].matricula, revisionITV.matricula);
revisionesITV[i].categoria = revisionITV.categoria;
revisionesITV[i].resultado = revisionITV.resultado;
printf("\n");
}
/* Se muestran los resultados por pantalla */
printf("Listado de revisiones realizadas: \n");
for (i=0; i<MAX_REVISIONES; i++) {
printf("\tVehículo: %s, categoría: %s, ITV: %s \n",
revisionesITV[i].matricula,
categorias[revisionesITV[i].categoria],
resultados[revisionesITV[i].resultado]);
}
return 0;
}
Un ejemplo de ejecución puede ser el siguiente:
Matrícula: 7654-GFD
Categoría (2=moto, 4=coche, 5=furgoneta, 6=camión): 2
Resultado (1=favorable, 2=desfavorable, 0=negativa): 1
Matrícula: B-2189-FM
Categoría (2=moto, 4=coche, 5=furgoneta, 6=camión): 4
Resultado (1=favorable, 2=desfavorable, 0=negativa): 2
Matrícula: 566423
Categoría (2=moto, 4=coche, 5=furgoneta, 6=camión): 6
Resultado (1=favorable, 2=desfavorable, 0=negativa): 0
Listado de revisiones realizadas:
Vehículo: 7654-GFD, categoría: moto, ITV: favorable
Vehículo: B-2189-FM, categoría: coche, ITV: desfavorable
Vehículo: 566423, categoría: camión, ITV: negativa
5.9 Ejemplo: conductores
Imaginemos que tenemos una empresa de seguros y queremos penalizar aquellos conductores asegurados que hayan cometido muchas infracciones de tráfico, independientemente de los puntos asociados a cada una de ellas. Para encontrarlos necesitaremos revisar todos los conductores, por lo tanto estamos ante un recorrido.
Una posible implementación en lenguaje C sería:
/* Ejemplo ES0509 */
#include <stdio.h>
#include <string.h>
#define MAX_CONDUCTORES 4
#define MAX_NOMBRE 15+1
typedef struct{
char nom[MAX_NOMBRE];
int numInfracciones;
} tConductor;
int main(int argc, char **argv) {
tConductor conductores[MAX_CONDUCTORES];
int minimoInfracciones;
int conductoresEncontrados;
int i;
minimoInfracciones = 0;
conductoresEncontrados = 0;
for (i=0; i<MAX_CONDUCTORES; i++) {
printf("Nombre: ");
scanf("%s", conductores[i].nom);
printf("Número de infracciones: ");
scanf("%d", & conductores[i].numInfracciones);
}
printf("\nLímite mínimo de infracciones: ");
scanf("%d", &minimoInfracciones);
/* Recorrido: a partir de un valor mínimo de infracciones,
* recorremos todo el vector de tConductor y contabilizamos
* aquellos que como mínimo tengan el mismo número. */
for (i=0; i<MAX_CONDUCTORES; i++) {
if (conductores[i].numInfracciones >= minimoInfracciones) {
conductoresEncontrados++;
}
}
printf("\n>> Se han contrado %d conductores con un mínimo de %d infracciones. \n",
conductoresEncontrados, minimoInfracciones);
return 0;
}
Un ejemplo de ejecución puede ser el siguiente:
Nombre: Jan
Número de infracciones: 2
Nombre: Belén
Número de infracciones: 3
Nombre: Luis
Número de infracciones: 5
Nombre: María
Número de infracciones: 5
Límite mínimo de infracciones: 3
>> Se han encontrado 3 conductores con un mínimo de 3 infracciones.
5.10 Errores más frecuentes
5.10.1 Definición de tipo: definición de tuplas mal ubicada
Código incorrecto:
#include <stdio.h>
#include <stdbool.h>
int main(int argc, char **argv) {
typedef struct {
int id;
char brand[MAX_LEN];
float price;
} tHotel;
tHotel myHotel;
/* ... */
return 0;
}
Los tipos de datos se declararán al principio del bloque de código, y fuera de cualquier función (sea el main
u otra), ya que los tipos son globales en todo el programa, y las variables asociadas a los tipos se declaran posteriormente en cada una de las funciones que se necesitan.
Las datos de tipo tupla (struct
) no son una excepción, y por tanto no es correcto abrir un bloque de definición de tuplas en un bloque central de código (y menos aún abrir varios bloques de definición de tuplas a medida que los necesitamos).
Código correcto:
#include <stdio.h>
#include <stdbool.h>
typedef struct{
int id;
char brand[MAX_LEN];
float price;
} tHotel;
int main(int argc, char **argv) {
tHotel myHotel;
/* ... */
return 0;
}
5.10.2 Definición de tipo: definición mal ubicada
Código incorrecto:
#include <stdio.h>
#include <stdbool.h>
int main(int argc, char **argv) {
typedef enum {BUDGET, INN, RESORT} tTypeHotel;
typedef enum {STANDARD, SUITE} tTypeRoom;
tTypeHotel myHotelType;
tTypeRoom myRoomType;
myHotelType = BUDGET;
myRoomType = STANDARD;
/* ... */
return 0;
}
Los tipos de datos se declararán al principio del bloque de código, y fuera de cualquier función (sea el main
u otra), ya que los tipos son globales en todo el programa, y las variables asociadas a los tipos se declaran posteriormente en cada una de las funciones que se necesitan. No es correcto abrir un bloque de definición de tipo dentro de un bloque central de código (y menos aún abrir varios bloques de definición de tipo a medida que los necesitamos).
Código correcto:
#include <stdio.h>
#include <stdbool.h>
typedef enum {BUDGET, INN, RESORT} tTypeHotel;
typedef enum {STANDARD, SUITE} tTypeRoom;
int main(int argc, char **argv) {
tTypeHotel myHotelType;
tTypeRoom myRoomType;
myHotelType = BUDGET;
myRoomType = STANDARD;
/* ... */
return 0;
}