Archivo

Archivo para la categoría ‘C/C++’

trim(), un gran amigo (PHP, C++, C)

Miércoles, 10 de Marzo de 2010 admin Sin comentarios

A mi entender, es una de las funciones más útiles que se han inventado, como programador de PHP estoy harto de utilizarlo para filtrar información (caracteres a la derecha y a la izquierda, ya sean espacios, caracteres especiales o algún carácter que yo utilice para el control de la información).
Sabemos que el usuario final no nos va a dejar las cosas fáciles, puesto que a veces, nos llena un campo con “intros” al principio y al final; o la información, después de pasar por HTTP, lectura de un archivo XML o por otros tratamientos, tal vez tenga un retorno de carro al final; por eso, a veces es útil hacer:

1
$cadena=trim($cadena);

Pero ahora estamos en C++, bien quería postear también el código en C++, así que decidí googlear un poco para ver esto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <string>
const std::string whiteSpaces( " \f\n\r\t\v" );

void trimRight( std::string& str,
      const std::string& trimChars = whiteSpaces )
{
   std::string::size_type pos = str.find_last_not_of( trimChars );
   str.erase( pos + 1 );
}

void trimLeft( std::string& str,
      const std::string& trimChars = whiteSpaces )
{
   std::string::size_type pos = str.find_first_not_of( trimChars );
   str.erase( 0, pos );
}

void trim( std::string& str, const std::string& trimChars = whiteSpaces )
{
   trimRight( str, trimChars );
   trimLeft( str, trimChars );
}

Con esto podemos jugar con nuestros textos…

Ahora vamos al caso de C, muchos se siguen preguntando… pero si C es un lenguaje muy antiguo, ¿aún se sigue usando? Pues sí ! Aunque muchas cosas sean horribles de programar en C, a pelo, se sigue usando, y aún le queda mucha vida a este lenguaje. Por eso, veremos dos funciones trim() especiales para C:

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

char *trim(char *s)
{
  char *start = s;

  /* Nos comemos los espacios al inicio */
  while(*start && isspace(*start))
    ++start;

  char *i = start;
  char *end = start;

  /* Nos comemos los espacios al final */
  while(*i)
  {
    if( !isspace(*(i++)) )
      end = i;
  }

  /* Escribimos el terminados */
  *end = 0;

  return start;
}

char *trim2(char *s, const char *trimChars)
{
  char *start = s;

  /* Nos comemos los caracteres al principio */
  while(*start && strpbrk((const char*)start, trimChars)==start)
    ++start;

  char *i = start;
  char *end = start;

  /* Nos comemos los caracteres al final */
  while(*i)
  {
    if( strpbrk(i++, trimChars)!=i-1 )
      end = i;
  }

  /* Coloramos el perminador */
  *end = 0;

  return start;
}

int main()
{
  char mi_cadena[30]="\f\n Cadena; \tSucia \n\t ;";
  printf("Mi cadena inicialmente: \"%s\"\n", mi_cadena);
  printf("Mi cadena tras trim(): \"%s\"\n", trim(mi_cadena));
  printf("Mi cadena tras trim2(): \"%s\"\n", trim2(mi_cadena,";\f\n\t"));
}

En C también podremos tener nuestro trimleft y nuestro trimright y creo que es fácil sacarlo desde esta función general, ya que *start se mueve indicando el principio de la cadena, y con end, y es ese movimiento (que aunque perdemos algo de memoria) el que hace que se recorte la cadena; además, como buena función de C, perdemos la cadena que inicialmente teníamos.

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

Generador de números primos en C

Martes, 15 de Diciembre de 2009 admin Sin 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

Capicúa recursivo en C

Viernes, 11 de Diciembre de 2009 admin Sin comentarios
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
#include <stdio.h>
#include <stdlib.h>

