PDA

View Full Version : [C] Errore realloc()


Gino+89+
13-05-2010, 10:09
Ciao a tutti...
Ho compilato con successo il seguente codice su Linux Ubuntu 9.04 con gcc (4.3.3) senza nessun errore o warning...
Ma eseguendolo, aggiungendo anche una sola realloc() (vedi commento codice), a run-time mi da Segmentation fault!

Il codice e' molto semplice:

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

int addElem(char **array,int *len,const char *elem);
void printElements(char **array,const int len);
void freeElements(char **array,int *len);

int main()
{
char **array;
int lenght=0;

array=(char**)malloc(sizeof(char*));
*array=strdup("elem1");
lenght++;
puts(array[lenght-1]);

if(addElem(array,&lenght,"asd2"))
{
printf("%d\n",lenght);
puts(array[lenght-1]);
}
if(addElem(array,&lenght,"asd3"))
{
printf("%d\n",lenght);
puts(array[lenght-1]);
}
if(addElem(array,&lenght,"asd4")) /* <== This generate the error! */
{
printf("%d\n",lenght);
puts(array[lenght-1]);
}

printElements(array,lenght);

freeElements(array,&lenght);

return 0;
}

int addElem(char **array,int *lenght,const char *elem)
{
if((array=realloc(array,((*lenght)+1)*sizeof(char*)))!=NULL)
{
array[(*lenght)++]=strdup(elem);
puts(array[(*lenght)-1]);
return 1;
}
return 0;
}

void printElements(char **array,const int len)
{
int i;

for(i=0;i<len;i++)
puts(array[i]);
}

void freeElements(char **array,int *len)
{
int i;

for(i=0;i<(*len);i++)
free(array[i]);

*len=0;

free(array);
}



Se togliete l'ultimo:

if(addElem(array,&lenght,"asd4"))
{
printf("%d\n",lenght);
puts(array[lenght-1]);
}


viene eseguito senza errori...
Da cosa puo' derivare questo errore??
Grazie mille!

lock cmpxchg8b %ebx
13-05-2010, 11:29
È semplice. Se non c'è abbastanza spazio per il cambio di dimensioni, realloc sposta l'array da qualche altra parte, cambiando il puntatore.
Il problema e che tu passi il puntatore base dell'array (invece di un puntatore al puntatore base dell'array), quindi la modifica fatta da realloc non viene propagata all'esterno della funzione.

Teo@Unix
13-05-2010, 11:58
if((array=realloc(array,((*lenght)+1)*sizeof(char*)))!=NULL)

questo controllo non va bene per realloc(). Se realloc fallisce lascia invariata la dimensione di array, ma non ritorna NULL!

Il tuo codice fallisce quando puts() tenta di mandare su stdout un elemento di array che non c'è.

lock cmpxchg8b %ebx
13-05-2010, 12:16
if((array=realloc(array,((*lenght)+1)*sizeof(char*)))!=NULL)

questo controllo non va bene per realloc(). Se realloc fallisce lascia invariata la dimensione di array, ma non ritorna NULL!

Il tuo codice fallisce quando puts() tenta di mandare su stdout un elemento di array che non c'è.
Upon successful completion with a size not equal to 0, realloc() returns a pointer to the (possibly moved) allocated space. If size is 0, either a null pointer or a unique pointer that can be successfully passed to free() is returned. If there is not enough available memory, realloc() returns a null pointer and sets errno to [ENOMEM].

Teo@Unix
13-05-2010, 13:20
:doh: ragione :fagiano:

Gino+89+
13-05-2010, 13:37
Eg gia'..mi ha detto la stessa cosa di @lock anche il prof ma nulla da fare non riesco a correggere

Ho provato una roba del genere ma peggio di prima:

char **array;
int lenght=0;

array=(char**)malloc(sizeof(char*));
*array=strdup("elem1");
lenght++;
puts(array[lenght-1]);

if(addElem(&array,&lenght,"asd2"))
{
printf("%d\n",lenght);
puts(array[lenght-1]);
}
if(addElem(&array,&lenght,"asd3"))
{
printf("%d\n",lenght);
puts(array[lenght-1]);
}
if(addElem(&array,&lenght,"asd4"))
{
printf("%d\n",lenght);
puts(array[lenght-1]);
}

printElements(array,lenght);

freeElements(array,&lenght);

return 0;
}

int addElem(char ***array,int *lenght,const char *elem)
{
*array=realloc(*array,((*lenght)+1)*sizeof(char*));
*array[(*lenght)++]=strdup(elem);
puts(*array[(*lenght)-1]);

return 0;
}


Non riesco proprio ad inquadrare la soluzione, ed inizio a vedere doppio:D

Gino+89+
13-05-2010, 13:47
RISOLTO

Ecco il codice corretto:

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

int addElem(char ***array,int *len,const char *elem);
void printElements(char **array,const int len);
void freeElements(char **array,int *len);

int main()
{
char **array;
int lenght=0;

array=(char**)malloc(sizeof(char*));
*array=strdup("elem1");
lenght++;
puts(array[lenght-1]);

if(addElem(&array,&lenght,"asd2"))
{
printf("%d\n",lenght);
puts(array[lenght-1]);
}
if(addElem(&array,&lenght,"asd3"))
{
printf("%d\n",lenght);
puts(array[lenght-1]);
}
if(addElem(&array,&lenght,"asd4"))
{
printf("%d\n",lenght);
puts(array[lenght-1]);
}

printElements(array,lenght);

freeElements(array,&lenght);

return 0;
}

int addElem(char ***array,int *lenght,const char *elem)
{
(*array)=realloc((*array),((*lenght)+1)*sizeof(char*));
(*array)[(*lenght)++]=strdup(elem);
puts((*array)[(*lenght)-1]);

return 0;
}

void printElements(char **array,const int len)
{
int i;

for(i=0;i<len;i++)
puts(array[i]);
}

void freeElements(char **array,int *len)
{
int i;

for(i=0;i<(*len);i++)
free(array[i]);

*len=0;

free(array);
}


Sebbene la compilazione non dava errori mancavano alcune parentesi! :D

Teo@Unix
13-05-2010, 20:09
Intendi queste?

(*array)=realloc((*array),((*lenght)+1)*sizeof(char*));
(*array)[(*lenght)++]=strdup(elem);
puts((*array)[(*lenght)-1]);

sinceramente credevo non influisse.

Un'altra cosa perchè per i primi due casi andava bene?
Scusa se chiedo, so che hai risolto, ma mi interessa capire il tipo di problema.

lock cmpxchg8b %ebx
13-05-2010, 20:38
Intendi queste?

(*array)=realloc((*array),((*lenght)+1)*sizeof(char*));
(*array)[(*lenght)++]=strdup(elem);
puts((*array)[(*lenght)-1]);

sinceramente credevo non influisse.
Nella linea del realloc non credo, ma nelle ultime due servono per forza le parentesi.
*array[i] //prendi l'i-esimo elemento di array e dereferenzialo
(*array)[i] //dereferenzia array e prendine l'i-esimo elemento

Teo@Unix
13-05-2010, 20:54
Giusto, giusto.... perchè lavora con puntatori....
grazie del chiarimento....

è che io mi sarei limitato a passare l'array normalmente non un puntatore a puntatore..... ma forse scopo dell'esercizio era proprio questo :)

lock cmpxchg8b %ebx
13-05-2010, 21:47
è che io mi sarei limitato a passare l'array normalmente non un puntatore a puntatore..... ma forse scopo dell'esercizio era proprio questo :)
Era quello che ha fatto lui all'inizio, ma non poteva funzionare per via del cambiamento di puntatore restituito da realloc.