Newsgroup: it.comp.lang.c
Titolo: problema con liste e puntatori.

Ho seguito i vostri consigli e giŕ ho fatto qualche passo avanti nella
battaglia contro la mia ignoranza nel C++.
Ma ho ancora problemini........C'č qualche paziente che mi spiega perchč
questo prog. non funziona....
Non credo di stare usando correttamente i puntatori....anche perchč non ho
capito come fare avanzare i dati all'interno della lista....e nel K&R non
l'ho trovato....Tralascio volontariamente l'ipotesi di domandarlo al
prof.(non chiedetemi perchč....potrei dare sfogo alla mia rabbia di
studente!!).....
Aiuto!!
Sempre grazie per l'attenzione e la pazienza...a presto.
Andrea.
Incollo il testo:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
struct persona
   {
   char nome[30];
   char cognome[30];
   };
struct dato
    {
    struct persona per;
    struct dato *datop;
    };
void scelta();
char menu ()
 {
 int c;
 printf("\nscegli l'operazione:  ");
 printf("\ni)inserisci.");
 printf("\nl)leggi.\n");
 scanf("%c", &c);
 return c;
 }
void immetti()
 {
 struct dato *p;
 if((p=(struct dato *) malloc (sizeof(struct dato)))==NULL)
  puts("\a\nmemoria insuficiente");
 else
  {
  char s;
  printf("\ninserisci nome:\t");
  scanf("%s",&p->per.nome);
  fflush(stdin);
  puts("\ninserisci cognome:\t");
  gets(p->per.cognome);
  fflush (stdin);
  p=p->datop;
  printf("\nvuoi immettere un altro elemento?(s/n)");
  scanf("%c", &s);
  if(s=='s')
   immetti();
  else {
    fflush(stdin);
    char f;
    printf("vuoi leggere i dati?(s/n)");
    scanf("%c",&f);
    if (f=='s')
     scelta();
    else exit(1);
  }
 }
}
void legginome()
 {
 struct dato *p;
 char name[30];
 printf("\nimmetti il nome da cercare:\t");
 scanf("%s",&name);
 while((strcmp(p->per.nome, name))==0)
  p->datop=p;
 if ((strcmp(p->per.nome, name))!=0)
   {
   printf("\nnome cercato:\t",p->per.nome);
   printf("\ncognome associato:\t",p->per.cognome);
   }
 }
void leggicognome()
 {
 struct dato *p;
 char surname[30];
 printf("\nimmetti il cognome da cercare:\t");
 scanf("%s",&surname);
 while((strcmp(p->per.cognome, surname))==0)
  p->datop=p;
 if ((strcmp(p->per.cognome, surname))!=0)
  {
  printf("\ncognome cercato:\t", p->per.cognome);
  printf("\nnome associato:\t", p->per.nome);
  }
 }
int main()
 {
 char c;
 c=menu();
 switch (c)
   {
   case 'i':
      {
      fflush(stdin);
      immetti();
      }
    break;
   case 'l': scelta();
    break;
   default:;
}   }
void scelta()
 {
  fflush(stdin);
  char c;
  printf("\nimmetti cognome o nome? (c/n)");
  scanf("%c", &c);
  if(c=='c')
   leggicognome();
  else if (c=='n')
   legginome();
   else exit(1);
  }

questo prog. non funziona....
Dunque, nel tuo programma c'e' qualche particolare che non mi va a
genio.
Innanzitutto, l'uso di fflush(stdin), che andrebbe evitato, in quanto
non si sa bene che cosa faccia.
Infatti, questa funzione, applicata a qualsiasi stream di input, ha un
comportamento indefinito e, generamente, non serve, come si potrebbe
pensare, a svuotare il buffer di tastiera.
Inoltre, l'uso si scanf() andrebbe evitato, meglio utilizzare fgets(),
piu' affidabile.
Ho anche notato che fai uso della ricorsione, diretta o indiretta, e
questa, a mio avviso, non e' una buona cosa, in quanto complica
inutilmente il programma.
Mi sono permesso, quindi, di riscriverti il programma in una forma che
a me sembra la piu' corretta.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX  30   /* massimo numero di caratteri per il nome e
                     il cognome */
typedef enum { PER_NOME, PER_COGNOME } tipo_lettura ;
typedef enum { INSERIMENTO, LETTURA, FINE } tipo_operazione ;
struct persona {
                  char nome[MAX] ;
                  char cognome[MAX] ;
                  struct persona * prossimo ;
               } ;
/* la seguente funzione immette un nuovo "record" persona 
   in una lista concatenata, prendendo come punto di
   partenza, il nodo p, passato per riferimento */
void immetti_nuova_persona( const char *nome,
                            const char *cognome,
                            struct persona **p )
{
     if (*p == NULL )
     {
        *p = malloc( sizeof **p ) ;
        (*p)->prossimo = NULL ;
        strcpy( (*p)->nome, nome ) ;
        strcpy( (*p)->cognome, cognome ) ;
     }
     else
       immetti_nuova_persona( nome, cognome, &(*p)->prossimo ) ;
}
/* la seguente funzione chiede un carattere all'utente
   e provvede a svuotare il buffer della tastiera da
   eventuali altri caratteri premuti, nonche' dalla sequenza
   di "a capo" '\n'*/
