Newsgroup: it.comp.lang.c
Titolo: Argh, maledetta free

int build(int n, int m, int *rcl, int *nrcl, int *headp, int *headm, int
*lit,
          int *x, long *wsat, int *clause, long *w, int *headc, int *nextp,
int *nextm, long *minus, long *plus, float alpha){
  int *satcl;
  int i, k;
  int index, index2;
  int s; /* numero casuale tra 0 ed nrcl */
  int ptr;
  satcl = calloc(m+1, sizeof(int));
  (*wsat)=0;
  for(i=1; i<=n+1; i++){
    x[i]=0;
  }
  for(i=1; i<=n; i++){
    if((*nrcl)==0) return 0; /* se la rcl č vuota ritorna  */
    /* seleziona un candidato dalla RCL */
    s = (genrand_int31()%(*nrcl))+1;
    index=abs(rcl[s]);
    if(rcl[s]>0){
      x[index]=1;
      (*wsat)=(*wsat)+plus[index];
      ptr=headp[index];
    }
    else{
      x[index]=-1;
      (*wsat)=(*wsat)+minus[index];
      ptr=headm[index];
    }
    while(ptr!=0){
      if(satcl[clause[ptr]] != 1){
        for(k=headc[clause[ptr]]; k<headc[clause[ptr]+1]; k++){
          index2=abs(lit[k]);
          if(x[index2]==0){
            if(lit[k]>0)
              plus[index2]=plus[index2]-w[clause[ptr]];
            else
              minus[index2]=minus[index2]-w[clause[ptr]];
          }
        }
        satcl[clause[ptr]]=1;
      }
      if(rcl[s]>0)
        ptr=nextp[ptr];
      else
        ptr=nextm[ptr];
    }
    plus[index]=0;
    minus[index]=0;
    updateRCL(minus, plus, rcl, nrcl, x, alpha, n);
  }
  free(satcl);  <----------------------------------------
  return 0;
}
Secondo voi perchč con la free indicata dalla freccia va tutto in malora?
Eppure satcl lo utilizzo solo nella funzione che vi ho mostrato. Credo sia
sbagliato non mettere la free, altrimenti ad ogni chiamata alloco altro
spazio senza deallocare il vecchio che non mi serve piů.
Grazie

Le uniche cose che posso suggerirti sono:
1 - invece di usare calloc() passa a malloc() (non so se la free() va 
bene anche per che chiamate a calloc());
2 - Potrebbe succedere (ma non lo so, sto solo supponendo) che, se tu 
scrivi oltre la zona allocata, si verifichino problemi con la free().
Comunque, dopo una chiamata a malloc() o calloc(), tu controlli che 
effettivamente ti sia stato concesso qualcosa.
int *p = 0;
p = malloc(3000 * sizeof(int));
if (p)
{
    ...
    ...
    free(p);
    p = 0;
};
-- 
Quando noi ignoranti eravamo di più, tutto era più bello...
(A. Celentano)
Per rispondermi in privato, prima togli l'immondizia dalla testa.

 };
Ho verificato e mi viene allocato tutto.


Ho verificato ed è tutto ok. In ogni caso la free() gestisce anche
l'evenienza che il puntatore sia NULL.
Uffa !!!!

Non so dirti, l'unica cosa è provare a callocare e a richiamare free() 
immediatamente, così da vedere che succede.
Se non va in bestia, allora il problema è nel loop, e quindi ti 
consiglio di mandare in output i valori che assume di volta in volta 
clause[ptr] così da vedere se rimane compreso tra 0 ed m+1...
Ripeto, secondo me vai in overflow da qualche parte...


 spazio senza deallocare il vecchio che non mi serve più.
