Scanf e passaggio di stringhe a funzioni

di il
6 risposte

Scanf e passaggio di stringhe a funzioni

Salve a tutti!
Ho un problema che non riesco a risolvere in nessun modo.

int ins_product(char wharehouse[][M],float price[],int n,char newproduct[], float pricenewpr){
  int j, k, h, vuoto=2, ritorno=4;
  for(j=0; (j<n)&&(vuoto==2); j++)
     if(price[j]==-2) vuoto=0;
  if(vuoto==0)
     {do{k=-1;
        printf("inserisci il nome del nuovo prodotto non più lungo di %d caratteri\n", M);
         do {k++;
            scanf("%c",&newproduct[k]);}    //questa riga viene saltata
          while(newproduct[k]!='\n');
        if (k>=M+1)
         {printf("Il nome del prodotto è troppo lungo\n");
          ritorno=3;}}
       while(ritorno==3);
     for(h=0; (h<n)&&price[h]!=-2; h++)
       {if((strcmp(wharehouse[h], newproduct))==0)
           ritorno=0;}
     if(ritorno!=0)
       {for(h=0; (h<k-1); h++)
           wharehouse[j][h]=newproduct[h];
        printf("Inserisci il prezzo del nuovo prodotto\n");
        scanf("%f", &price[j]); ritorno=1;}}
    else ritorno=vuoto;
return (ritorno);
}
questa è la funzione dove ho dei problemi: in pratica, passo il vettore newproduct inizializzato nel main nel quale voglio scrivere il nome di un prodotto, e per farlo utilizzo scanf("%c",ecc), come faccio di solito, solo che stavolta mi da problemi.
In pratica il programma "salta" la scanf: facendo il debug, con un breakpoint all'inizio del do, vedo che la "freccetta" passa allegramente sopra l'istruzione di input, controlla la condizione del while e la trova falsa, saltandone fuori. Il problema è che il vettore è vuoto (o così dovrebbe essere). Ho provato ad inizializzarlo in ogni modo, il risultato è lo stesso. Con getchar() è la stessa cosa, con scanf("%S"ecc) ancora peggio. Ho provato gets(newproduct) e così mi funziona, solo che io preferirei inserire carattere per carattere (e capire cosa sto sbagliando). Sapreste aiutarmi?
Ho provato a riscrivere la funzione come programma a parte, in un altro progetto, e funziona! e sta cosa non riesco a spiegarmela.
Grazie in anticipo a chi vorrà rispondermi! Buona serata.