int alreves(int n, int digitos)
{
  int resto, cocie;

  if (n<10)     // Si tenemos un número de dígitos menor a 2, devolvemos n
    return n;
  else
    {
      resto = n % 10;
      cocie = n / 10;
      return resto*digitos + alreves(cocie, digitos/10);
    }
}

int main()
{
  int num, rev;
  int digitos = 1;
  int tmp;
  printf("Dame un numero: ");
  scanf("%d", &num);
  // Hacemos un número 10^(numero de cifras-1) con esto alreves determinará el
  // número de cifras que tiene el número dado.
  tmp =num;
  while (tmp>=10)
    {
      tmp=tmp/10;
      digitos=digitos*10;
    }

  rev = alreves(num, digitos);

  // Capicúa o no ?
  if (rev==num)
    printf("\nEs capicua");
  else
    printf("\nNO es capicua");

  return 0;
}

Una posible solución al cálculo de números capicúa en C. La verdad es que tenemos muchas soluciones a este problema, ésta es una de ellas. El tema es, ¿acarreamos el número de cifras? podemos calcularlo a cada recursión (al principio de alreves()), o en lugar de este número tan raro (1 para 1 cifra, 10 para 2 cifras, 100 para 3 cifras…), poner un número del tipo 1, 2, 3… éste sería capaz de dar la vuelta a número más grandes.

En fin, sólo es una de las 10.000 posibles soluciones al problema :)

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

Tuberías con nombre para comunicación entre procesos

Domingo, 19 de Julio de 2009 blakeyed Sin comentarios

Las tuberías con nombre son un método de comunicación FIFO entre procesos (también se les llama fifos). FIFO son las siglas de First In First Out, es decir, el primero que llega es que primero que se marcha, como en una cola, el primero que llega es el que antes termina.

Observad lo que hacen las macros depura_int y depura_string, nos darán el número de línea y el archivo donde están, así como el nombre de la variable y el valor que tiene en ese momento.

Normalmente las tuberías son anónimas, aunque el hecho de tenerlas con un nombre en nuestro sistema de ficheros puede sernos de gran utilidad. Como ejemplo, podemos verlo en funcionamiento en la siguiente imagen:

Cómo hacer una pipe con nombre en 1 minuto

Cómo hacer una pipe con nombre en 1 minuto

Primero vemos el terminal de abajo, en el que se ejecuta lo siguiente:

1
2
$ mkfifo prueba
$ cat prueba

Seguidamente en el otro terminal se escribe lo siguiente:

1
$ echo "Esto es una prueba" > prueba

Automáticamente el texto “Esto es una prueba” aparece en el primer terminal. ¡Hemos logrado enviar un mensaje!

De la misma forma podemos programar aplicaciones que utilicen estas características de forma muy fácil en casi cualquier lenguaje de programación, para los ejemplos utilizaré C. Debemos hacer dos programas, uno que escriba en la tubería (pipe) y otro que lea de ella. Empezamos por pipewrite.c:

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
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

