Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Ghalad en 24 Mayo 2010, 18:28 pm



Título: reservar memoria para punteros en C
Publicado por: Ghalad en 24 Mayo 2010, 18:28 pm
Hola a todos, tengo una duda sobre este tema. Entiendo que si declaro:

char *cadena;
cadena = (char*)malloc( (sizeof(char)*4) + 1);

estoy declarando un puntero a un string de 5 posiciones, pj: "HOLA"+'\0'.
Entonces tengo 2 preguntas:

1ro) que diferencia hay entre:
    (char*)malloc(sizeof(char)*5);
    (char*)malloc(sizeof(char*)*5);

2do) si lo que quiero es tener una lista de strings dinamica y declaro:

char **lista;

como declaro correctamente memoria para los distintos strings que quiera agregar a la lista? supongamos que los strings, en un determinado momento, son "hola1", "hola2", "hola3"


Título: Re: reservar memoria para punteros en C
Publicado por: Eternal Idol en 24 Mayo 2010, 19:24 pm
Si, entendiste bien hasta ahi.

1)(char*)malloc(sizeof(char)*5);
Reserva memoria para 5 caracteres.

(char*)malloc(sizeof(char*)*5);
Reserva memoria para 5 PUNTEROS a caracteres (pero deberias hacer el casting a char **).

En realidad siempre reserva memoria simplemente, pero desde un punto de vista logico la diferencia seria esa con el casting correcto, en una PC con un S.O. de 32 bits, char = 1 byte, char *(y cualquier otro puntero) 4 bytes.

2) Reservas primero la memoria para los punteros a cadena y despues la memoria para las cadenas mismas.

Código
  1. //reservar
  2. char **lista = (char**)malloc(sizeof(char*) * 3);
  3. for (int x = 0; x < 3; x++)
  4. {
  5.  lista[x] = (char*)malloc(sizeof(char) * 5);
  6. }
  7. //usar
  8. //liberar
  9. for (int x = 0; x < 3; x++)
  10. {
  11.  free(lista[x]);
  12. }
  13. free(lista);


Título: Re: reservar memoria para punteros en C
Publicado por: Ghalad en 24 Mayo 2010, 21:03 pm
ahhhh, bueno entonces dado mi programa...para generar la lista de strings seria correcto hacer:

void fnc(char** lista){
    lista = (char**)malloc( sizeof(char*)*5 );
    for(int i = 0; i < 5; i++){
        *lista = (char*)malloc( sizeof(char)*10);
        strcpy(*list, cadena); //cadena es un string que se genera dentro de la misma funcion, solo que no tengo ganas de poner la funcion completa porque interviene un base de datos, pero es un string.
        }
}


int main(){

char** lista, **ptr;

fnc(lista);

ptr = lista; //para no perder el puntero

while(*ptr != NULL)
{
    while(**ptr != '\0')
        printf("%s\n", *ptr++);
    ptr++;
}
}//fin del main


Título: Re: reservar memoria para punteros en C
Publicado por: h0oke en 24 Mayo 2010, 21:19 pm
Puedes utilizar GesHi por favor?


Título: Re: reservar memoria para punteros en C
Publicado por: Ghalad en 24 Mayo 2010, 21:25 pm
Código
  1. void fnc(char** lista){
  2.    lista = (char**)malloc( sizeof(char*)*5 );
  3.    for(int i = 0; i < 5; i++){
  4.        *lista = (char*)malloc( sizeof(char)*10);
  5.        strcpy(*list, cadena); //cadena es un string que se genera dentro de la misma funcion, solo que no tengo ganas de poner la funcion completa porque interviene un base de datos, pero es un string.
  6.        }
  7. }
  8.  
  9.  
  10. int main(){
  11.  
  12. char** lista, **ptr;
  13.  
  14. fnc(lista);
  15.  
  16. ptr = lista; //para no perder el puntero
  17.  
  18. while(*ptr != NULL)
  19. {
  20.    while(**ptr != '\0')
  21.        printf("%s\n", *ptr++);
  22.    ptr++;
  23. }
  24. }//fin del main

asi? no tengo idea de como se usa
igual creo que camulle en los while para recorrer la lista


Título: Re: reservar memoria para punteros en C
Publicado por: Eternal Idol en 24 Mayo 2010, 21:39 pm
Esta mal la inicializacion ... siempre accedes a lista[0], mira el ejemplo que deje. El bucle esta mal del todo, primero y principal para poder usarlo tendrias que reservar un puntero mas y asignarle como valor 0; ademas de pasar la variable lista por referencia (la asignacion que haces ahora mismo en fnc es local, al volvera main lista sigue teniendo el mismo valor que antes de llamar a fnc).