6 Risposte

  • Re: Scanf e passaggio di stringhe a funzioni

    Il problema è principalmente dovuto all'annosa questione della mancata pulizia del buffer di tastiera, un problema che si trascina dai primi anni Ottanta in una insensata discrasia tra mondo Unix e PC DOS/Windows.

    Premesso che l'uso di scanf() è di fatto del tutto sconsigliato per l'input di stringhe e caratteri, fatto ormai sviscerato e approfondito in una buona dozzina di testi e in migliaia di discussioni, si deve come minimo fare ricorso ad una funzione siffatta per lo svuotamento forzato del buffer tra due o più chiamate successive di scanf:
    
        void ClearKeyboardBuffer(void)
        {
            char ch;
            do
            {
                ch = getchar();
            } while (('\n' != ch) && (EOF != ch));
            /* versione sintetica: while (((ch = getchar()) != '\n') && (ch != EOF)); */
        }
    
  • Re: Scanf e passaggio di stringhe a funzioni

    Grazie M.A.W. 1968!
    E' la prima volta che sento parlare di problemi legati alla scanf: il nostro professore non ci ha detto nulla a proposito [sto al primo anno di ingegneria meccanica]

    quindi sarebbe meglio adesso (e in futuro) di "pensare" il codice direttamente senza scanf? mi ci ero affezionato perché coi numeri funziona molto bene, con i caratteri un po' meno, però pensavo fosse un problema mio.

    Ad esempio utilizzare gets e poi la funzione strlen per la lunghezza (eliminando di fatto il contatore "k") potrebbe essere utile?
  • Re: Scanf e passaggio di stringhe a funzioni

    Molti docenti evitano di discutere taluni aspetti "nascosti" delle funzioni, esposti peraltro molto chiaramente in letteratura, probabilmente per timore di confondere le idee e/o per non perdere la comodità e l'immediatezza didattica di ricorrere a certe funzioni-segnaposto, ancorché ampiamente sconsigliate nel codice professionale.

    Purtroppo anche gets() è fattualmente deprecata nei manuali di stile (vedi la seconda parte della bibliografia linkata): molto meglio ricorrere alla fgets() su stdin per l'unput di stringhe, con una serie di vantaggi in robustezza, efficienza e controllo del numero massimo di caratteri immessi nel buffer.
    Naturalmente è sempre possibile (e talora necessario) continuare ad abbinare l'idioma segnalato per la pulizia del keyboard buffer, come suggerisce il seguente esempio.
    
        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
    
        typedef enum {FALSE, TRUE} boole_t;
    
        #define MAX_LEN 20
    
        void ClearKeyboardBuffer(void)
        {
            char ch;
            while ((ch = getchar() != '\n') && (ch != EOF));
        }
    
        boole_t get_string(char **buff, size_t max_chars_to_read, boole_t purge, boole_t trim_CRLF)
        {
            char *p;
            *buff = (char *)malloc(max_chars_to_read +1);
            if (NULL == *buff)
            {
                return FALSE;
            }
    
            if (NULL == fgets(*buff, max_chars_to_read +1, stdin))
            {
                free(*buff);
                return FALSE;
            }
    
            p = strrchr(*buff, '\n');
            if (NULL != p)
            {
                if (trim_CRLF)
                {
                    *p = '\0';
                }
            }
            else
            {
                if (purge)
                {
                    ClearKeyboardBuffer();
                }
            }
    
            return TRUE;
        }
    
        int main()
        {
            char *b;
            boole_t res;
    
            printf("Immetti una stringa (max %d caratteri): ", MAX_LEN);
            res = get_string(&b, MAX_LEN, FALSE, TRUE);
            if (res)
            {
                printf("Stringa immessa: (%d) \"%s\"", strlen(b), b);
                free(b);
            }
            ClearKeyboardBuffer();
    
            printf("\nImmetti una stringa (max %d caratteri): ", MAX_LEN);
            res = get_string(&b, MAX_LEN, TRUE, FALSE);
            if (res)
            {
                printf("Stringa immessa: (%d) \"%s\"", strlen(b), b);
                free(b);
            }
    
            return EXIT_SUCCESS;
        }
    
    L'esempio è tratto da questo thread, dove era stato presentato in forma volutamente incompleta per stimolare una riflessione dell'OP su alcune necessarie modifiche. Mi scuso in anticipo per eventuali errori commessi nel risistemarlo "al volo" su uno smartphone.
  • Re: Scanf e passaggio di stringhe a funzioni

    M.A.W. 1968 ha scritto:


    Molti docenti evitano di discutere taluni aspetti "nascosti" delle funzioni, esposti peraltro molto chiaramente in letteratura, probabilmente per timore di confondere le idee e/o per non perdere la comodità e l'immediatezza didattica di ricorrere a certe funzioni-segnaposto, ancorché ampiamente sconsigliate nel codice professionale.

    Purtroppo anche gets() è fattualmente deprecata nei manuali di stile (vedi la seconda parte della bibliografia linkata): molto meglio ricorrere alla fgets() su stdin per l'unput di stringhe, con una serie di vantaggi in robustezza, efficienza e controllo del numero massimo di caratteri immessi nel buffer.
    Naturalmente è sempre possibile (e talora necessario) continuare ad abbinare l'idioma segnalato per la pulizia del keyboard buffer, come suggerisce il seguente esempio.
    
        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
    
        typedef enum {FALSE, TRUE} boole_t;
    
        #define MAX_LEN 20
    
        void ClearKeyboardBuffer(void)
        {
            char ch;
            while ((ch = getchar() != '\n') && (ch != EOF));
        }
    
        boole_t get_string(char **buff, size_t max_chars_to_read, boole_t purge, boole_t trim_CRLF)
        {
            char *p;
            *buff = (char *)malloc(max_chars_to_read +1);
            if (NULL == *buff)
            {
                return FALSE;
            }
    
            if (NULL == fgets(*buff, max_chars_to_read +1, stdin))
            {
                free(*buff);
                return FALSE;
            }
    
            p = strrchr(*buff, '\n');
            if (NULL != p)
            {
                if (trim_CRLF)
                {
                    *p = '\0';
                }
            }
            else
            {
                if (purge)
                {
                    ClearKeyboardBuffer();
                }
            }
    
            return TRUE;
        }
    
        int main()
        {
            char *b;
            boole_t res;
    
            printf("Immetti una stringa (max %d caratteri): ", MAX_LEN);
            res = get_string(&b, MAX_LEN, FALSE, TRUE);
            if (res)
            {
                printf("Stringa immessa: (%d) \"%s\"", strlen(b), b);
                free(b);
            }
            ClearKeyboardBuffer();
    
            printf("\nImmetti una stringa (max %d caratteri): ", MAX_LEN);
            res = get_string(&b, MAX_LEN, TRUE, FALSE);
            if (res)
            {
                printf("Stringa immessa: (%d) \"%s\"", strlen(b), b);
                free(b);
            }
    
            return EXIT_SUCCESS;
        }
    
    L'esempio è tratto da questo thread, dove era stato presentato in forma volutamente incompleta per stimolare una riflessione dell'OP su alcune necessarie modifiche. Mi scuso in anticipo per eventuali errori commessi nel risistemarlo "al volo" su uno smartphone.

    Ciao io ho un errore simile.
    Premetto che sto facendo un progetto per l'università e ho come compito quello di fare una libreria (sempre in linguaggio c).
    Tra le tante funzioni create , c'è quella dell'inserimento di un libro. Al momento dell'inserimento chiedo all'utente il nome del libro e l'autore. Ovviamente tutti e due campi char in un array di un tot di elementi dettati dal prof. Come posso impostare il discorso dello spazio? Se il titolo è Il piccolo principe , come faccio a fargli salvare questo ,compresi gli spazi , nel campo corretto?
  • Re: Scanf e passaggio di stringhe a funzioni

    Up!
  • Re: Scanf e passaggio di stringhe a funzioni

    @paloppa ... perché ti inserisci in un thread di un altro utente? Creane uno tuo ...
Devi accedere o registrarti per scrivere nel forum
6 risposte