Newsgroup: it.comp.lang.c
Titolo: Segmentation Fault....AIUTO PER FAVORE!

Ragazzi aiutatemi.
Vi posto il codice che mi il Segmentation Fault, potete vedere voi
dov'è l'errore??MI compila perfettamente, ma quando vado a fare il
test mi va in SF.
Si tratta di una rubrica in C, questa sotto è la funzione PUSH (dove
mi da il SF)
[code]
int push(elem** db, voce* v)
{
	elem *	nuova	= malloc(sizeof(elem*));
	/* Riempimento della nuova voce */
        memcpy(&nuova->ptvoce,&v,sizeof(voce*));
	/* Aggiunta alla lista */
	memcpy(&nuova->next,db,sizeof(elem*));
	memcpy(db,&nuova,sizeof(elem*));
        /* Controllo */
	/*
	if (memcmp(&nuova,&(*db)->next,sizeof(elem*)) ||
memcmp(&nuova->ptvoce,&v,sizeof(voce*)))
	{
		return -1;
	}
	*/
	return 0;
}
[\code]
e qui sotto dove alloco il DataBase per la prima volta:
[code]
int leggiArchivio(FILE* ingresso, elem** db)
{
  char		record[RECLEN+2];
  voce *	temp	= NULL;
  int		num	= 0;
	/* Se il file non è valido, usciamo con un errore */
	if (ingresso == NULL)
	{
		return -1;
	}
	db = malloc(sizeof(elem**));
	while (record == fgets(record,RECLEN+2,ingresso))
	{
		/* Se il formato non è valido, usciamo con un errore */
		if (record[RECLEN] != '\n')
		{
			return -1;
		}
		/* Se il record non è convertito correttamente, usciamo con un
errore */
		if ((temp = rectovoce(record)) == NULL)
		{
			return -1;
		}
		/* Proviamo ad aggiungere la nuova voce, o usciamo con un errore */
		if (push(db,temp) != 0)
		{
			return -1;
		}
		num++;
  }
	return num;
}
[\code]
GRAZIE A TUTTI!

 memcpy(db,&nuova,sizeof(elem*));
