Acquisizione stringa da tastiera senza '\n' [C]

di il
11 risposte

Acquisizione stringa da tastiera senza '\n' [C]

Buongiorno a tutti.

Come potete leggere dal titolo cerco di acquisire dati da tastiera e vorrei eliminare il carattere newline. Nella fase di popolamento di una struttura dati, ovvero mentre inserisco nome, congome...., potrei utilizzare la gets() però ho visto che non fa alcun controllo sulla dimensione del buffer e quindi uso fgets.
Utilizzando fgets però mi porto dietro anche '\n'. Questo è quello che ho capito.

Ora cercando in rete e smanettando un pò, la soluzione che ho implementato è questa:
void leggi_dato_stdin(char *destinazione, int n, FILE *stdin)
{
  char ctrl;
  char buffer[MAX];
  fgets(buffer,n,stdin);
  if(buffer[strlen(buffer)-1]=='\n') buffer[strlen(buffer)-1]='\0';
  else while(fgetc(stdin!='\n');
  strcpy(destinazione,buffer);
}
La stessa medesima funzione può essere usata anche in lettura da un file e popolare così la struttura dati.
la funzione viene chiamata ogni qualvolta vi è un inserimento dei dati della struttura sopracitata:
void nuova_persona(persona **head)
{
  int ctrl;
 persona *nuova=NULL;
 nuova=(persona*)malloc(sizeof(persona));
 assert(nuova!=NULL);
 printf("Inserire i dati della nuova persona: ");
 fflush(stdin);
 printf("\nCognome: ");
 leggi_dato_stdin(nuova->cognome,31,stdin);
 printf("\nNome: ");
 leggi_dato_stdin(nuova->nome,31,stdin);
 printf("\nEmail: ");
 do
 {
   leggi_dato_stdin(nuova->email,31,stdin);
   ctrl=chiocciola(nuova->email);
 }while(ctrl!=1);
 printf("Telefono: ");
 scanf("%d",&nuova->telefono);
 fflush(stdin);
 inserisci_persona(head,nuova);
}
Quando compilo però mi da un errore ovvero:

- error: expected ')' before '&' token
void leggi_dato_stdin(char *destinazione, int n, FILE *stdin);

Cosa sbaglio?

Vi ringrazio in anticipo

11 Risposte

  • Re: Acquisizione stringa da tastiera senza '\n' [C]

    else while(fgetc(stdin!='\n');
    Manca una parentesi tonda.
  • Re: Acquisizione stringa da tastiera senza '\n' [C]

    Ho corretto, ma neanche me lo aveva segnalato quell'errore. Ma il problema persiste..
  • Re: Acquisizione stringa da tastiera senza '\n' [C]

    Quale problema? Posta il codice completo.
  • Re: Acquisizione stringa da tastiera senza '\n' [C]

    Andrea Quaglia ha scritto:


    Quale problema? Posta il codice completo.
    Quello per cui ho scritto il post
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    
    #define MAX 31
    
    //-------------------------------------------------------------------------------------------
    //------------------------------------------------STRUTTURE DATI-----------------------------
    //-------------------------------------------------------------------------------------------
    typedef struct s_persona
    {
      char cognome[MAX];
      char nome[MAX];
      char email[MAX];
      unsigned int telefono;
      struct s_persona *next;
    }persona;
    
    //--------------------------------------------------------------------------------------------------
    //-------------------------------------------PROTOTIPI FUNZIONI-------------------------------------
    //--------------------------------------------------------------------------------------------------
    void nuova_persona(persona **head);
    void inserisci_persona(persona **head, persona *nuova);
    void leggi_dato_stdin(char *destinazione, int n, FILE *stdin);
    void stampa_lista(persona *head);
    //--------------------------------------------------------------------------------------------------
    //------------------------------------------------MAIN----------------------------------------------
    //--------------------------------------------------------------------------------------------------
    int main()
    {
      char cognome[MAX],nome[MAX];
      int i,dim,scelta;
      persona *head=NULL;
      do
      {
        system("CLS");
        printf("\n**MENU ESERCIZIO LISTE**\n");
        printf("1. Inserisci Persona nella Lista\n");
        printf("2. Stampa Lista\n");
        printf("3. Cerca Persona nella Lista\n");
        printf("4. Cencella Persona dalla Lista\n");
        printf("5. Cancella Lista\n");
        printf("6. Esci\n");
        printf("7. Salva Lista in File\n");
        printf("8. Carica Lista da File\n\n");
        printf("Scegli un'opzione del menù: ");
        scanf("%d",&scelta);
        switch (scelta)
        {
          case 1: system("CLS");
                  printf("\n***INSERIMENTO PERSONA IN LISTA***\n");
                  printf("\nNumero di persona da inserire in lista:");
                  scanf("%d",&dim);
                  for(i=0;i<dim;i++)
                  {
                    nuova_persona(&head);
                  }
                  scelta=9;
                  printf("\n");
                  system("PAUSE");
                  break;
          case 2: system("CLS");
                  printf("\n*** STAMPA PERSONE IN LISTA***\n");
                  printf("\n\nCognome\t\tNome\n");
                  stampa_lista(head);
                  if(head==NULL)
                  printf("\nLa lista è vuota.\n");
                  scelta=9;
                  printf("\n");
                  system("PAUSE");
                  break;
        }
      }while(scelta<1 || scelta >8);
    
    }
    
    //--------------------------------------------------------------------------------------------------
    //----------------------------------------------DEFINIZIONE FUNZIONI--------------------------------
    //--------------------------------------------------------------------------------------------------
    void nuova_persona(persona **head)
    {
      int ctrl;
     persona *nuova=NULL;
     nuova=(persona*)malloc(sizeof(persona));
     assert(nuova!=NULL);
     printf("Inserire i dati della nuova persona: ");
     fflush(stdin);
     printf("\nCognome: ");
     leggi_dato_stdin(nuova->cognome,31,stdin);
     printf("\nNome: ");
     leggi_dato_stdin(nuova->nome,31,stdin);
     printf("\nEmail: ");
     do
     {
       leggi_dato_stdin(nuova->email,31,stdin);
       ctrl=chiocciola(nuova->email);
     }while(ctrl!=1);
     printf("Telefono: ");
     scanf("%d",&nuova->telefono);
     fflush(stdin);
     inserisci_persona(head,nuova);
    }
    
    void leggi_dato_stdin(char *destinazione, int n, FILE *stdin)
    {
      char ctrl;
      char buffer[MAX];
      fgets(buffer,n,stdin);
      if(buffer[strlen(buffer)-1]=='\n') buffer[strlen(buffer)-1]='\0';
      else while(fgetc(stdin!='\n'));
      strcpy(destinazione,buffer);
    }
    
    int chiocciola(char *email)
    {
      int i;
      for(i=0;i<email[i]!='@';i++)
      {
        if(email[i]=='@')
          return 1;
        else
        {
          printf("\n!ERRORE! -> Reinserire la email, '@' mancante..\n");
          system("PAUSE");
          return 0;
        }
      }
    }
    
    void inserisci_persona(persona **head, persona *nuova)
    {
      int ctrl;
      persona *prec=NULL, *corr=*head;
      while(corr!=NULL && ((ctrl=strcmp(nuova->cognome,corr->cognome))>0 ||
      (!ctrl && strcmp(nuova->nome,corr->nome)>0)))
      {
        prec=corr;
        corr=corr->next;
      }
      if(prec)
      {
        prec=corr;
        corr=corr->next;
      }
      else
      {
          *head=nuova;
      }
      nuova->next=corr;
    }
    
    void stampa_lista(persona *head)
    {
      while(head!=NULL)
      {
        printf("\n%s %s\n%s\n%d\n",head->cognome,head->nome,head->email,head->telefono);
        head=head->next;
      }
      return;
    }
    Quando compilo il terminale mi dice:
    error: expected ')' before '&' token
    void leggi_dato_stdin(char *destinazione, int n, FILE *stdin)
  • Re: Acquisizione stringa da tastiera senza '\n' [C]

    gcc -Wall -c "Esempio.c" (nel direttorio: /home/andrea/SviluppoSW)
    Esempio.c: In function ‘main’:
    Esempio.c:32:21: warning: unused variable ‘nome’ [-Wunused-variable]
       char cognome[MAX],nome[MAX];
                         ^
    Esempio.c:32:8: warning: unused variable ‘cognome’ [-Wunused-variable]
       char cognome[MAX],nome[MAX];
            ^
    Esempio.c: In function ‘nuova_persona’:
    Esempio.c:97:4: warning: implicit declaration of function ‘chiocciola’ [-Wimplicit-function-declaration]
        ctrl=chiocciola(nuova->email);
        ^
    Esempio.c: In function ‘leggi_dato_stdin’:
    Esempio.c:111:25: warning: comparison between pointer and integer
       else while(fgetc(stdin!='\n'));
                             ^
    Esempio.c:111:20: warning: passing argument 1 of ‘fgetc’ makes pointer from integer without a cast
       else while(fgetc(stdin!='\n'));
                        ^
    In file included from Esempio.c:1:0:
    /usr/include/stdio.h:531:12: note: expected ‘struct FILE *’ but argument is of type ‘int’
     extern int fgetc (FILE *__stream);
                ^
    Esempio.c:107:8: warning: unused variable ‘ctrl’ [-Wunused-variable]
       char ctrl;
            ^
    Esempio.c: In function ‘chiocciola’:
    Esempio.c:118:12: warning: suggest parentheses around comparison in operand of ‘!=’ [-Wparentheses]
       for(i=0;i<email[i]!='@';i++)
                ^
    Esempio.c: In function ‘main’:
    Esempio.c:76:1: warning: control reaches end of non-void function [-Wreturn-type]
     }
     ^
    Compilazione terminata correttamente.
    
    A me sembra che tu abbia più di un problema...
    Implicit declaration: se la funzione che usi la definisci dopo, la devi dichiarare prima.
    Poi, ti avevo detto che mancava una parentesi, tu l'hai messa, ma nel posto sbagliato! Te lo dicono anche i messaggi di warning relativi a quella linea di codice
    Esempio.c:111:25: warning: comparison between pointer and integer
       else while(fgetc(stdin!='\n'));
                             ^
    Esempio.c:111:20: warning: passing argument 1 of ‘fgetc’ makes pointer from integer without a cast
       else while(fgetc(stdin!='\n'));
                        ^
    In file included from Esempio.c:1:0:
    /usr/include/stdio.h:531:12: note: expected ‘struct FILE *’ but argument is of type ‘int’
     extern int fgetc (FILE *__stream);
    Siccome oggi ho un momento di folle bontà, ti scrivo la riga corretta:
    else while(fgetc(stdin)!='\n');
    Gli altri warning (che sono molto importanti, perché rendono il comportamento del programma assai imprevedibile rispetto a quello che vorresti), te li lascio come utile esercizio.
  • Re: Acquisizione stringa da tastiera senza '\n' [C]

    Ti ho postato la versione sbagliata del codice, scusami. La funzione chiocciola l'avevo già corretta, e comunque, come puoi vedere dal codice, so che se definisco dopo una funzione, la devo dichiarare prima.

    Gli unici errori che mi segna sono:
    In file included from persona.c:1:0:
    persona.c:25:56: error: expected ')' before '&' token
     void leggi_dato_stdin(char *destinazione, int n, FILE *stdin);
                                                            ^
    persona.c: In function 'nuova_persona':
    persona.c:91:2: warning: implicit declaration of function 'leggi_dato_stdin' [-Wimplicit-function-declaration]
      leggi_dato_stdin(nuova->cognome,31,stdin);
      ^~~~~~~~~~~~~~~~
    In file included from persona.c:1:0:
    persona.c: At top level:
    persona.c:106:56: error: expected ')' before '&' token
     void leggi_dato_stdin(char *destinazione, int n, FILE *stdin)
    Il codice completo:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    
    #define MAX 31
    
    //-------------------------------------------------------------------------------------------
    //------------------------------------------------STRUTTURE DATI-----------------------------
    //-------------------------------------------------------------------------------------------
    typedef struct s_persona
    {
      char cognome[MAX];
      char nome[MAX];
      char email[MAX];
      unsigned int telefono;
      struct s_persona *next;
    }persona;
    
    //--------------------------------------------------------------------------------------------------
    //-------------------------------------------PROTOTIPI FUNZIONI-------------------------------------
    //--------------------------------------------------------------------------------------------------
    void nuova_persona(persona **head);
    void inserisci_persona(persona **head, persona *nuova);
    void leggi_dato_stdin(char *destinazione, int n, FILE *stdin);
    int chiocciola(char *email);
    void stampa_lista(persona *head);
    //--------------------------------------------------------------------------------------------------
    //------------------------------------------------MAIN----------------------------------------------
    //--------------------------------------------------------------------------------------------------
    int main()
    {
      char cognome[MAX],nome[MAX];
      int i,dim,scelta;
      persona *head=NULL;
      do
      {
        system("CLS");
        printf("\n**MENU ESERCIZIO LISTE**\n");
        printf("1. Inserisci Persona nella Lista\n");
        printf("2. Stampa Lista\n");
        printf("3. Cerca Persona nella Lista\n");
        printf("4. Cencella Persona dalla Lista\n");
        printf("5. Cancella Lista\n");
        printf("6. Esci\n");
        printf("7. Salva Lista in File\n");
        printf("8. Carica Lista da File\n\n");
        printf("Scegli un'opzione del menù: ");
        scanf("%d",&scelta);
        switch (scelta)
        {
          case 1: system("CLS");
                  printf("\n***INSERIMENTO PERSONA IN LISTA***\n");
                  printf("\nNumero di persona da inserire in lista:");
                  scanf("%d",&dim);
                  for(i=0;i<dim;i++)
                  {
                    nuova_persona(&head);
                  }
                  scelta=9;
                  printf("\n");
                  system("PAUSE");
                  break;
          case 2: system("CLS");
                  printf("\n*** STAMPA PERSONE IN LISTA***\n");
                  printf("\n\nCognome\t\tNome\n");
                  stampa_lista(head);
                  if(head==NULL)
                  printf("\nLa lista è vuota.\n");
                  scelta=9;
                  printf("\n");
                  system("PAUSE");
                  break;
        }
      }while(scelta<1 || scelta >8);
    
    }
    
    //--------------------------------------------------------------------------------------------------
    //----------------------------------------------DEFINIZIONE FUNZIONI--------------------------------
    //--------------------------------------------------------------------------------------------------
    void nuova_persona(persona **head)
    {
     int ctrl;
     persona *nuova=NULL;
     nuova=(persona*)malloc(sizeof(persona));
     assert(nuova!=NULL);
     printf("Inserire i dati della nuova persona: ");
     fflush(stdin);
     printf("\nCognome: ");
     leggi_dato_stdin(nuova->cognome,31,stdin);
     printf("\nNome: ");
     leggi_dato_stdin(nuova->nome,31,stdin);
     printf("\nEmail: ");
     do
     {
       leggi_dato_stdin(nuova->email,31,stdin);
       ctrl=chiocciola(nuova->email);
     }while(ctrl!=1);
     printf("Telefono: ");
     scanf("%d",&nuova->telefono);
     fflush(stdin);
     inserisci_persona(head,nuova);
    }
    
    void leggi_dato_stdin(char *destinazione, int n, FILE *stdin)
    {
      char ctrl;
      char buffer[MAX];
      fgets(buffer,n,stdin);
      if(buffer[strlen(buffer)-1]=='\n') buffer[strlen(buffer)-1]='\0';
      else while(fgetc(stdin)!='\n');
      strcpy(destinazione,buffer);
    }
    
    int chiocciola(char *email)
    {
      int i;
      for(i=0;email[i]!='@';i++)
      {
        if(email[i]=='@')
          return 1;
        else
        {
          printf("\n!ERRORE! -> Reinserire la email, '@' mancante..\n");
          system("PAUSE");
          return 0;
        }
      }
    }
    
    void inserisci_persona(persona **head, persona *nuova)
    {
      int ctrl;
      persona *prec=NULL, *corr=*head;
      while(corr!=NULL && ((ctrl=strcmp(nuova->cognome,corr->cognome))>0 ||
      (!ctrl && strcmp(nuova->nome,corr->nome)>0)))
      {
        prec=corr;
        corr=corr->next;
      }
      if(prec)
      {
        prec=corr;
        corr=corr->next;
      }
      else
      {
        *head=nuova;
      }
      nuova->next=corr;
    }
    
    void stampa_lista(persona *head)
    {
      while(head!=NULL)
      {
        printf("\n%s %s\n%s\n%d\n",head->cognome,head->nome,head->email,head->telefono);
        head=head->next;
      }
      return;
    }
    
  • Re: Acquisizione stringa da tastiera senza '\n' [C]

    Ho copiaincollato il tuo codice e l'ho compilato: non ho i tuoi errori, sicuro di compilare il codice giusto?
    C'è un solo problema serio:
    ctrl=chiocciola(nuova->email);
    Se guardi i messaggi di warning leggi
    persona.c:130:1: warning: control reaches end of non-void function [-Wreturn-type]
    cioè hai una funzione che ritorna int ma non c'è il return, quindi secondo te che cosa c'è nella variabile ctrl dopo che la funzione chiocciola è terminata (il warning si riferisce al fatto che nessuno dei due return che hai messo potrebbe essere raggiungibile)?
  • Re: Acquisizione stringa da tastiera senza '\n' [C]

    Andrea Quaglia ha scritto:


    cioè hai una funzione che ritorna int ma non c'è il return, quindi secondo te che cosa c'è nella variabile ctrl dopo che la funzione chiocciola è terminata (il warning si riferisce al fatto che nessuno dei due return che hai messo potrebbe essere raggiungibile)?
    int chiocciola(char *email)
    {
      int i;
      for(i=0;email[i]!='@';i++)
      {
        if(email[i]=='@')
          return 1;   <------------
        else
        {
          printf("\n!ERRORE! -> Reinserire la email, '@' mancante..\n");
          system("PAUSE");
          return 0;    <------------
        }
      }
    }
    Scusami non sono questi i return di cui parli? Sono confuso

    EDIT:
    Se scrivo la funzione come segue puoi verificare se ti da ancora errore? Perchè purtroppo a me non lo segnala. Soprattutto non capisco come mai non ci da gli stessi errori.
    int chiocciola(char *email)
    {
      int i;
      for(i=0;email[i]!='@';i++);
      if(email[i]=='@')
        return 1;
      else
      {
        printf("\n!ERRORE! -> Reinserire la email, '@' mancante..\n");
        system("PAUSE");
        return 0;
      }
    }
    Però mi sarebbe molto d'aiuto innanzitutto risolvere il problema dell'inserimento in stringa senza \n e non so perchè la funzione "void leggi_dato_stdin(char *destinazione, int n, FILE *stdin)" mi da errore.
  • Re: Acquisizione stringa da tastiera senza '\n' [C]

    La programmazione andrebbe sempre fatta con modalità 'difensiva', cioè evitare assolutamente di scrivere codice che potrebbe portare guai. Se la funzione prevede un valore di ritorno, l'ultima istruzione prima della parentesi di chiusura dovrebbe essere appunto il return di qualcosa. Mettere un return dentro un ciclo for non è vietato, ma potresti trovarti con problemi se per caso il ciclo for non viene eseguito.
    Hai messo 2 versioni della funzione 'chiocciola': la prima non funziona (ripete sempre 'ERRORE!...') perchè il ciclo for testa solo il primo carattere della stringa 'email', che se non è '@', passa nell'else dell'if e fa ritornare 0. Se scrivi un indirizzo tipo '@pippo.it', il ciclo for non viene eseguito e la funzione non ritorna niente, ovvero lascia la variabile 'ctrl' invariata, ovvero con un valore a caso, dato che non è inizializzata (adesso sono con Visual Studio 2012 in modalità debug ed il giro è quello, ctrl viene inizializzata a 0). La seconda funziona solo se la '@' c'è, perchè il ciclo for si ferma solo quando la trova, e se non c'è continua all'infinito (ovvero sino a quando i > MAXINT o email non la fa fuori del vaso... Ho eseguito un paio di volte il programma e una volta l'indice i si è fermato a 3166, l'altra a 230 perchè evidentemente ha trovato un '@').
    Per quanto riguarda la funzione
    void leggi_dato_stdin(char *destinazione, int n, FILE *stdin)
    la dichiarazione è sbagliata: non devi mettere stdin (ed in genere i nomi delle variabili non si mettono).
    void leggi_dato_stdin(char *, int , FILE *);
    Poi nelle chiamate alla funzione devi mettere solo stdin:
    leggi_dato_stdin(nuova->cognome,31, stdin);
    leggi_dato_stdin(nuova->nome,31, stdin);
    leggi_dato_stdin(nuova->email,31, stdin);
    La funzione viene poi definita così:
    void leggi_dato_stdin(char *destinazione, int n, FILE *flusso_io)
    {
      char ctrl;
      char buffer[MAX];
      fgets(buffer,n, flusso_io);
      if(buffer[strlen(buffer)-1]=='\n') buffer[strlen(buffer)-1]='\0';
      else while(fgetc(stdin)!='\n');
      strcpy(destinazione,buffer);
    }
    Comunque ci sono molte ridondanze inutili:
    • stdin non serve passarlo come parametro (a meno che tu non voglia usare la funzione per leggere da un altro stream, ma allora devi correggere la fgetc)
    • il parametro n (dimensione massima del buffer) non serve, perché hai già definito la costante MAX
    PS: che compilatore stai usando?
  • Re: Acquisizione stringa da tastiera senza '\n' [C]

    Allora per quanto riguarda la funzione chiocciola confermo che non funziona. La riguardo e vedo di scriverne una che sia in grado di svolgere la sua funzione e che sintatticamente sia corretta in modo tale da non avere problemi con i return, in caso se posso te la faccio rivedere.
    Per quanto riguarda la funzione "leggi_stato_stdin":

    - Ho effettuato le modifiche da te indicate e sembra funzionare tutto correttamente.

    - Posso sapere perchè non conviene dichiarare prima le variabili?

    - Avevo passato stdin perchè in questo stesso codice questa funzione verrà riscritta per poi leggere da file, a meno che non ci sia un modo per scrivere solo un prototipo di funzione che mi consenta di farla funzionare sia se legge da stdin o da file.

    - Per quanto riguarda il parametro n, l'ho inserito perchè mi è capitato spesso che le dimensioni delle stringhe non sono tutte uguali, a questo punto indico come "buffer max" la dimensione massima che posso avere nel codice e con "n" la dimensione effettiva che mi serve in quel momento da acquisire. (Spero di essere stato chiaro)

    Sto utilizzando un editor di testo "ATOM" e compilo direttamente su terminale.
  • Re: Acquisizione stringa da tastiera senza '\n' [C]

    Per quanto riguarda la funzione chiocciola, è molto semplice da fare: crea una variabile chiocciola_trovata e mettila a 0; scorri tutti i caratteri fino a trovare la chiocciola, se la trovi metti chiocciola_trovata a 1; quando arrivi al fondo della stringa, ritorni chiocciola_trovata.
    Posso sapere perchè non conviene dichiarare prima le variabili?
    Perché al compilatore non interessano in fase di dichiarazione, gli serve solo sapere come è fatta la funzione, in modo da poter controllare la corrispondenza dei parametri e del valore ritornato.
    Avevo passato stdin perchè in questo stesso codice questa funzione verrà riscritta per poi leggere da file, a meno che non ci sia un modo per scrivere solo un prototipo di funzione che mi consenta di farla funzionare sia se legge da stdin o da file.
    Allora la funzione "leggi_dato_stdin" la devi rivedere leggermente.
Devi accedere o registrarti per scrivere nel forum
11 risposte