prima di tutto calloc e malloc vanno bene entrambe con la free.
il problema puo' essere dovuto questo.
Il compilatore per poter fare la free deve memorizzare da qualche
parte la lunghezza dell'array allocato (altrimenti
non saprebbe quanto spazio liberare).
Una possibilita' (almeno su certi compilatori) e' che
queste informazioni vengano memorizzate subito prima dell'array
stesso.
Cioe' tu pensi di allocare 100 byte, ma in realta ne allochi
4+100 o 8+100 e i primi 4 o 8 contengono delle informazioni che
serviranno per la free.
Ora, ci potrebbe essere un errore nell'accedere a
un altro array adiancente (o allo stesso array in questione)
per cui viene erroneamente sovrascritta questa zona.
Quando vai poi a fare la free magari invece di liberare 100
byte lui cerca di liberarne 20MB con conseguente incartamento.
Quindi il fatto che si pianti nella free e' solo un campanello
di allarme che qualcosa va storto. Il problema e' che non
e' assolutamente detto che l'errore coinvolta direttamente
l'array del quale fai la free.
Prima di cancellarla potresti controllare se per esempio
anche il primo valore satcl[0] e' stato modificato.
In quel caso (monitorando quel valore) dovrebbe essere
facile capire con un debugger quale istruzione va erroneamente
a sovrascriverlo.
Altrimenti dovresti controllare che tutti gli array vengano
acceduti con indici entro i bound. E controllare anche
come usi i puntatori... La cosa puo' essere putroppo parecchio
noiosa.
ciao,
g.

 > spazio senza deallocare il vecchio che non mi serve piů.

Nell'array č tutto ok. Maledizzione, non ne verrň mai fuori.

 Ho verificato ed è tutto ok. 
Allora devi verificare anche tutti gli altri vettori e puntatori...
 > In ogni caso la free() gestisce anche
 > l'evenienza che il puntatore sia NULL.
Che sia NULL si, ma non che sia sballato o che non sia un puntatore
restituito da malloc o calloc.
Per esempio questo e' sbagliato
int *p;
p = malloc(400);
p++;
free(p);
ciao,
g.

 Non scrivo mai oltre la zona allocata.
Non so come fai ad esserne certo. Nota che non stiamo parlando 
esclusivamente di quella zona allocata con calloc. Se il programma va in 
crash durante una 'free', vuol dire che c'è un baco (presumibilmente nel 
tuo codice). Una della cause tipiche di crash nelle routine di gestione 
della memoria dinamica è la precedente accidentale sovrascrittura delle 
strutture dati su cui deve far affidamento il gestore delle allocazioni 
dinamiche.
Max

 esclusivamente di quella zona allocata con calloc.
Perchè il codice in questione è quello che ho postato ed ho verificato tutti
i parametri e stanno nel range corretto.

 bene anche per che chiamate a calloc());
Inutile: la free() va bene per malloc(), calloc() e realloc().
Passando a malloc() perderebbe il vantaggio di avere la memoria allocata
automaticamente inizializzata a zero (sempre che ciò gli serva).
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 Nell'array č tutto ok. Maledizzione, non ne verrň mai fuori.
allora devi
1) controllare anche cosa fa la routine UpdateRCL
2) scriverti una versione alternativa della tua funzione che ogni
volta che accede ad un qualunque array controlli che l'indice sia
nei limiti, non solo quando accedi a satcl.
Una cosa che potrebbe funzionare (male non fa)
con un debugger e' questa.
ti definisci un puntatore ausiliario
int *chkp;
e DOPO aver allocato satcl poni
chkp = satcl - 1;
in questo modo chkp dovrebbe puntare ai 4 byte precedenti
l'inizio canonico di satcl. (Supponendo che sul tuo sistema
gli int occupino 4 byte).
In diversi sistemi quella zona e' quella che tiene
le informazioni sulla allocazione di satcl.
Supponendo che tutto questo sia corretto,
usando un debugger tieni d'occhio il valore
di *chkp  o equivalmentente chkp[0].
Se l'assunzione che abbiamo fatto sopra e' vera
e se ad un certo punto lo vedi cambiare,
allora hai trovato l'istruzione che ti 'sporca'
l'allocazione di satcl.
Se non sai usare un debugger puoi infarcire il programma di
stampe del tipo printf("%d\n",*chkp);
Naturalmente se la mia assunzione che quei 4 byte siano vitali
e' falsa tutto cio' non ti aiutera'.
Su certi ambienti di sviluppo/compilatori ci sono delle
opzioni per condurre automaticamente dei controlli sugli
accessi alla memoria. Per esempio nel vecchio BorlandC++BuilderPro5
c'era CodeGuard che a volte funzionava. Magari c'e' qualcosa di
simile anche per il compilatore che usi tu.
ciao,
g.

 ha scritto nel messaggio
