Archivo

Entradas Etiquetadas ‘division’

Algoritmos: Validar un DNI en C

Miércoles, 4 de Abril de 2012 Gaspar Fernández Sin comentarios

En España, para identificar de forma única a cada ciudadano se utiliza el número del Documento Nacional de Identidad (DNI). Como es costumbre, en muchos datos numéricos, como este, un número de cuenta corriente, códigos ISBN, etc existe un algoritmo de verificación que comprueba que el número es válido. En este caso, la comprobación se realiza con la letra que acompaña el número.

El algoritmo es sencillo, puede que a la hora de implementarlo no nos acordemos del orden de las letras (para eso lo pongo, y podemos hacer Copia y Pega rápidamente).

Tal vez si estás empezando con la programación y no domines el uso de Arrays te resulte algo complicado, pero es un buen momento para empezar a programar Arrays, te ayudarán mucho y te ahorrarán en casos como este muchísimo código.

Presento primero una función que genera la letra del DNI a partir del número:

1
2
3
4
5
6
char letraDNI(int dni)
{
  char letra[] = "TRWAGMYFPDXBNJZSQVHLCKE";

  return letra[dni%23];
}

En definitiva, necesitamos averiguar el resto de el número del DNI entre 23 (lo cual nos dará una cifra entre 0 y 22), cada cifra corresponderá con una letra: el 0 con la T, el 1 con la R, el 2 con la W…

Podemos utilizar esta función, no para generar, sino para validar un DNI almacenado en una cadena de caracteres:

1
2
3
4
5
6
7
short verificaDNI(char *dni)
{
  if (strlen(dni)!=9)
      return 0;
  else
    return (letraDNI(atoi(dni))==dni[8]);
}

En ella, convertimos el número a entero (después de verificar que hay 9 caracteres), y se lo pasamos a letraDNI() para que genere una letra, luego comparamos la letra generada con la letra introducida por el usuario.

Aquí vemos el código completo:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
*************************************************************
* @file dni.c
* @brief Comprueba la letra del DNI (España)
*
* @author Gaspar Fernández <blakeyed@totaki.com>
* http://totaki.com/poesiabinaria/algoritmos/
*************************************************************/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char letraDNI(int dni)
{
  char letra[] = "TRWAGMYFPDXBNJZSQVHLCKE";

  return letra[dni%23];
}

short verificaDNI(char *dni)
{
  if (strlen(dni)!=9)
      return 0;
  else
    return (letraDNI(atoi(dni))==dni[8]);
}

int main(int argc, char *argv[])
{
  char dni[20];
 
  printf ("Introduce tu DNI con letra (sin espacios): ");
  scanf("%s", dni);

  if (verificaDNI(dni))
    printf ("El DNI es correcto\n");
  else
    printf ("El DNI no es correcto\n");
   
  return EXIT_SUCCESS;
}

Descargar: dni.c (838bytes)

Generador de números primos en C

Martes, 15 de Diciembre de 2009 Gaspar Fernández 2 comentarios

Un ejercicio de estos típicos de lenguaje C, es la generación de números primos y la comprobación de éstos. Ni que decir tiene que esta es sólo una de las 13.485,72 maneras (o más) de solucionar este problema. Y es más estamos complicando un poco la cosa, ya que sólo generaremos 10 números, que se almacenarán en un fichero binario, y a la siguiente vez que ejecutamos el programa, se leerá ese último número y seguiremos generando primos a partir de ahí:

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <stdio.h>
#include <math.h>

// Comprobamos si un número es primo o no
int es_primo(int numero)
{
  int res=0;
  int divs=2;
  int mitad;
  if (numero>2)    // Si el número es mayor a 2, comprobamos si es primo.
    {
      /* Para ahorrar sólo comprobamos si un número es divisible hasta su mitad, ya que 7/2 = 3.xxx, 7/3=2.xxx, 7/4=0.xxx */
      /* cuando empezamos a obtener valores menores que 0, ya no encontraremos más divisores enteros */
      mitad=floor((double)numero/2);
      do
    {
      res=(numero%divs!=0);  /* ¿ El resto es 0 ? */
      //      printf("Divido %d entre %d. Resto %d. Res: %d\n", numero, divs, numero%divs, res);
      divs++;
    } while ((res!=0) && (divs<=mitad));
    }
  else if (numero==2) /* || (numero==1) */ /* ¿1 lo consideramos primo? */
    res=1;

  return res;
}

// Genera primos, los almacenaremos en p, empezamos desde _inicial_ y generamos _cantidad_ de números
void genera_primos (FILE *p, int inicial, int cantidad)
{
  int primos=0;
  int i=inicial;

  printf("INI:%d\n", inicial);
  while (primos<cantidad)
    {
      // Vamos comprobando uno a uno si es primo
      if (es_primo(i))
    {
      fwrite(&i, sizeof(int), 1, p);
      primos++;
      printf("%d\n", i);
    }
      i++;
    }
}


int main()
{
  FILE *p;
  int last_primo;
  // Abrimos el archivo para actualizar
  p = fopen("primos.dat", "a+b");
  if (p)
    {
      fseek(p, -sizeof(int), SEEK_END); /* Nos posicionamos para leer el último entero almacenado. */
      fread(&last_primo, sizeof(int), 1, p); /* Leemos el último */
      fseek(p, 0, SEEK_END); /* Nos posicionamos al final, para seguir escribiendo */
      printf("%d: ",last_primo);
      genera_primos(p, last_primo+1, 10);
      fclose(p);
    }
  else
    printf("No puedo abrir el archivo");
}

De aquí se pueden extraer ideas para hacer muchos ejercicios de este tipo. Eso sí, hay que recordar que para compilar tenemos que incluir la librería matemática. Por ejemplo, con gcc, en el caso de llamar al archivo primos.c, se compilaría:

gcc -lm -o primos primos.c

Visita otras webs de la red