int main()
{
  FILE *mipipe;
  char buffer[128];
  int i=0;

  if (mkfifo("pipetest", S_IWUSR |  /* El usuario puede escribir */
                 S_IRUSR |  /* El usuario puede leer */
                 S_IRGRP |  /* El grupo puede leer */
                     S_IROTH    /* Otros pueden leer */
         )!=0)
    printf ("Hubo un problema al crear la pipe\n");

  mipipe=fopen("pipetest", "w"); /* Lo abrimos como un fichero normal y corriente */

  /* Con esta línea leemos hasta que se cierre la tubería por el otro */

  while (i<10)
    {
      sprintf(buffer, "CADENA ENVIADA Número: %i\n", i+1);
      fputs(buffer, mipipe);
      i++;
    }

  fclose(mipipe);       /* Cerramos la tubería por aquí también */

Y ahora pipecilla.c (o el programa que leerá la pipe):

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
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

int main()
{
  FILE *mipipe;
  char buffer[128];
  if (mkfifo("pipetest", S_IWUSR |  /* El usuario puede escribir */
                 S_IRUSR |  /* El usuario puede leer */
                 S_IRGRP |  /* El grupo puede leer */
                     S_IROTH    /* Otros pueden leer */
         )!=0)
    printf ("Hubo un problema al crear la pipe\n");

  mipipe=fopen("pipetest", "r"); /* Lo abrimos como un fichero normal y corriente */

  /* Con esta línea leemos hasta que se cierre la tubería por el otro */
  while (!feof(mipipe))      
    {
      if (fgets(buffer, 128, mipipe))
      printf ("RECIBIDO: %s", buffer);
    }

  fclose(mipipe);       /* Cerramos la tubería por aquí también */
}

Ahora compilamos y ejecutamos en terminales diferentes de nuevo:
Probando pipes
En el terminal de pipewrite.c, al ejecutar el programa da un mensaje de error, es porque la pipe ya existe (se creó en el programa anterior).

Esta forma de comunicación es unidireccional, puede ser últil por ejemplo para publicar el estado de un programa (un reproductor de audio podría publicar la canción que está sonando como en xmms-infopipe), o para modificar el comportamiento de un software mientras éste está en ejecución. Pero si queremos que nuestras aplicaciones dialoguen (en full-duplex), debemos tener dos pipes simultáneas, en ese caso, la aplicación 1, por ejemplo deberá leer en la tubería 1 y escribir en la tubería 2; y la aplicación 2, deberá escribir en la tubería 1 y leer en la tubería 2.

Controlar señales

Viernes, 5 de Junio de 2009 admin Sin comentarios

A veces, se nos presenta la necesidad de modificar el comportamiento de nuestro programa por ejemplo cuando el usuario pulse Control+C, o cuando terminemos nuestra aplicación, o cuando… dividamos por 0, o más cosas… podemos ver un listado de las diferentes señales con:

man 7 signal

Podemos utilizar para probar este programa (signals.c):

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
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void salir(int recib);
void alarma(int que);
int tmp=0;
int divi=5;
int main()
{
    signal(SIGINT, salir);  /* Control+C */
    signal(SIGKILL, salir); /* kill */
    signal(SIGFPE, salir);  /* división por 0 */
    signal(SIGALRM, alarma);    /* alarma */
    signal(SIGUSR1, alarma);    /* definido por el usuario */
    int numero=4;
    while (1)
        {
            usleep(1000);       /* Le damos un respiro a la CPU mientras estamos en el bucle */
            tmp++;
            if (tmp%1000==0)
            {
                tmp=tmp/divi;
                printf("tmp = %d\n", tmp);
            }
        }
}
void salir(int recib)
{
    printf("Salgo porque ");
    switch (recib)
        {
        case SIGINT: printf("has pulsado Control+C...\n"); break;
        case SIGTERM: printf("alguien me ha terminado\n"); break;
        case SIGFPE: printf("he dividido por 0 y eso no se puede hacer\n"); break;
        default: printf("yo que sé !!");
        }
    printf("Sólo quería decirte que me quedé contando por %d\n\n", tmp);
    exit(0);
}
void alarma(int que)
{
    switch (que)
        {
        case SIGALRM:
            printf("Voy contando por %d\n\nDivi vale %d\n", tmp, divi); break;
        case SIGUSR1:
            divi--; break;
        }
}

Para aprovechar su funcionalidad, tenemos que ejecutarlo desde un terminal, y abrir otro terminal al lado, para ir ejecutando ciertas cosas:

killall signals (o el nombre que le hayáis dado al ejecutable)
killall -14 signals (alarma)
killall -SIGUSR1 signals (varias veces)

Observaremos que con “killall signals” cerraremos directamente, igual que con Control+C, pero antes de salir del programa, nos dará cierta información (función salir); también veremos que con “killall -14 signals” veremos información en pantalla (función alarma), y que con killall -SIGUSR1 signals” veremos que tmp se va dividiendo por un número menor cada vez que la pulsamos, y cuando lo hemos hecho varias veces, dividirá por 0 (y también capturaremos ese error).

Esto puede servir, por ejemplo, por si estamos grabando un informe de lo que estamos haciendo y se cancela la ejecución, pero queremos cerrar el archivo, queremos mostrar un resumen, capturar errores, ignorar las señales… o comunicarnos con otras aplicaciones de forma sencilla

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

Intercambiar valores

Jueves, 4 de Junio de 2009 admin Sin comentarios

Cuando queremos hacer que una variable a sea igual a una variable b y viceversa (intercambiar los valores), lo primero que se viene a la mente, es utilizar una variable auxiliar, como en este ejemplo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
void intercambia(int *x, int *y);
int main()
{
    int a=50;
    int b=90;
    printf("a=%d t b=%dn", a, b);
    intercambia(&a, &b);
    printf("a=%d t b=%dn", a, b);
}
void intercambia(int *x, int *y)
{
    int tmp;
    tmp=*x;
    *x=*y;
    *y=tmp;
}

Aunque puede que queramos (o que nos pidan) hacerlo sin variable temporal, podemos hacer un intercambiador con sumas y restas:

1
2
3
4
5
6
void intercambia2(int *x, int *y)
{
    *x=*x+*y;           /* x=x+y */
    *y=*x-*y;           /* y=x-y */
    *x=*x-*y;           /* x=x-y */
}

Y con las propiedades de la operación XOR también podemos jugar:

1
2
3
4
5
6
void intercambia3(int *x, int *y)
{
    *x ^= *y;           /* x = x xor y */
    *y ^= *x;           /* y = y xor x */
    *x ^= *y;           /* x = x xor y */
}

Pero lo bueno de estos dos últimos métodos es que los podemos utilizar desde macros de preprocesador, y con eso nuestro código se ejecutará mucho más rápido:

1
2
3
4
5
6
7
8
9
#define interc(x,y) x=x+y; y=x-y; x=x-y;
int main()
{
    int a=-50;
    int b=40;
    printf("a=%d t b=%dn", a, b); /* a=-50 b=40 */
    interc(a, b);
    printf("a=%d t b=%dn", a, b); /* a=40 b=-50 */
}

Para ver lo rápido que se ejecuta, he hecho el programa intercambiando continuamente en un bucle for de unos 300000000 (trescientos millones) de iteraciones lo siguiente:

Para la macro de preprocesador interc(a,b),

gaspy@XiKiTiN ~/proyectos/poesiabinaria $ time ./interc
a=-50 b=40
a=-50 b=40

real 0m8.027s
user 0m7.461s
sys 0m0.022s

Para intercambia(a,b) (con variable auxiliar):

gaspy@XiKiTiN ~/proyectos/poesiabinaria $ time ./intvaux
a=-50 b=40
a=-50 b=40

real 0m8.691s
user 0m7.058s
sys 0m0.022s

Para intercambia2(a,b), con sumas y restas:

gaspy@XiKiTiN ~/proyectos/poesiabinaria $ time ./intsyr
a=-50 b=40
a=-50 b=40

real 0m12.331s
user 0m10.508s
sys 0m0.024s

Para intercambia3(a,b) con xor:

gaspy@XiKiTiN ~/proyectos/poesiabinaria $ time ./intxor
a=-50 b=40
a=-50 b=40

real 0m11.882s
user 0m10.516s
sys 0m0.031s

Por lo tanto vemos, que el método de la variable auxiliar es bastante rápido, mucho más que haciendo sumas y restas y xor (por lo tanto estos métodos no sirven de mucho, sobre todo ahora, que la memoria es barata), aunque, con las sumas y restas nos acercamos en tiempo al método de la variable auxiliar cuando lo hacemos desde una macro.

Ahora bien, es una cosa un poco sucia, pero es un buen experimento: crear una variable global c, y una macro que haga el intercambio ayudándose de la variable auxiliar c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#define interca(x,y) c=x; x=y; y=c;
int c;
int main()
{
    int a=-50;
    int b=40;
    long i;
    printf("a=%d t b=%dn", a, b); /* a=-50 b=40 */
    for (i=0; i<300000000; i++)
        {
            interca(a, b);
        }
    printf("a=%d t b=%dn", a, b); /* a=-50 b=40 */
}

Con éste método, obtenemos estos tiempos:

gaspy@XiKiTiN ~/proyectos/poesiabinaria $ time ./inter
a=-50 b=40
a=-50 b=40

real 0m3.087s
user 0m2.901s
sys 0m0.005s

Bastante menos :) De todas formas estos tiempos son aproximados.