Código
  1. while(*ptr != '\0')
  2.        printf("%s\n", *ptr++);


Título: Re: reservar memoria para punteros en C
Publicado por: Ghalad en 24 Mayo 2010, 21:52 pm
Si a la funcion le paso una referencia a lista, el prototipo no seria
void fnc(char*** lista); ????

entonces...
quedamos de acuerdo en que
Código
  1. char** lista;
  2. lista = (char**)malloc( sizeof(char*)*5); // reservo espacio para 5 strings
  3. lista = (char*)malloc( sizeof(char)*10); // reservo 10 bytes para 1 de los 5 strings
  4.  

ahora, para copiar 1 cadena, es corecto?:
Código
  1. strcpy(lista[i], "mi cadena");

pensa que todo el tema de asignacion de memoria y strings se hace dentro de la funcion, no en el main.


Título: Re: reservar memoria para punteros en C
Publicado por: Eternal Idol en 25 Mayo 2010, 00:49 am
Si a la funcion le paso una referencia a lista, el prototipo no seria
void fnc(char*** lista); ????

Si, ahora mismo si inicializas lista a 0 y depuras vas a ver que lista sigue siendo 0.

entonces...
quedamos de acuerdo en que
Código
  1. char** lista;
  2. lista = (char**)malloc( sizeof(char*)*5); // reservo espacio para 5 strings
  3. lista = (char*)malloc( sizeof(char)*10); // reservo 10 bytes para 1 de los 5 strings
  4.  

Si.

ahora, para copiar 1 cadena, es corecto?:
Código
  1. strcpy(lista[i], "mi cadena");

Tambien.

pensa que todo el tema de asignacion de memoria y strings se hace dentro de la funcion, no en el main.

Si, ya lo hice funcionar tanto en C (char*** como en C++ **&).


Título: Re: reservar memoria para punteros en C
Publicado por: nicolas_cof en 25 Mayo 2010, 01:25 am
Yo te recomendaria mas el uso de la funcion strncpy() que strcpy()

http://www.cplusplus.com/reference/clibrary/cstring/strncpy/
http://c.conclase.net/librerias/index.php?ansifun=strncpy

Salu10.


Título: Re: reservar memoria para punteros en C
Publicado por: Ghalad en 29 Mayo 2010, 18:42 pm
mm algo me funcionamal aver:

Código
  1. void obtenerLista(char ***lista)
  2. {
  3.     char buf[50];
  4.     *lista = (char**)malloc(sizeof(char*)*5);
  5.     for(int i=0; i<5; i++)
  6.     {
  7.             printf("Ingresa cadena: ");
  8.             fgets(buf, 50, stdin);
  9.             *lista[i]= (char*)malloc(sizeof(char)*strlen(buf));
  10.             strcpy(*lista[i], buf);
  11.     }
  12. }

Código
  1. int main(){
  2.  
  3.    char **lista;
  4.  
  5.    obtenerLista(&lista);
  6.  
  7.    for(int i =0; i<5; i++){
  8.        printf("grupo %d: %s", i, lista[i]);
  9.    }
  10.    for(int i=0; i<5; i++){
  11.            free(lista[i]);
  12.            }
  13.    free(lista);
  14.    retunr 0;
  15. }

lo que quiero es una lista de strings, y como nose cuantos estoy le voy a poner a la lista estaria bueno, en vez de usar malloc(sizeof(char*)*5), usar realloc. Pero bueno si funciona con malloc despues se cambia.

que esta mal de ese codigo?


Título: Re: reservar memoria para punteros en C
Publicado por: Eternal Idol en 29 Mayo 2010, 20:14 pm
Vos queres acceder a:
Código:
lista[0][i]

Y estas accediendo a:
Código:
lista[i][0]

Podes hacerlo como muestro arriba de todo o asi:
Código:
(*lista)[i]


Título: Re: reservar memoria para punteros en C
Publicado por: Ghalad en 30 Mayo 2010, 16:43 pm
estoy haciendo una prueba y calculo que esta vez hice bien el tema de la lista pero hay algo que me esta fallando en el programa y no me doy cuenta que es, porque al finalizar me salta un mensaje del visual studio preguntando si quiero debuggearlo. A ver que me decin ustedes.
Código
  1. char** obtenerLista(int *contador)
  2. {
  3.       int cont = 0;
  4.       char buf[50], **lista;
  5.  
  6.       for(int i = 0; i < 10; i++)
  7.       {
  8.               printf("Ingresa cadena: ");
  9.               fgets(buf, 50, stdin);
  10.               buf[strlen(buf)-1] = '\0';
  11.  
  12.               if(strlen(buf) > 0){
  13.                   lista = (char**)realloc(lista, sizeof(char*));
  14.                   lista[cont]= (char*)malloc( (sizeof(char)*strlen(buf))+1);
  15.                   strcpy(lista[cont], buf);
  16.                    ++cont;
  17.               }
  18.       }
  19.       *contador = cont;
  20.       return lista;
  21. }

