Archivo

Entradas Etiquetadas ‘strrev’

Cambio de base (de base b1 a b2… hasta base36 o tal vez más)

Viernes, 22 de Mayo de 2009 blakeyed Sin comentarios

Hace tiempo tuve la necesidad de hacer una función de cambios de base, pero que no estuviera limitada, es decir, no tuviera definido qué base vamos a introducir y qué base debe devolver. Es decir, convertiremos un número en base b1 a base b2; la limitación, el número de caracteres con los que contemos, en el ejemplo hay hasta base 36, y es fácil extenderlo hasta base256… un número en hexadecimal no tiene desde el 0 al 9 y de la A a la F, pues un base36, del 0 al 9 y de la A a la Z. Con un poco de imaginación podremos sacar muchas ideas de este fragmento. Incluye programa de ejemplo:

Hace tiempo tuve la necesidad de hacer una función de cambios de base, pero que no estuviera limitada, es decir, no tuviera definido qué base vamos a introducir y qué base debe devolver. Es decir, convertiremos un número en base b1 a base b2; la limitación, el número de caracteres con los que contemos, en el ejemplo hay hasta base 36, y es fácil extenderlo hasta base64, base256, por ejemplo… con un poco de imaginación podremos sacar muchas ideas de este fragmento. Incluye programa de ejemplo:

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
67
68
69
#include <stdio.h>
#include <string.h>
#include "strutils.h"

void cambiobase (char *n1, int b1, char *n2, int b2)
{
  int lnum = strlen(n1);        /* Longitud de nuestro número */
  /* Caracteres que forman todos los posibles números hasta base 36 */
  char numeros[37]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  int divide;
  int i;
  int posn=0;
  int long2;

  do
    {
      divide = 0;
      long2 = 0;                /* Será un puntero de n1, */
                                /* ya que iremos modificando su valor, long2 */
                                /* nos indicará por dónde vamos */

      for (i=0; i<lnum; i++)
        {
          /* divide vale lo que valía antes multiplicado por la base + el número que acabamos de extraer */
          /* que coincidirá con la posición del carácter dentro del array de numeros[] */
          divide=divide*b1+strchr(numeros, n1[i])-(char*)&numeros;

          if (divide>=b2)
            {
              /* Si el número resultante es mayor o igual a la base */
              n1[long2] = numeros [(int) divide / b2]; /* Modificaremos el dígito long2 de n1, */
                                /*  y este será el número divide/b2 en base b1  */
              divide = divide % b2; /* divide será el resto de la división */
              long2++;
            }
          else if (long2>0)
            {
              n1[long2] = '0';  /* divide<b2, pero en iteraciones anteriores ha sido >= */
              long2++;
            }
        }

      lnum=long2;
      /* hemos hallado un dígito de n2. Su valor será divide */
      n2[posn] = numeros[divide];
      posn++;                   /* posn es el puntero del nuevo número */
    } while (long2!=0);

  n2[posn] = '\0';
  n2=strrev(n2, posn);
}

int main()
{
  char num1[20], num2[20];
  int base1, base2;
  printf("Numero a convertir:");
  scanf("%s", num1);
  printf("¿En qué base está ese número? ");
  scanf("%d", &base1);
  printf("¿A qué base quieres convertirlo? ");
  scanf("%d", &base2);

  cambiobase(num1, base1, num2, base2);

  printf("\n%s\n", num2);

  return 0;
}

La idea principal la saqué hace tiempo de un código escrito en otro lenguaje.
Tenemos que tener en cuenta que esta función utiliza a strutils.h (ver anterior post), aunque también podéis copiar directamente la función strrev y a compilar!!
Todo esto es debido a que el algoritmo para cambiar la base genera el número (como una cadena, pero al fin y al cabo un número) al revés, es decir el dígito de menor peso primero.

Categories: C/C++ Tags: , , , ,

Volteando cadenas

Viernes, 22 de Mayo de 2009 blakeyed Sin comentarios

En C, una de las pequeñas cosas que a veces nos hace más lentos a la hora de hacer un pequeño programa es la posibilidad de darle la vuelta a una cadena. Bien, aquí traigo un pequeño código (función y ejemplo) de strrev, que además de poder dar la vuelta a una cadena, puede manipular sólo ciertos caracteres:

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
#include <stdio.h>
#include <string.h>

char *strrev(char *str, int strl)
{
    /* Creamos punteros al principio y al final de la cadena */
    /*       C   A   R   A   C   T   E   R   5   \0 */
    /*       |                               |      */
    char *start = str, *end = str + strl - 1;
    char temp;
    /* Iteramos hasta que el principio y el fin coincidan */
    while(start < end)
        {
            /* Intercambiamos los caracteres */
            /* 1º  C A R A C T E R 5 */
            /* 2º  5 A R A C T E R C */
            /* 3º  5 R R A C T E A C */
            /* 4º  5 R E A C T R A C */
            /* 4º  5 R E T C A R A C */
            temp = *start;
            *start++ = *end;
            *end-- = temp;
        }
    return str;
}

/* Ejemplo */
int main()
{
    char cadena[50]="Una cadena de caracteres cualquiera";
    char tmp[50]="Una cadena de caracteres cualquiera";
    char *cad2=cadena;
    printf("Cadena original: %s\n", cadena);
    printf("Cadena al revés: %s\n", strrev(tmp, strlen(tmp)));
    strrev(cadena+14, 10);
    printf("Caracteres al revés: %s\n", cad2);
    return 0;
}

Esta función la encontré hace mucho tiempo navegando y me pareció muy interesante, sobre todo por cómo está hecha, creo que es de las más rápidas.

Categories: C/C++ Tags: , ,

Visita otras webs de la red