news:d9easn$kqp$8...@newsfeed.cineca.it...

Ho lanciato il codice per verificando che ogni scrittura dal momento
dell'allocazione di satcl alla free venga fatta nei range corretti, ed č
tutto ok. In ogni caso, ragionando mi sono accorto che era una stupidata
allocarlo in quella funzione dato che la funzione Build(....) viene
richiamata 100inaia di volte. Quindi ogni volta allocavo e disallocavo. Ho
allora, allocato esternamente alla funzione build() l'array satcl e poi
glielo ho passato tra i parametri. Ora va tutto bene.
L'unica cosa č che all'inizio della funzione utilizzo una memset per
azzerare tutti gli elementi di satcl. L'ho preferita ad un banale for con
assegnazioni satcl[i]=0 perchč credo che l'implementazione della memset sia
di sicuro piů performante.
Ho quindi scritto:
  memset(satcl,0,(m+1)*sizeof(int));
ricordando che:
  checkMem(satcl  = calloc(m+1, sizeof(int)));
dove checkMem č:
void checkMem(void *array){
  if (array==NULL){
    perror("Errore di allocazione");
    exit(1);
  }
}
Tutto ok, vero?
Grazie ancora e sempre.

 Tutto ok, vero?
Si. A parte che non e' detto che il risparmio in termini
di tempo tra memset e fare un ciclo sia una gran cosa.
Tieni conto che il compilatore ottimizza e si accorge se
stai facendo un ciclo per azzerare un array.
In particolare sulla mia macchina/compilatore ci mettono
esattamente lo stesso tempo.
Per quel che riguarda il fatto di spostare fuori l'allocazione
di satcl e il fatto che ti funzioni sono contento,
e non vorrei fare l'uccello del malaugurio dicendo che pero'
se si inceppava prima vuol dire che c'era un errore nel
codice e questo errore ancora c'e'...
Quindi potrebbe anche andare tutto bene, ma potrebbe anche
essere che ora produce risultati errati, senza darti errori apparenti.
ciao,
g.

 ha scritto nel messaggio
news:d9eelf$kqp$1...@newsfeed.cineca.it...

Grazie, di questo sono conscio anche io, ma ho verificato tutte le
assegnazioni, ho controllo che tutte le assegnazioni venissero fatte
all'interno degli indici di assegnazione degli array e tutto era ok. I
risultati li ho verificati con quelli di una pubblicazione (sto lavorando al
miglioramento di una meta-eruristica per maxsat) e sono corretti.
Ho letto di alcuni bug con malloc/calloc/free, non vorrei dipendesse da
quello. Cmq, appena trovo il tempo faccio il controllo se c'e' una qualche
scrittura sulla locazione satcl-1 come mi è stato suggerito.
Grazie di tutto.

di sicuro piů performante.
E credi sbagliato perche' dipende dal compilatore; con
un compilatore decente una sequenza di azzeramento di
un array viene riconosciuta e ottimizzata.
Persino il Visual C++ 6.0 (scritto un bel po' di anni
fa) ad esempio con il codice
     int vector[100];
     void foo(int n)
     {
         int i;
         for (i=0; i<n; i++)
             vector[i] = 0;
     }