Categories: C/C++ Tags: , ,

Decimal a Binario (y negativos en Complemento a 2)

Martes, 2 de Junio de 2009 admin 4 comentarios

Aquí traigo un fragmento de código que nos puede ayudar bastante a la hora de hacer cambios de base de decimal a binario, sobre todo porque para manejarnos con los números negativos utilizamos el Complemento a dos.

En principio, antes de hacer esta función miré un poco el blog Static Zero, y luego me decidí simplificar un poco el código. Así ha quedado:

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
int *decToBin(int decimal, int nBits, int binary[]) {
    int i;

    int flag = 0;
    /* Si es un número negativo, lo hacemos positivo y le restamos 1(*), */
    /* además activamos el flag para saber que es negativo */

    /* (*) El complemento a 2 es igual que el complemento a 1, que es cambiar */
    /* 1->0, 0->1, y luego sumando 1 en binario. Aquí restamos 1 en decimal y */
    /* luego pasamos a binario. */
    if (decimal < 0)
        {
            flag = 1;
            decimal = -decimal-1;
        }

    /* Pasamos a binario, atendiendo a lo que vale flag, en lugar de añadir (decimal%2) */
    /* como es normal, le hacemos un XOR con flag, vemos la tabla de verdad de XOR */
    /* |    A    (xor)   B       =   X   |  */
    /* |     0      |        0       |   0   |  */
    /* |     0      |        1       |   1   |  */
    /* |     1      |        0       |   1   |  */
    /* |     1      |        1       |   0   |  */
    /* ------------------------------   */
    /* Por tanto, cuando flag vale 0, al encontrar un 0, pondremos un 0, y al encontrar un 1, ponemos un 1 */
    /*           Pero cuando flag vale 1, al encontrar un 0, pondremos un 1, y al encontrar un 1, ponemos un 0 */
    while (decimal > 0)
        {
            binary[--nBits] = flag^(decimal%2);
            decimal/=2;
        }

    /* Con esto terminamos de llenar el array, con 0 a la izquierda si es un número positivo */
    /* y con 1s si es un número negativo */
    while (nBits>0)
        binary[--nBits] = flag;
   
    /* Devolvemos el array */
    return binary;
}