Código
  1. int main(){
  2. char **lista;
  3.    int contador;
  4.  
  5.    lista = obtenerLista(&contador);
  6.  
  7.    for(int i =0; i < contador; i++){
  8.        printf("grupo %d: %s\n", i, lista[i]);
  9.        }
  10.  
  11.  
  12.  
  13.    for(int i=0; i<contador; i++){
  14.            free(lista[i]);
  15.            }
  16.    free(lista);
  17.  
  18.    system("pause");
  19.    return 0;
  20. }


Título: Re: reservar memoria para punteros en C
Publicado por: Eternal Idol en 30 Mayo 2010, 17:20 pm
lista = (char**)realloc(lista, sizeof(char*));

lista es un puntero indefinido la primera vez que se llama a realloc (si lo inicializas a 0 es otra cosa) y ademas siempre reservas la misma cantidad de memoria (un puntero).


Título: Re: reservar memoria para punteros en C
Publicado por: Ghalad en 30 Mayo 2010, 17:37 pm
claro porque la idea es que, si hay una nue3va cadena a agregar se reserve memoria para un nuevo puntero a string y despues se reserve memoria para ese string. Segun entendi si el puntero no tienen memoria asiganada el realloc funciona como un malloc. Y que decis que lo tengo que inicializar con NULL a lista?


Título: Re: reservar memoria para punteros en C
Publicado por: Eternal Idol en 30 Mayo 2010, 17:41 pm
http://www.cplusplus.com/reference/clibrary/cstdlib/realloc/

"ptr
    Pointer to a memory block previously allocated with malloc, calloc or realloc to be reallocated.
    If this is NULL, a new block is allocated and a pointer to it is returned by the function."

Ademas tendras que calcular correctamente el tamaño para ir agregando cada vez un elemento mas ...


Título: Re: reservar memoria para punteros en C
Publicado por: Ghalad en 30 Mayo 2010, 18:19 pm
es que no hay que hacer calculos, es sencillo a vos te van a venir en varios strings, nose cuantos y lo que quiero hacer es: si me viene un string, reservo memoria para el puntero al string y reservo memoria para el string en si. Entonces no entiendo cual es el problema.

Código
  1.  lista = (char**)realloc(lista, sizeof(char*));
se supone que con eso cada vez que lo invoque genero una posicion mas de la lista de punteros


que tengo que hacer para que funcioneeeeeeeeee????? jajajja


Título: Re: reservar memoria para punteros en C
Publicado por: Eternal Idol en 30 Mayo 2010, 19:25 pm
Entonces el problema es que no entendes como funciona realloc, ya te deje el link antes:

"The size of the memory block pointed to by the ptr parameter is changed to the size bytes, expanding or reducing the amount of memory available in the block.
...
size
    New size for the memory block, in bytes.
    If it is 0 and ptr points to an existing block of memory, the memory block pointed by ptr is deallocated and a NULL pointer is returned."

Si llamas a realloc con el mismo tamaño al final de cuentas no estas haciendo nada logico, siempre reservas memoria para UN puntero en este caso, el segundo parametro de realloc es el tamaño TOTAL y no el tamaño a "agregar" por decirlo de algun modo.


Título: Re: reservar memoria para punteros en C
Publicado por: Ghalad en 30 Mayo 2010, 19:47 pm
ahhh yo crei que vos le pasabas cuanto querias agrandar el bloque de memoria, entonces lo correcto seria algo asi:
Código
  1. char** obtenerLista(int *contador)
  2. {
  3.       int cont = 0;
  4.       char buf[50], **lista = NULL;
  5.  
  6.       for(int i = 0; i < 10; i++)
  7.       {
  8.               printf("Ingresa cadena: ");
  9.               fgets(buf, 50, stdin);
  10.               buf[strlen(buf)-1] = '\0';
  11.  
  12.               if(strlen(buf) > 0){
  13.                   ++cont;
  14.                   lista = (char**)realloc(lista, sizeof(char*)*cont);
  15.                   if(lista == NULL) abort();
  16.                   lista[cont]= (char*)malloc( (sizeof(char)*strlen(buf))+1);
  17.                   if(lista[cont]==NULL) abort();
  18.                   strcpy(lista[cont], buf);
  19.               }
  20.       }
  21.       *contador = cont;
  22.       return lista;
  23. }