Che dire.. dovresti ricontrollare meglio l'uso dei puntatori..
Ciao
M`

> 	elem *	nuova	= malloc(sizeof(elem*));
Questo basta già da solo:
sizeof(elem*) ti restituisce la dimensione di un PUNTATORE A ELEM, e non 
la dimensione della struttura.
Quindi tu allochi lo spazio "per un puntatore", e lo assegni alla 
variabile "nuova". A quel punto tratti "nuova" come se puntasse ad una 
struttura, con memcpy e cose varie, sovrascrivendo certamente qualche 
zona di memoria che tu presumi vuota ma che in realtà non lo è...
-- 
Quando noi ignoranti eravamo di più, tutto era più bello...
(A. Celentano)
Per rispondermi in privato, togli prima l'immondizia dalla testa ;)

 la dimensione della struttura.
E' il motivo per cui io consiglio sempre di scrivere:
T *p;
p = malloc(sizeof *p);
e non:
p = malloc(sizeof(T));
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/

> E' il motivo per cui io consiglio sempre di scrivere:
...e' il motivo per cui io sconsiglio di usare i puntatori...e in assoluto 
il c !!!!!! 

 il c !!!!!!
Ecco... un troll era quello che ci voleva...


Allora, grazie ai vostri suggerimenti sono riuscito a risolvere il
segmentation fault nella funzione push(), ma mi si è spostato nella
funzione formatvoce().
La funzione formatvoce() ha il seguente obbiettivo: converte i dati di
una voce in una stringa pronta per l'output.
ecco il codice:
int formatvoce(char b[], voce * v)
{
	/* Cancella la stringa */
	strcpy(b, "");
	/* Copiamo i dati */
	strcat(b, FORMAT_COGN);
	strcat(b, str_rtrim(v->cognome));
	strcat(b, "\n");
	strcat(b, FORMAT_NOME);
	strcat(b, str_rtrim(v->nome));
	strcat(b, "\n");
	strcat(b, FORMAT_CITT);
	strcat(b, str_rtrim(v->citta));
	strcat(b, "\n");
	strcat(b, FORMAT_TELE);
	strcat(b, str_rtrim(v->telefono));
	strcat(b, "\n");
	strcat(b, FORMAT_COMM);
	strcat(b, str_rtrim(v->commento));
	strcat(b, "\n");
	b[strlen(b) +1] = '\0';
	return (strlen(b)  == FORMAT_LEN);
}
mi da il segfault in una delle strcat che legge dei dati da "v"
cosa posso fare??
grazie

 strcat(b, FORMAT_COGN);
A che serve ? nel caso fai direttamente un:
strcpy(b, FORMAT_COGN);
In ogni caso, quello che scrivi produce dei memory leak (restituisci memoria
allocata con str_rtrim() ma non la liberi mai) e comunque il seg fault č
sicuramente dovuto a ciň che fai nella funzione str_rtrim()).
In ogni caso, puoi scrivere qualcosa del tipo:
char *cognome = str_rtrim(v->cognome);
char *nome = str_rtrim(v->nome);
...
...
e poi usare una bella sprintf() per ottenere il risultato finale:
sprintf(b, "%s%s\n%s%s\n%s%s", cognome, ..., nome, ..., ..., ...., ....);
ricordandoti di liberare la memoria allocata precedentemente:
free(cognome);
free(nome;
e comunque assicurandoti che b abbia sufficiente spazio per contenere
l'intero stringone.


 /* Copiamo i dati */
Come facciamo all'interno di questa funzione a sapere se l'array
identificato da 'b' ha sufficiente spazio per ospitare quanto stiamo
copiando?
E se anche conoscessimo le dimensioni di detto array, come facciamo a sapere
se le stringhe restituite dalle varie invocazioni di 'str_rtrim' (e passate
a 'strcat') non eccedano lo spazio disponibile? 'strcat' non puň sapere se
quello che gli chiediamo di fare sia legittimo.
Inoltre: dove risiedono le stringhe restituite da 'str_rtrim'? Sono allocate
da 'malloc'? Se sě, chi ci pensa a rilascarle con 'free'?
Consigli: 
 - ogni volta che devi passare un array a una funzione, trova il modo di
passare anche le sue dimensioni
 - non usare MAI 'strcat' 
 
Max

@Andrea Laforgia
Ho provato a fare le modifiche che mi hai suggerito, cioè usando
sprintf e togliendo le chiamate a str_rtrim, ma nonstante questo il
segfault resta durante una chimata a strlen; quindi penso che sia un
problema di memoria....

 cosa posso fare??
il metodo piu' efficace per verificare questi problemi e usare il 
debugger gdb e vedere cosa succede alla variabile b.
Ovviamente dovrai compilare il tuo codice con lo switch -g
Ciao.

 ha
scritto:

"problema di memoria" non vuol dire nulla.
Non credo che i banchi di RAM della tua macchina abbiano qualche problema
;-P
La sprintf() può fallire solo e soltanto, nel tuo caso, perché non allochi
sufficiente memoria per la stringa di destinazione. Il fatto che, poi, tu
abbia un errore su una chiamata a strlen() può essere del tutto fortuito.


 
la funzione strlen puo' fallire per 2 motivi essenzialmente
1) gli passi un indirizzo sbagliato, quindi va ad accedere a memoria
che non esiste o che in generale non e' di sua competenza.
2) l'indirizzo e' giusto ma la stringa non e' stata fornita di 
terminatore o il terminatore e' stato "mangiato".
esempio:
hai
char S[4];
double x;
poi in S copi per sbaglio la stringa "ciao" che
pero' occupa 5 caratteri.
strcpy(S,"ciao");
quindi nelle 4 posizioni valide di S c'e' 'c','i','a','o',
mentre il terminatore 0 di "ciao" va a finire oltre il
limite dei 4 caratteri assegnati ad S.
Gia' questo di per se potrebbe causare un errore.
Ma supponiamo che la memoria "dietro" S sia usata per
il double x. Allora il terminatore 0 di "ciao" andrebbe a
sporcare X.
Ma se poi io scrivo X=3453453.353453 quello che
capitera' e' che io sovrascrivo X e quindi ammazzo
lo 0 di "ciao".
Se ora vado a fare strlen(S) la strlen comincia
a scandire S fino a che non trova uno 0.
Quello giusto non c'e' piu' perche' e' stato
sovrascritto da X. Quindi va avanti a cercarne un altro:
o ne trova uno nel mio spazio di memoria e mi da quindi
un bel risultato sbagliato ma nessun errore (caso sfigato),
oppure a forza di cercar lo 0 va a finire fuori
dal mio spazio di memoria e mi genera un segmentation f. (caso
fortunato, perche' cosi' mi accorgo che c'e' un errore).
Comunque problemi di questo tipo dovrebbero
essere abbastanza facilmente risolvibili con un debugger.
ciao,
g.

 abbia un errore su una chiamata a strlen() può essere del tutto fortuito.


Prima di cominciare, grazie a tutti delle risposte.
Ecco la situazione. In una main (che non possiamo modificare) ci
troviamo questo codice:
int main(void)
{
  elem* database=NULL;
  FILE* archivio;
  int i=0;
/* cut */
  i=leggiArchivio(archivio,&database);
/* cut */
}
Quindi, leggiArchivio() ha da gestire l'allocazione dello spazio per
"database", che dovrà poi essere utilizzato dalla funzione push():
int leggiArchivio(FILE* ingresso, elem** db)
{
/* cut */
  (*db) = (elem *) malloc(sizeof(elem));
/* cut */
}
int push(elem** db, voce* v)
{
  elem * nuova = malloc(sizeof(elem));
  /* Riempimento della nuova voce */
  nuova->ptvoce = v;
  /* Aggiunta alla lista */
  if (!*db)
    (*db) = nuova;
  else
    (*db)->next = nuova;
  return 0;
}
Ora, il problema con la push() sembra essersi risolto, grazie alle
vostre risposte, e tutto sembra funzionare, finché il codice della
main() non decide di stampare sullo schermo i dati ottenuti. Lo fa dopo
aver convertito la voce in una stringa, e lo fa con la seguente
funzione, formatvoce():
int formatvoce(char b[], voce * v)
{
  sprintf
  (
    b,
    FORMAT_COGN "%s\n" FORMAT_NOME "%s\n" FORMAT_CITT "%s\n"
FORMAT_TELE "%s\n" FORMAT_COMM "%s\n",
    v->cognome, v->nome, v->citta, v->telefono, v->commento
  );
  return (strlen(b) == FORMAT_LEN);
}
È durante la chiamata a questa funzione che strlen() (usato da
sprintf()) restituisce solo un segmentation fault. Questa funzione,
formatvoce(), viene chiamata in questo modo:
  formatvoce(str,db->ptvoce);
dove "db" è il database della main() e "str" è stata allocata con il
seguente assegnamento:
  char * str = malloc(8 * 1024);
Mi scuso con tutti per il post così lungo e pieno di codice, ma mi
sembrava indispensabile per chiarire la situazione.
Vi ringrazio nuovamente per l'aiuto che ci avete dato finora.

 }
Avete provato a stampare a video la stringa b, per vedere se
e' corretta?
printf("<%s>\n",b);
e prima ancora avete provato a stampare le singole voci
printf("<%s>\n",v->cognome);
etc.etc.
per controllare che siano a posto ?
ciao,
g.

Non avevo provato, ora ho usato questo codice per controllare:
	printf("b (string): %s;\n", b);
	printf("b (pointer): %p;\n", b);
	printf("v (pointer): %p;\n", v);
	printf("v->nome (string): %s;\n", v->nome);
	printf("v->nome (pointer): %p;\n", v->nome);
	printf("v->cognome (string): %s;\n", v->cognome);
	printf("v->cognome (pointer): %p;\n", v->cognome);
	printf("v->citta (string): %s;\n", v->citta);
	printf("v->citta (pointer): %p;\n", v->citta);
	printf("v->telefono (string): %s;\n", v->telefono);
	printf("v->telefono (pointer): %p;\n", v->telefono);
	printf("v->commento (string): %s;\n", v->commento);
	printf("v->commento (pointer): %p;\n", v->commento);
Ma leggo soltanto:
	b (string): ;
	b (pointer): 0x804b498;
	v (pointer): (nil);
	v->nome (string): (null);
	v->nome (pointer): (nil);
	Segmentation fault
Quindi era come temevo. Qualche assegnazione è sbagliata, ma non
riesco ad individuare l'errore.