En un programa de gestión o una utilidad que nos ayuda a administrar un sistema, no es habitual que podamos permitir que las cosas ocurran al azar. Pero los juegos se encuentran muchas veces entre los ejercicios de programación más completos, y para un juego sí suele ser conveniente que haya algo de azar, para que una partida no sea exactamente igual a la anterior.
Generar números al azar ("números aleatorios") usando C no es difícil. Si nos ceñimos al estándar ANSI C, tenemos una función llamada "rand()", que nos devuelve un número entero entre 0 y el valor más alto que pueda tener un número entero en nuestro sistema. Generalmente, nos interesarán números mucho más pequeños (por ejemplo, del 1 al 100), por lo que "recortaremos" usando la operación módulo ("%", el resto de la división).
Vamos a verlo con algún ejemplo:
Para obtener un número del 0 al 9 haríamos x = rand() % 10;
Para obtener un número del 0 al 29 haríamos x = rand() % 30;
Para obtener un número del 10 al 29 haríamos x = rand() % 20 + 10;
Para obtener un número del 1 al 100 haríamos x = rand() % 100 + 1;
Para obtener un número del 50 al 60 haríamos x = rand() % 11 + 50;
Para obtener un número del 101 al 199 haríamos x = rand() % 100 + 101;
Pero todavía nos queda un detalle para que los números aleatorios que obtengamos sean "razonables": los números que genera un ordenador no son realmente al azar, sino "pseudo-aleatorios", cada uno calculado a partir del siguiente. Podemos elegir cual queremos que sea el primer número de esa serie (la "semilla"), pero si usamos uno prefijado, los números que se generarán serán siempre los mismos. Por eso, será conveniente que el primer número se base en el reloj interno del ordenador: como es casi imposible que el programa se ponga en marcha dos días exactamente a la misma hora (incluyendo milésimas de segundo), la serie de números al azar que obtengamos será distinta cada vez.
La "semilla" la indicamos con "srand", y si queremos basarnos en el reloj interno del ordenador, lo que haremos será srand(time(0)); antes de hacer ninguna llamada a "rand()".
Para usar "rand()" y "srand()", deberíamos añadir otro fichero a nuestra lista de "includes", el llamado "stdlib":
#include
Si además queremos que la semilla se tome a partir del reloj interno del ordenador (que es lo más razonable), deberemos incluir también "time":
#include
Vamos a ver un ejemplo, que muestre en pantalla un número al azar entre 1 y 10:
/*---------------------------*/
/* Ejemplo en C nº 69: */
/* C069.C */
/* */
/* Obtener un número al */
/* azar */
/* */
/* Curso de C, */
/* Nacho Cabanes */
/*---------------------------*/
#include
#include
#include
int main() {
int n;
srand(time(0));
n = rand() % 10 + 1;
printf("Un número entre 1 y 10: %d\n", n);
return 0;
}
Ejercicios propuestos:
Dentro del fichero de cabecera "math.h" tenemos acceso a muchas funciones matemáticas predefinidas en C, como:
La raiz cuadrada de 4 se calcularía haciendo x = sqrt(4);
La potencia: para elevar 2 al cubo haríamos y = pow(2, 3);
El valor absoluto: si queremos trabajar sólo con números positivos usaríamos n = fabs(x);
Ejercicios propuestos:
Pero en C hay muchas más funciones de lo que parece. De hecho, casi todo lo que hasta ahora hemos llamado "órdenes", son realmente "funciones", y la mayoría de ellas incluso devuelven algún valor, que hasta ahora habíamos despreciado en muchos casos.
Vamos a hacer un repaso rápido a las funciones que ya conocemos y el valor que devuelven:
Función |
Valor devuelto |
Significado |
main |
int |
Programa terminado correctamente (0) o no (otro) |
printf |
int |
Número de caracteres escritos |
scanf |
int |
Número de datos leídos, o EOF si hay error |
putchar |
int |
El carácter escrito, o EOF si hay algún error |
getchar |
int |
Siguiente carácter de la entrada, o EOF en caso de error |
gets |
char* |
Cadena si todo va bien o NULL si hay error |
puts |
int |
EOF si hay algún error, otro número (un entero positivo) si no lo hay |
strcpy, strncpy |
char* |
Cadena resultado de la asignación |
strcat |
char* |
Cadena resultado |
strcmp |
int |
0 si las cadenas son iguales, <0 si la primera “es menor” o >0 si la primera “es mayor” |
sprintf |
int |
Número de caracteres almacenados en la cadena (en alguna versión, como BSD, devuelve la cadena creada) |
sscanf |
int |
Número de datos leídos, o EOF si hay error |
fopen |
FILE* |
NULL si hay error |
fclose |
int |
0 si todo va bien o EOF si hay error |
fputs |
int |
EOF si hay algún error, otro número (no especificado) si no lo hay |
fgets |
char* |
NULL si hay error o fin de fichero |
feof |
int |
0 si no es final de fichero, otro valor si lo es |
fprintf |
int |
Número de bytes escritos (puede no ser fiable si se está escribiendo a un buffer antes de mandar a disco). |
fscanf |
int |
Número de datos leídos, o EOF si hay error |
fgetc |
int |
El carácter leido, o EOF si hay algún error |
fputc |
int |
El carácter escrito, o EOF si hay algún error |
fread |
int |
Número de bytes leidos (0 o menor de lo previsto si hay error) |
fwrite |
int |
Número de bytes escritos (0 o menor de lo previsto si hay error) |
fseek |
int |
0 si se ha saltado correctamente; otro valor si el fichero no está abierto o no se ha podido saltar |
ftell |
long (size_t) |
Posición actual en el fichero (en bytes) o -1L en caso de error |
(Nota: expresiones como "FILE*" ya las conocemos, aunque todavía no entendemos bien a qué se refieren: otras como "char*" son nuevas para nosotros, pero las veremos con detalle en el próximo tema).
Por el contrario, las siguientes "órdenes" no son funciones, sino "palabras reservadas" del lenguaje C: if, else, do, while, for, switch, case, default, break, int, char, float, double, struct.
Ejercicios propuestos: