Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: samur88 en 22 Noviembre 2010, 12:58 pm



Título: Problema con Malloc y cadenas de tamaño variable.
Publicado por: samur88 en 22 Noviembre 2010, 12:58 pm
Hola. Saludos a todos.

Tengo un problema a la hora de entender malloc, el caso es que quiero un array que cada elemento almacene cadenas de dimension variable.
En principio tengo:

Código:
char nombre[2];
nombre[0] = (char *)malloc(sizeof(char));

Supuestamente esto me funciona, es decir, yo puedo usar scanf y almacenar una cadena del tamaño que yo quiera en nombre[0], pero el caso es que creo que la asignación de memoria esta mal, es decir, yo estoy reservando memoria para lo que ocupa un carácter, es decir un byte, por lo tanto no me tendría que dejar almacenar mas de un bye, al menos que este machando la memoria a partir de la posición de asignación de dicho byte, por eso quería saber si este código es correcto.
Es decir, si de esta forma yo estoy reservando memoria para una cadena de tamaño variable en nombre[0].

Un Saludo.


Título: Re: Problema con Malloc y cadenas de tamaño variable.
Publicado por: Akai en 22 Noviembre 2010, 13:18 pm
Tal como asumes, esa asignación está mal. Estás asignando en un char un puntero a char. De hecho el compilador debería darte un error como mínimo.

Para lo que tu quieres hacer, primero necesitas un puntero a puntero a char, o también visto como un vector de cadenas.

Código
  1. char **nombre;
  2. nombre= nombre=(char**)malloc(n*sizeof(char*)); //n=numero de cadenas
  3. //luego, para cada cadena:
  4. nombre[i]=(char*)malloc(n*sizeof(char)); // n= numero de caracteres en la cadena
  5.  


o

Código
  1. char nombre[tam1][tam2]
En esta opción el tamaño de la matriz de carácteres / vector de cadenas se define en tiempo de compilación.

En ambos casos, el uso sería el mismo, como si de una matriz se tratase

PD: Es posible que en el código usando malloc pueda haber alguna incorrección, hace tiempo que no lo uso.

Edit: gracias por la corrección, Eternal Idol.


Título: Re: Problema con Malloc y cadenas de tamaño variable.
Publicado por: samur88 en 22 Noviembre 2010, 13:31 pm
Muchísimas gracias por la respuesta Akai pero tengo un problema, mi idea es que yo "n" no lo conozco hasta que no inserto la cadena, necesito que se asigne el tamaño en tiempo de ejecución del programa, así que si el usuario inserta 5 caracteres la cadena tenga un tamaño de 5 bytes en la memoria.

¿Como puedo hacer eso?
Un saludo y gracias de nuevo.


Título: Re: Problema con Malloc y cadenas de tamaño variable.
Publicado por: Eternal Idol en 22 Noviembre 2010, 13:36 pm
Podes usar una variable temporal donde leer la cadena:

Código
  1. char tmp[80];
  2. fgets(tmp, sizeof(tmp), stdin);

Despues solo tenes que usar strlen para saber el tamaño (no te olvides de reservar memoria para el 0 terminador de cadena) y copiar.


PD. Al reservar los punteros a cadena se tiene que usar el sizeof de char* y no de char para obtener el tamaño.


Título: Re: Problema con Malloc y cadenas de tamaño variable.
Publicado por: samur88 en 22 Noviembre 2010, 13:39 pm
Gracias Eternal Idol pero mi problema sigue estando ahí, yo no quiero que la variable temporal sea de 80 caracteres como máximo, ya que no se cuanto se puede introducir, podrían ser mas o menos, me gustaría poder pasarle el valor de caracteres a la cadena en tiempo de ejecución.
Saludos.


Título: Re: Problema con Malloc y cadenas de tamaño variable.
Publicado por: Eternal Idol en 22 Noviembre 2010, 13:46 pm
No, no hay ningun problema, en todo caso se truncaria pero 80 es un tamaño mas que suficiente para practicamente cualquier cosa, si te parece insuficiente siempre podes reemplazar el 80 por 32768 por ejemplo.


Título: Re: Problema con Malloc y cadenas de tamaño variable.
Publicado por: samur88 en 22 Noviembre 2010, 14:08 pm
Pero si lo reemplazo por eso, ¿no estaría desperdiciando memoria en el momento de capturar la cadena en tmp?

Sigo teniendo la curiosidad de hacer ese 80, ponerle en vez de un numero una variable y sacar cuando caracteres he introducido por teclado, eso lo puedo hacer, usando los flujos o algo así?
Un saludo y muchísimas gracias.


Título: Re: Problema con Malloc y cadenas de tamaño variable.
Publicado por: Eternal Idol en 22 Noviembre 2010, 14:21 pm
Si pones el codigo en una funcion al salir de la misma todo esa memoria vuelve a estar disponible. ¿Estas tratando de entender malloc o tenes requisitos de un hardware con infima memoria?

