Newsgroup: it.comp.lang.c
Titolo: Linked list

ciao a tutti...una domanda.. come mai queste due verifiche devono 
essere scritte in modo diverso, o almeno il compilatore me le fa 
scriviere solo in questo modo (altrimenti va in crash!)?!!!
le verifiche sn: del pimo algoritmo: if(head -> next == NULL) e del 
secondo: if(head == NULL)
ad entrambe chiamo la ricorsione sempre cn (head -> next) ma alla prima 
devo confrontare se (head -> next == NULL) e nella seconda confronto 
solo se (head == NULL)
questo è il primo algoritmo:
void tagliente(LINK head, int *tag)
{
  LINK temp;
temp = head -> next;
/*sarebbe lo stesso se scrivessi (temp == NULL)*/
if (head -> next == NULL)
;
else if(((head -> d < 0) && (temp -> d < 0))|| ((head -> d > 0) && 
(temp -> d > 0)))
      *tag = 0;
else
{
   *tag = 1;
   tagliente(head -> next, tag);
}
}
questo il secondo:
int count(LINK head)
{
if (head == NULL)
return 0;
else
return (1+count(head -> next));
}
-- 
Renato Zero
Provaci a riemergere, da quei sogni che il tuo silenzio ha ucciso...che 
ne sai, dell'origine, delle lacrime, se non ha mai pianto...provaci, a 
scommettere, che al traguardo tu non sarai secondo...agile è 
quest'anima,  non puoi vincerla, non la puoi ingannare più......PROVA A 
PRENDERMI......

 in questo modo (altrimenti va in crash!)?!!!
Ti va in crash il compilatore? Che cosa stai usando?
Dal codice che hai postato non vedo niente di strano, forse qualcosa in 
qualche altra parte del programma?
Remo D.

 qualche altra parte del programma?
infatti è stranissimo...sn uscito pazzo stamattina...!!
#include <stdio.h>
#include <stdlib.h>
typedef int DATA;
struct linked_list{
        DATA d;
        struct linked_list *next;
};
typedef struct linked_list ELEMENT;
typedef ELEMENT *LINK;
int count(LINK head)
{
if (head == NULL) /*qui funziona tranquillamente cn head == NUL*/
return 0;
else
return (1+count(head -> next));
}
void tagliente(LINK head, int *tag)
{
  LINK temp;
temp = head -> next;
if (head  == NULL) /*mentre qui nn funziona!mi pare sia la stessa 
cosa*/
;
else if(((head -> d < 0) && (temp -> d < 0))|| ((head -> d > 0) && 
(temp -> d > 0)))
      *tag = 0;
else
{
   *tag = 1;
   tagliente(head -> next, tag);
}
}
main()
{
LINK head;
int tag, t;
head = malloc(sizeof(ELEMENT));
head -> d =-8;
head -> next = malloc(sizeof(ELEMENT));
head -> next -> d = 4;
head -> next -> next = malloc(sizeof(ELEMENT));
head -> next -> next -> d = -5;
head -> next -> next -> next = malloc(sizeof(ELEMENT));
head -> next -> next -> next -> d = 5;
head -> next -> next -> next -> next = NULL;
tag=0;
tagliente(head, &tag);
t=count(head);
printf("%d ed numero: %d\n", tag, t);
return 0;


 ;
Falso. E' la riga precedente che non funziona.
Se head è null non puoi leggere head->next.

> if (head  == NULL) /*mentre qui nn funziona!mi pare sia la stessa cosa*/
al posto di mettere (head == NULL) metto (temp == NULL) oppure (head -> 
next == NUL) FUNZIONA!!!! è questo che nn sono riuscito a capire....


Runner (RU) ed AnalogFile (AF) hanno scritto:
RU>>> if (head == NULL) /*qui funziona tranquillamente cn head == NUL*/
AF>> Vero.
RU>>> temp = head -> next;
RU>>> if (head  == NULL) /*mentre qui nn funziona!mi pare  sia la
stessa cosa*/
AF>> Falso. E' la riga precedente che non funziona.
AF>>Se head è null non puoi leggere head->next.
RU> aspetta nn ho capito.....
RU> questo algoritmo è ricorsivo, e termina diciamo quando
RU> raggiungo la  fine della lista. quindi ci sarà sempre un
RU> valore null!!
Certo, ma, come ha detto AF, tu cerchi di accedere a head->next quando
head è NULL. La variabile temp puo' contenere un valore qualunque
oppure ti puo' andare in crash direttamente sull'assegnazione. Il
momento esatto in cui il programma andrà in errore dipende da come il
compilatore ha tradotto le istruzioni in assembler.
Devi essere sicuro che il puntatore non sia NULL *prima* di accedere ad
un campo della struttura puntata, farlo dopo potrebbe essere troppo
tardi!
Remo D.

 
Come ti ho detto non funziona perché accedi prima di fare il controllo.
Proprio perché è ricorsivo.
In pratica hai qualche cosa del tipo:
void f( T *p )
{
   T* tmp;
   // nota: questo è indefinito se p==NULL
   tmp = p->next;
   if ( p == NULL ) {
     ...
   } else {
     ...
     f( p->next );
     ...
   }
}
Ora se p!=NULL ma p->next==NULL tu esegui la chiamata ricorsiva e a 
questo punto vai in crash.
Se invece cambi il test nell'if in "if ( p->next == NULL ) {" allora la 
chiamata ricorsiva non la esegui.
Però nota che non esegui neppure il corpo dell'else anche se p è valido.
Quindi devi deciderti:
1) l'if si riferisce alla validità del record attuale o all'esistenza di 
un record successivo all'attuale? In base alla risposta scrivi il corpo 
di then e else.
2) la funzione può essere richiamata con un record nullo o ha come 
precondizione che il record non possa essere nullo?
Nel primo caso non puoi dare tmp=p->next senza prima aver verificato se 
il record è valido. Nel secondo va tutto bene ed è responsabilità del 
chiamante assicurarsi di non chiamare mai la funzione con NULL. In tal 
caso consiglio di affiungere come primo statemente della funzione un 
bell'ASSERT che ti aiuta a "trappare" errori di chiamata:
void tagliente(LINK head, int *tag)
{
   LINK temp;
   assert( head != NULL );
   temp = head -> next;
   ...