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"
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.
//reservar
char **lista = (char**)malloc(sizeof(char*) * 3);
for (int x = 0; x < 3; x++)
{
lista[x] = (char*)malloc(sizeof(char) * 5);
}
//usar
//liberar
for (int x = 0; x < 3; x++)
{
free(lista[x]);
}
free(lista);
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
Puedes utilizar GesHi por favor?
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
asi? no tengo idea de como se usa
igual creo que camulle en los while para recorrer la lista
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).
while(*ptr != '\0')
printf("%s\n", *ptr++);
Si a la funcion le paso una referencia a lista, el prototipo no seria
void fnc(char*** lista); ????
entonces...
quedamos de acuerdo en que
char** lista;
lista = (char**)malloc( sizeof(char*)*5); // reservo espacio para 5 strings
lista = (char*)malloc( sizeof(char)*10); // reservo 10 bytes para 1 de los 5 strings
ahora, para copiar 1 cadena, es corecto?:
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.
Cita de: Ghalad en 24 Mayo 2010, 21:52 PMSi 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.
Cita de: Ghalad en 24 Mayo 2010, 21:52 PMentonces...
quedamos de acuerdo en que
char** lista;
lista = (char**)malloc( sizeof(char*)*5); // reservo espacio para 5 strings
lista = (char*)malloc( sizeof(char)*10); // reservo 10 bytes para 1 de los 5 strings
Si.
Cita de: Ghalad en 24 Mayo 2010, 21:52 PMahora, para copiar 1 cadena, es corecto?:
strcpy(lista[i], "mi cadena");
Tambien.
Cita de: Ghalad en 24 Mayo 2010, 21:52 PMpensa 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++ **&).
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.
mm algo me funcionamal aver:
void obtenerLista(char ***lista)
{
char buf[50];
*lista = (char**)malloc(sizeof(char*)*5);
for(int i=0; i<5; i++)
{
printf("Ingresa cadena: ");
fgets(buf, 50, stdin);
*lista[i]= (char*)malloc(sizeof(char)*strlen(buf));
strcpy(*lista[i], buf);
}
}
int main(){
char **lista;
obtenerLista(&lista);
for(int i =0; i<5; i++){
printf("grupo %d: %s", i, lista[i]);
}
for(int i=0; i<5; i++){
free(lista[i]);
}
free(lista);
retunr 0;
}
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?
Vos queres acceder a:
lista[0][i]
Y estas accediendo a:
lista[i][0]
Podes hacerlo como muestro arriba de todo o asi:
(*lista)[i]
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.
char** obtenerLista(int *contador)
{
int cont = 0;
char buf[50], **lista;
for(int i = 0; i < 10; i++)
{
printf("Ingresa cadena: ");
fgets(buf, 50, stdin);
buf[strlen(buf)-1] = '\0';
if(strlen(buf) > 0){
lista = (char**)realloc(lista, sizeof(char*));
lista[cont]= (char*)malloc( (sizeof(char)*strlen(buf))+1);
strcpy(lista[cont], buf);
++cont;
}
}
*contador = cont;
return lista;
}
int main(){
char **lista;
int contador;
lista = obtenerLista(&contador);
for(int i =0; i < contador; i++){
printf("grupo %d: %s\n", i, lista[i]);
}
for(int i=0; i<contador; i++){
free(lista[i]);
}
free(lista);
system("pause");
return 0;
}
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).
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?
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 ...
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.
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
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.
ahhh yo crei que vos le pasabas cuanto querias agrandar el bloque de memoria, entonces lo correcto seria algo asi:
char** obtenerLista(int *contador)
{
int cont = 0;
char buf[50], **lista = NULL;
for(int i = 0; i < 10; i++)
{
printf("Ingresa cadena: ");
fgets(buf, 50, stdin);
buf[strlen(buf)-1] = '\0';
if(strlen(buf) > 0){
++cont;
lista = (char**)realloc(lista, sizeof(char*)*cont);
if(lista == NULL) abort();
lista[cont]= (char*)malloc( (sizeof(char)*strlen(buf))+1);
if(lista[cont]==NULL) abort();
strcpy(lista[cont], buf);
}
}
*contador = cont;
return lista;
}
De esta forma estaria diciendo que el puntero se agrande sizeof(char*) cada vez que quiero agregar un nuevo string?
char** obtenerLista(int *contador)
{
int cont = 0;
char buf[50], **lista = NULL;
for(int i = 0; i < 10; i++)
{
printf("Ingresa cadena: ");
fgets(buf, 50, stdin);
buf[strlen(buf)-1] = '\0';
if(strlen(buf) > 0){
++cont;
lista = (char**)realloc(lista, sizeof(char*)*cont);
if(lista == NULL) abort();
lista[cont-1]= (char*)malloc( (sizeof(char)*strlen(buf))+1);
if(lista[cont-1]==NULL) abort();
strcpy(lista[cont-1], buf);
}
}
*contador = cont;
return lista;
}
con este codigo me funciones de 10! pero es correcto o e n que la estoy pifiando?
Si, pero cont arranca de 0 asi que:
lista = (char**)realloc(lista, sizeof(char*) * (cont+ 1));
ahi le reste 1, funciona bien pero esta bien hecho el codigo? no estoy desperdiciando memoria en algun lado?
Cita de: Eternal Idol en 30 Mayo 2010, 19:51 PM
Si, pero cont arranca de 0 asi que:
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..
Si, el codigo tiene que ser enteramente en C ansi pero me es mas facil para mostrarselo a ustedes en c++.
Cita de: 08l00D en 30 Mayo 2010, 19:55 PMPero si lo incrementa previamente con "++count;" una linea antes...
Estaba viendo el codigo original donde no lo hacia ;D
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:
memset(buffer, 0 ,512);
i = recv(buffer);
buffer[i]='\0';
while(strcmp(buffer, "."))
{
estructura.m_cuerpo = (char*)realloc(estructura.m_cuerpo, SIZEOF(CHAR)*STRLEN(BUFFER) +1);
if(strlen(estructura.m_cuerpo) > 0)strcat(estructura.m_cuerpo, buffer);
else strcpy(estructura.m_cuerpo, buffer);
memset(buffer, 0, 512);
i =recv(buffer);
buffer[i]='\0';
}
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?