No hay forma de saber el tamaño de la cadena ANTES de que el usuario la escriba, salvo que tambien tenga que escribir el tamaño de la misma ...


Título: Re: Problema con Malloc y cadenas de tamaño variable.
Publicado por: samur88 en 22 Noviembre 2010, 14:29 pm
Muchas gracias Eternal Idol, en realidad no quiero decir antes, si no una vez que la ha ingresado, yo es que ahora mismo no estoy muy puesto en memoria dinamica, pero podría hacerse algo asi:

Sería coger y poner un tamaño mínimo de un byte, si la cadena no entra en ese tamaño entonces con realloc se asigna un nuevo de tamaño de los mismos byte que la cadena.

Un saludo.


Título: Re: Problema con Malloc y cadenas de tamaño variable.
Publicado por: Eternal Idol en 22 Noviembre 2010, 14:36 pm
¿Que la ha ingresado en donde? Para poder ingresarla se necesita minimo el tamaño exacto de la cadena ya reservado (incluyendo el 0 terminador). ¿Como sabes si la cadena no entra? Si es tratando de ingresar los datos en esa cadena para la que reservas un caracter (el 0 terminador en realidad) usando fgets correctamente no tendras nunca nada en la cadena, usando algun metodo inseguro accederas a memoria no reservada ...


Título: Re: Problema con Malloc y cadenas de tamaño variable.
Publicado por: Garfield07 en 22 Noviembre 2010, 19:54 pm
Pseucode:

1. Pedir cadena =  char *tmp, fgets (...)
2. Calcular tamaño = strlen ()
3. Reservar memoria = malloc
4. Borrar tmp [x ejemplo metiendo paso 1 en funcion aparte....


Algo asi???


Título: Re: Problema con Malloc y cadenas de tamaño variable.
Publicado por: Eternal Idol en 22 Noviembre 2010, 22:10 pm
¿Y a char *tmp que tamaño le damos? Estamos en la misma y usando memoria dinamica dos veces para nada ...

Yo lo haria mas o menos asi:

Código
  1. void getString(char **pstr)
  2. {
  3.  char tmp[16384];
  4.  fgets(tmp, sizeof(tmp), stdin);
  5.  *pstr = (char*)malloc(strlen(tmp) + 1);
  6.  strcpy(*pstr, tmp);
  7. }

Primero reservas memoria para los punteros y despues con un bucle llamas a esta funcion pasandole la direccion de cada elemento del array de punteros a char.


Título: Re: Problema con Malloc y cadenas de tamaño variable.
Publicado por: do-while en 23 Noviembre 2010, 01:58 am
¡Buenas!

Tambien puedes asignar la memoria seguna vayas leyendo caracteres:

Código
  1. int main(int argc, char *argv[])
  2. {
  3.    char *cadenas[N_CADENAS],lector;
  4.    int i,ncaracteres;
  5.  
  6.    for(i = 0 ; i < N_CADENAS ; i++)
  7.    {
  8.        cadenas[i] = NULL;
  9.        ncaracteres = 0;
  10.  
  11.        while((lector = getchar() != '\n')
  12.        {
  13.            cadenas[i] = (char*) realloc(cadenas[i] , (ncaracteres + 2) sizeof(char));
  14.  
  15.            cadenas[ncaracteres] = lector;
  16.            cadenas[ncaracteres + 1] = '\0';
  17.  
  18.            ncaracteres++;
  19.        }
  20.    }
  21. }
  22.  

Eso si, este codigo puede dar errores si no se consigue asignar la memoria, corrige eso y listo.

¡Saludos!

PD: Es codigo lo he puesto mientras lo pensaba, asi que puede tener errores. Si los hay, no creo que sean dificiles de detectar y corregir.


Título: Re: Problema con Malloc y cadenas de tamaño variable.
Publicado por: samur88 en 25 Noviembre 2010, 01:06 am
Muchas gracias por todas las respuestas, siento no haber podido contestar antes, he estado de exámenes y he tenido problemas con el ISP de internet y por eso no lo hice antes, ya por suerte se ha arreglado todo.

Tu idea de la variable temporal la tendré muy en cuenta, realmente si pongo un numero muy grande no creo que una cadena llegue a tener mas de ese numero y luego con realloc podría disminuirla a lo que ocupa la cadena.

Una pregunta, la idea de leer carácter por carácter es mas lento que el algoritmo propuesto por Eternal Idol de la variable temporal?

Y una ultima cosa, realmente la cadena en C no se almacena hasta que se pulsa enter, ¿no hay una forma de que cuando pulse enter todo lo que este en studin o en la entrada de datos que internamente el sistema operativo administra sacar los caracteres que han sido leídos en esa entrada y con ese tamaño darle el valor a la cadena?

Un saludo y gracias de nuevo.