Para descargar este código y un pequeño programa de prueba:
Pasar de decimal a binario (Negativos en complemento a 2)

Depurando…

Sábado, 30 de Mayo de 2009 blakeyed Sin comentarios

A veces es muy útil saber el contenido de una variable en mitad de ejecución del programa, pero cuando queremos compilar la versión definitiva, eliminar todas las trazas de depuración de una vez, aunque cuando estemos desarrollando, es interesante volverlas a tener.

Podemos hacerlo de forma sencilla con algunas macros de preprocesador de C; podemos poner un pequeño fragmento de código al empezar cada programa, y lo mejor de todo es que la versión definitiva seguirá ocupando lo mismo, ya que si desactivamos la depuración es como si en el código final no se escribieran las trazas.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include

#define depuracion

#ifdef depuracion
#define depura_int(variable) printf("%s: Linea: %d (Variable \"%s\" vale: %d)\n", __FILE__, __LINE__, #variable, variable);
#define depura_string(variable) printf("%s: Linea: %d (Variable \"%s\" vale: \"%s\")\n", __FILE__, __LINE__, #variable, variable);
#else
#define depura_int(variable)
#define depura_string(variable)
#endif
int main()
{

int numero=99;
char strtest[20]="CADENA DE PRUEBA";

depura_int(numero)
depura_string(strtest)

return 0;
}