compila il loop in una istruzione "rep stosd" di
azzeramento esattamente come fa per memset.
Andrea

 ha scritto nel messaggio
news:b84mb1dn88999fog3...@4ax.com...

Tu hai perfettamente ragione, ma se nessuna scrittura (dico NESSUNA) andava
fuori array, cosa dovevo fare di piů?
Come potevo scovarlo. In ogni caso la soluzione era concettualmente
sbagliata.
Ciao

 On Thu, 23 Jun 2005 12:55:54 GMT, "Ciobin"
[CUT]
Dopo il tuo post, l'ansia mi ha spinto a ritornare sui miei passi. Cosě ho
ripreso la versione del codice incriminata che fino a 2 giorni fa crashava
ed ora funziona una bellezza.
Come cavolo č possibile !!!!!!! Potrebbe essere dipeso da uno
"sputtanamento" del sistema dovuto ad altri precedenti e ripetuti crash e
problemi vari che poi avevo risolto? Magari avrei dovuto cmq riavviare la
macchina.
Il mistero si infittisce !!!!!

Il mistero si infittisce !!!!!
Se avessi visto codice compilabile che presentava
il problema avrei provato a darci un'occhiata anche
se dallo stile temo che si tratti di andarsi a cercare
un mal di testa.
Una cosa molto importante da ricordare sempre e'
che il fatto che quando un programma sconfina ci
sia un crash NON E' GARANTITO.
Le cose in C e C++ sono complicate perche' per la
filosofia che sta alla base del linguaggio quando il
programmatore sbaglia qualcosa il risultato e' che
puo' succedere *di tutto*... e la cosa *peggiore* e'
quando questo "di tutto" si traduce nel fatto che
non succede (apparentemente) niente di niente e
tutto *sembra* funzionare.
Riassumendo: se hai un crash allora c'e' sicuramente
un errore, se invece non hai crash questo *NON*
significa che non ci sia un errore.
I programmi C o C++ che si comportano diversamente
da un lancio all'altro sono purtroppo comuni e
uno dei possibli motivi e' ad esempio la mancata
inizializzazione di qualche variabile.
Lo "sputtanamento" del sistema non e' teoricamente
impossibile, ma e' secondo me molto ma molto piu'
probabile che invece sia il tuo programma a fare
qualche sciocchezza e che il resto sia opera dei
simpatici demoni nasali.
Dando un'occhiata al codice del primo post... ad esempio
vedo:
   for(i=1; i<=n+1; i++){
      x[i]=0;
   }
x e' stato allocato correttamente ? per come e' scritto
questo loop deve puntare ad un array di almeno n+2 interi.
   for(i=1; i<=n; i++){
e rcl e' allocato con almeno n+1 elementi ?
In generale in un programma C in cui i loop sono stati
scritti da 1 a n incluso invece che da 0 a n-1 fatico
a credere che non ci siano sconfinamenti.
Perche' farsi del male in questo modo ?
Andrea


Questo lo so, ma purtroppo il mio compito è di portare del codice da Fortran
a C e al momento il contenuto di molti di questi array sono indici di altri
array che a volte contengono indici di variabili che vanno da 1 a n.
Cambiare l'indicizzazione partendo da 0 avrebbe voluto dire complicarsi
notevolmente con gli indici delle variabili. Avrei dovuto "ricostruire"
tutti il sistema di gestione degli indici e non mi andava di farlo. Ecco
tutto. In questo programma in pratica lascio inutilizzato l'elemento Zero di
ogni array. So che è agghiacciante, ma ho tempi stretti e francamente ho
altri aspetti da curare ed a cui dedicare tempo.
Cmq grazie per i suggerimenti. Ero conscio di quanto dici, ma l'ansia mi ha
fatto dimenticare molte cose.
GRAZIE !!!!!