int chiedi_carattere( void )
{
    int c = toupper( getchar() ), d ;
    d = c ;
    while ( d != '\n' ) d = getchar() ;
    return c ;
}
tipo_operazione scelta_menu( void )
{
    int c ;
    do
    {
       puts( "\nscegliere il genere di operazione :\n" ) ;
       puts( "(i)nserimento" ) ;
       puts( "(l)ettura\n" ) ;
       puts( "(f)ine\n" ) ;
       c = chiedi_carattere() ;
    } while ( c != 'I' && c != 'L' && c != 'F' ) ;
    switch( c )
    {
          case 'I' : return INSERIMENTO ;
          case 'L' : return LETTURA ;
          case 'F' : return FINE ;
    }
}
tipo_lettura scelta_tipo_lettura( void )
{
    int c ;
    do
    {
       puts( "\nscegliere il genere di lettura :\n" ) ;
       puts( "per (n)ome" ) ;
       puts( "per (c)ognome\n" ) ;
       c = chiedi_carattere() ;
    } while ( c != 'N' && c != 'C' ) ;
    return ( c == 'N' ? PER_NOME : PER_COGNOME )  ;
}
/* la seguente funzione esegue una ricerca parametrizzata
   in base al tipo di lettura da effettuare su tutta la
   lista di nomi, prendendo come punto di partenza il nodo
   radice p, passato per copia, in quanto non e' necessario
   modificarne il valore */
void ricerca_persona( tipo_lettura T, struct persona *p )
{
     char stringa[MAX] ;
     unsigned long occorrenze = 0L ;
     if ( T == PER_NOME )
        printf( "inserire il nome da cercare :" ) ;
     else
        printf( "inserire il cognome da cercare :" ) ;
     fgets( stringa, sizeof stringa, stdin ) ;
     for ( ; p != NULL ; p = p->prossimo )
     {
         if ( !strcmp( ( T == PER_NOME ) ? p->nome
                                         : p->cognome,
                                           stringa ) )
         {
            puts( "riferimento trovato :" ) ;
            printf( "nome    : %s", p->nome ) ;
            printf( "cognome : %s\n", p->cognome ) ;
            ++occorrenze ;
            puts( "premi un tasto per continuare la ricerca..." ) ;
            chiedi_carattere() ;
         }
     }
     if ( occorrenze == 0 )
        puts( "\nnessuna occorrenza trovata !" ) ;
     else
        printf("\ntrovate %lu occorrenze.\n", occorrenze ) ;
     puts( "premi un tasto per tornare al menu principale..." ) ;
     chiedi_carattere() ;
}
void chiedi_dati_persona( char *n, char *c )
{
     puts("\ninserisci i dati della nuova persona\n" ) ;
     printf( "nome    : " ) ; fgets( n, MAX, stdin ) ;
     printf( "cognome : " ) ; fgets( c, MAX, stdin ) ;
}
int main()
{
    struct persona *testa_lista = NULL ;
    tipo_operazione op ;
    tipo_lettura lett ;
    char nome[MAX], cognome[MAX] ;
    do
    {
      op = scelta_menu() ;
      if ( op == INSERIMENTO )
      {
         chiedi_dati_persona( nome, cognome ) ;
         immetti_nuova_persona( nome, cognome, &testa_lista ) ;
      }
      else
      if ( op == LETTURA )
      {
         lett = scelta_tipo_lettura() ;
         ricerca_persona( lett, testa_lista ) ;
      }
    } while ( op != FINE ) ;
    return 0 ;
}
--
Andrea Laforgia
andrea_...@bigfoot.com

 inutilmente il programma.
Non è una questione di complicare il programma. Il problema sta nel
fatto di usare la ricorsione in modo sbagliato. 
Commento un pezzetto di codice.
//--------------
void immetti()
 {
 struct dato *p;	//p è locale....
 if((p=(struct dato *) malloc (sizeof(struct dato)))==NULL)
  puts("\a\nmemoria insuficiente");
 else
  {
  char s;
  printf("\ninserisci nome:\t");
  scanf("%s",&p->per.nome);
  fflush(stdin);
  puts("\ninserisci cognome:\t");
  gets(p->per.cognome);
  fflush (stdin);
  p=p->datop;           // ora p punta a p->datop che non è stato
allocato, quindi punta a caso!!!!
  printf("\nvuoi immettere un altro elemento?(s/n)");
  scanf("%c", &s);
  if(s=='s')
   immetti();           //richiami immetti ma p verrà creato un'altra
volta come locale di questa funzione
In pratica ogni volta che chiami immetti() una struttura p ma sono tutte
scollegate tra loro (a parte ol fatto che poi non riesci a liberare la
memoria!).
Ciao,
Enrico
PS: la soluzione? Puoi usare la ricorsione ma prima bisogna capirne il
concetto. Altrimenti è meglio una soluzione semplice come quella
proposta.

 int main()
Manca il
return 0;
alla fine della funzione main().
Buono studio. :-)
EMG

 >Ma ho ancora problemini........C'è qualche paziente che mi spiega perchè


Lista *temp;
Questo e' vero in C++, non in C.
In C non puoi utilizzare il tag (leggi "Lista") della struttura come
identificatore.
Puoi solo scrivere :
struct Lista *testa ;
struct Lista *temp ;
--
Andrea Laforgia
andrea_...@bigfoot.com

 struct Lista *temp ;
Certo, davo per scontato un typedef.
EMG