Observad lo que hacen las macros depura_int y depura_string, nos darán el número de línea y el archivo donde están, así como el nombre de la variable y el valor que tiene en ese momento.

Cuando no queramos depurar comentamos la línea que contiene #define depuracion y listo.

Colores y posicionamiento en terminales Linux (como conio.h en DOS)

Viernes, 29 de Mayo de 2009 blakeyed Sin comentarios

A veces, es un poco difícil que alguien que sólo conoce conio.h se pase a Linux, más que nada, porque se puede utilizar ncurses, pero hay que cambiar un poco de mentalidad para poder trabajar con la nueva biblioteca.

Por eso, hace unos meses creé unas cuantas funciones que se podían utilizar para ir reemplazándolas poco a poco. Funcionan de forma muy parecida a conio.h (en los colores). Se basan en códigos ANSI, y las podemos utilizar para cualquier programa rápido en que necesitemos utilizar colores en terminal. ncurses es muy potente y si vamos a complicarnos un poco más la vida, mejor utilizar esta segunda.

Cuando estuve implementando estas funciones, tuve un problema, a la hora de leer información del terminal sin mostrarla por pantalla, me basé en: wsize.c de Stephen J. Friedl. También podéis encontrar información sobre los códigos ANSI aquí.

He incluído la opción subrayado (UNDERLINE) y un par de funciones que nos calculan las dimensiones de la pantalla (ya que los terminales pueden ser redimensionados y ser enormes).

Descargar stermp - Simple Terminal Play (stermp.c, stermp.h)

Os pongo aquí el código del ejemplo (conio.c)

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

int main()
{
    int pp, fn;
    clrscr();
    for (pp=BLACK; pp<=WHITE; pp++)
        {
            gotoxy(5, 20+pp);
            for (fn=BLACK; fn<DARKGRAY; fn++)
                {
                    textcolor(pp);
                    textbackground(fn);
                    printf("COLOR\t");
                }
        }
    restore_color();
    textcolor(RED+UNDERLINE);
    gotoxy(51, 5);
    printf("Posición X: %d\n", wherex());
    printf("Posición Y: %d\n", wherey());
    printf("Pantalla %dx%d", screenwidth(), screenheight());

}

Funciones que devuelven arrays

Jueves, 28 de Mayo de 2009 blakeyed 2 comentarios

Al principio, cuando empezaba a programar, yo me quejaba mucho de esa tonta manía de C que no me dejaba devolver arrays como resultado de una función.

Aunque al final, devolver arrays es una tontería, gasta memoria, gasta tiempo y termina siendo más fácil solucionarlo todo con un puntero.

Pero bueno, si realmente queremos devolver un array, siempre podemos meterlo dentro de un registro. Probando con una cadena de caracteres:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <string.h>

typedef struct
{
    char cadena[1000];
} t_array;

t_array devuelvo()
{
    t_array otroarr;
    printf("\nDirección de cadena: %X\nCadena: %s\n", &otroarr, otroarr.cadena);
    strcpy(otroarr.cadena, "ESTE STRING APARECE VARIAS VECES EN EL VOLCADO DE MEMORIA");
    printf("\nDirección de cadena: %X\nCadena: %s\n", &otroarr, otroarr.cadena);
    return otroarr;
}

int main()
{
    t_array array;
    array=devuelvo(&mem);
    printf("\nDirección de cadena: %X\nCadena: %s\n", &array, array.cadena);
}
Categories: C/C++ Tags: , ,
Easy AdSense by Unreal