De esta forma estaria diciendo que el puntero se agrande sizeof(char*) cada vez que quiero agregar un nuevo string?

Código
  1. char** obtenerLista(int *contador)
  2. {
  3.       int cont = 0;
  4.       char buf[50], **lista = NULL;
  5.  
  6.       for(int i = 0; i < 10; i++)
  7.       {
  8.               printf("Ingresa cadena: ");
  9.               fgets(buf, 50, stdin);
  10.               buf[strlen(buf)-1] = '\0';
  11.  
  12.               if(strlen(buf) > 0){
  13.                   ++cont;
  14.                   lista = (char**)realloc(lista, sizeof(char*)*cont);
  15.                   if(lista == NULL) abort();
  16.                   lista[cont-1]= (char*)malloc( (sizeof(char)*strlen(buf))+1);
  17.                   if(lista[cont-1]==NULL) abort();
  18.                   strcpy(lista[cont-1], buf);
  19.               }
  20.       }
  21.       *contador = cont;
  22.       return lista;
  23. }
con este codigo me funciones de 10! pero es correcto o e n que la estoy pifiando?


Título: Re: reservar memoria para punteros en C
Publicado por: Eternal Idol en 30 Mayo 2010, 19:51 pm
Si, pero cont arranca de 0 asi que:
Código:
lista = (char**)realloc(lista, sizeof(char*) * (cont+ 1));


Título: Re: reservar memoria para punteros en C
Publicado por: Ghalad en 30 Mayo 2010, 19:54 pm
ahi le reste 1, funciona bien pero esta bien hecho el codigo? no estoy desperdiciando memoria en algun lado?


Título: Re: reservar memoria para punteros en C
Publicado por: 08l00D en 30 Mayo 2010, 19:55 pm
Si, pero cont arranca de 0 asi que:
Código:
lista = (char**)realloc(lista, sizeof(char*) * (cont+ 1));
Pero si lo incrementa previamente con "++count;" una linea antes...


@Ghalad Lo que no entiendo es que decis que es en C, usas funciones propias de la libreria de C, manejas las cadenas como se haria en C, y sin embargo hay varias partes de codigo que son propias de C++, no me parece muy logico pero bue..


Título: Re: reservar memoria para punteros en C
Publicado por: Ghalad en 30 Mayo 2010, 19:59 pm
Si, el codigo tiene que ser enteramente en C ansi pero me es mas facil para mostrarselo a ustedes en c++.


Título: Re: reservar memoria para punteros en C
Publicado por: Eternal Idol en 30 Mayo 2010, 20:52 pm
Pero si lo incrementa previamente con "++count;" una linea antes...

Estaba viendo el codigo original donde no lo hacia  ;D


Título: Re: reservar memoria para punteros en C
Publicado por: Ghalad en 1 Junio 2010, 20:54 pm
Te tengo otra pregunta, mi programa recive de un servidor una estructura compuesta por 4 char* de longitud (los primeros 3) menor a 512 bytes y la 4ta de tamaño variable entre 1 y nose.... 9999999..muchos bytes, depende de la persona que haya cargado la informacion en esa estructura, no importa. Y como ultima transferencia recibe un ".". El hecho es que mi programa hace un recv, un malloc y un strcpy para el 1er, 2do y 3er campo. Para el 4to hago algo asi:

Código
  1. memset(buffer, 0 ,512);
  2. i = recv(buffer);
  3. buffer[i]='\0';
  4. while(strcmp(buffer, "."))
  5. {
  6.    estructura.m_cuerpo = (char*)realloc(estructura.m_cuerpo,  SIZEOF(CHAR)*STRLEN(BUFFER) +1);
  7.    if(strlen(estructura.m_cuerpo) > 0)strcat(estructura.m_cuerpo, buffer);
  8.    else strcpy(estructura.m_cuerpo, buffer);
  9.    memset(buffer, 0, 512);
  10.    i =recv(buffer);
  11.    buffer[i]='\0';
  12. }

Lo que estoy preguntando es, de que forma puedo hacer ese WHILE para que vaya agrandando la variable hasta que reciba del socket un ".". Y esta mal el tamaño del realloc, lo se jajaj.
Todo esto forma parte de un sistema que estoy haciendo para un trabajo practico, es un servidor de noticias que utiliza el protocolo nntp (un toke simplificado) esos 4 campos serian los campos de un articulo de noticias ID, groupname, head y body. Los primeros 3 basta con 512 bytes (1 lectura de socket) y el body puede llegar a ser mas grande, el tema es como agrando correctamente el body de mi estructura?