Newsgroup: it.comp.lang.c
Titolo: Comportamento di fgets

Sono di nuovo io...
questa volta ho da proporvi il seguente problema:
Voglio leggere da input una stringa che memorizzo in ad es.
char input[10]  
ora con l'aiuto del debugger noto che:
1-Se leggo da input con 
	fgets(input,10,stdin)
  ad esempio la parola "villo"	
  nell'array ci va "villo\n\000\000"
2-Se leggo la stessa parola con l'ausilio di scanf("%s",input) invece mi
  ritrovo "villo\000\000\000\000" 
mi sapreste spiegare come faccio ad evitare che fgets mi prenda ache il nl,
visto che a causa di questo poi non riesco ad usare per bene strcmp ( poco
dopo nel codice...)
grazie a tutti...
Vi][oZ
-- 
Per rispondere togliere NONSCASSA da reply-to.

 dopo nel codice...)
Non puoi evitarlo. Lo standard di fgets prescrive che, se riesce a
leggere tutta una linea,  essa ritorni anche \n.
Però non è un problema. Se c'è \n, è sempre in fondo alla stringa, prima
del \0, ovviamente. Verifichi se il penultimo carattere è \n e nel caso
lo sovrascrivi con \0.
ciao.

dopo nel codice...)
Non e' molto efficiente (testala, non l'ho compilata) :
char *mia_fgets( char *s, int size, FILE *fp )
{
     if ( fgets( s, size, fp ) ) 
     {
        for ( ; *s != '\n' ; s++ ) ;
        *(--s) = '\0' ;
     }
     return s ;
}

 mi sapreste spiegare come faccio ad evitare che fgets mi prenda ache il nl,
Non puoi. Devi eliminarlo tu, ad esempio con
input[ strlen( input ) - 1 ] = '\0';
EMG
PS. Non sono sicuro al 100% che l'espressione sopra sia legale.
Eventualmente spezzala in due.

 }
'\n' se c'è è il penultimo carattere ritornato da fgets, quindi basta
fare:
 if (fgets(s, size, fp) != NULL) {
                c = s + strlen(s) - 1;
                if (*c == '\n') *c = '\0';
        }
dove ovviamente char *c;
ciao.

        }
o meglio :
if ( fgets(s, size, fp) ) 
{ 
   int p = strlen( s ) - 1 ;
   if ( s[p] == '\n' )
      s[p] = '\0' ;
}
In questo modo si sfrutta l'ottimizzazione di strlen()


Grazie a tutti. Ieri sera ero arrivato anche io a queste conclusioni e mi
ero scritto una funzione simile a quella proposta da Ip...Aq. (che magari si
puo' chiamare anche in un altro modo...:-) ) ma poi mi e' venuta in mente
strchr() e devo dire che per quello che ho provato fa proprio al caso mio...
Voi che ne dite?
A proposito: ma in questi casi, se quello che mi serve e' solo questo non
conviene usare scanf()??
 bye bye



???
Non vedo nessuna ottimizzazione.
ciao.

 dopo nel codice...)
Toglilo 'a mano'. Ad esempio
     if (fgets(buff, sizeof buff, fp)) {
          char *c;
 
          if ((c = strchr(buff, '\n'))) 
               *c = '\0';
     }
Ciao ciao,
Andrea
-- 
"...Unix, MS-DOS, and Windows NT (also known as the Good, the Bad, and 
 the Ugly)."
(by Matt Welsh)

Non vedo nessuna ottimizzazione.
E' presumibile che strlen() sia scritta in assembly e quindi ottimizza
quello che altrimenti sarebbe un ciclo da compiere a mano.

    if ( s[p] == '\n' )
if    ( *(s+p) == '\n' )
cosi' e' piu' performante......
Ivan Molella

PS. Non sono sicuro al 100% che l'espressione sopra sia legale.
Perche' non dovrebbe esserlo? L'array viene modificato solo dopo che la
funzione strlen() sia terminata.
Saluti,
    Mardy

cosi' e' piu' performante......
Non direi proprio ...


D'accordissimo su questo, infatti l'ho usata anch'io :)
Siccome era in reply al mio post, pensavo ti riferessi ad una
ottimizzazione successiva sulla mia proposta. 
Ti dirņ, sono contento che non mi hai risposto che l'ottimizzazione era
la dichiarazione di p nel blocco...    non so se mi spiego...   ;) 
ciao.

 Ivan Molella
Eh no, proprio no. Se proprio si vuole costruire il puntatore 2 volte if
( s[p] == '\n' ); s[p] = '\0';  conviene usare l'array perchè puoi
ragionevolmente aspettarti che l'indicizzazione sia molto, molto svelta
(quasi certamente è implementata come un indirizzamento base+address in
assembly).
Sommare due puntatori, se ti va bene (ma bene) può andare _quasi_
altrettanto veloce. In pratica sarà sempre più lento.
Comunque non c'è nessun ciclo, ottimizzare non serve poi a molto (a
parte la didattica). Si perde più tempo a chiamarla come funzione.
L'ottimizzazione più importante è metterla inline. 
ciao

 cosi' e' piu' performante......
Credo proprio che sia la stessa identica cosa, invece.
EMG

 funzione strlen() sia terminata.
Si, dovrebbe essere cosě.
EMG

 L'ottimizzazione più importante è metterla inline.
Non e' standard.
Ivan Molella

 dell' array.
Cioè stai dicendo che per referenziare s[p], la cpu in realtà carica in
un registro s[0] e poi somma sizeof(elemento), cioè in questo caso 1, in
un loop, p volte?
Questo non può essere vero. Ovviamente niente può impedire di realizzare
un compilatore che faccia fare questo alla CPU, ma io confido che nessun
compilatore lo faccia perchè ci sono metodi molto più efficienti.
Non mi piace esprimere opinioni e basta. Mi sono scritto le 3 versioni:
con array, s+p, e un solo puntatore, ho compilato con GCC (egcs 2.91.66)
in ambiente linux e ho guardato il codice assembly generato. 
In particolare, ho riscritto il "nucleo" dell'algoritmo così:
s[p] = ( s[p] == '\n' ? '\0': s[c])
e ho ottenuto solo:
1- istruzioni LEA, MOV,
2- il test con: CMPB dato_immediato, (ebx,ecx)
3- poi JE ad un XOR (ecx,ecx) corrispondente a sovrascrivere '\0'. Nota
quanto è sveglio: formalmente sarebbe una MOV, ma siccome c'è un '\0'
come argomento allora usa XOR. Queste cose te le aspetti in un codice
scritto da un essere umano...
4- se invece non c'è '\n' esegue una MOV.
Insomma, se l'avessi fatto io direttamente in assembly mi sarei
stressato molto di più e forse avrei risparmiato un paio di MOV. Forse.
Differenza meno del 5% in termini di tempo.
La versione con i puntatori e la addizione con l'int [sì, è un int. Mi
distraggo un attimo e subito mi bacchetti, eh? Scherzo ;) ]
Per brevità ho semplicemente modificato quella precedente, anche se è
chiaro che non l'avrei scritta così usando s+p:
*(s+p) = ( *(s+p) == '\n' ? '\0': *(s+p))
Ma mi basta guardare come diventa s+p. Non tengo conto del numero totale
di istruzioni. Quello che si vede è che ad ogni s+p corrisponde una add
edx, eax , effettuata ovviamente dopo aver caricato il base ebp. Era
questo che io avevo in mente quando ti ho detto che non era conveniente,
e probabilmente questo intendeva anche I.A. Scritta comunque questa
riga, avrai 2 ricorrenze della s+p e quindi 2 add in più. La versione
senza il test suggerita da EMG non tiene conto del caso in cui fgets
ritorni un buffer pieno ma senza \n
Infine la mia versione:
 *c = ( *c == '\n' ? '\0': *c);
è praticamente identica a quella che usa s[p], l'unica differenza è che
ha 1 istruzione MOV in meno, grazie al fatto che il test viene
effettuato da CMPB dato_immediato, (edx) e non con indirizzamento
base+offset.
Riassumendo: 
1- gli array vengono gestiti con indirizzamento base+offset, molto
efficiente.
2- al massimo si può fare come ho fatto io, cioè usare un puntatore
calcolato una volta per tutte: il risparmio, sia chiaro, è del tutto
trascurabile. Del tutto.
3- i compilatori sono piuttosto svegli. A parte il fatto che la CPU fa
le moltiplicazioni in una singola istruzione, in questo caso non ci sono
nè moltiplicazioni nè addizioni, e per fortuna, prova a pensare quanta
inefficienza nel caso contrario, considera che stiamo usando del codice
frequentissimo in C.
ciao.

 &array[0] + ( i ) ,
Mai sentito parlare di shift? Pensi veramente (se ho capito bene) che il
processore esegua n * m come n + n + n + ... ripetuta m volte?
EMG

Ehm...
ho visto la piccola discussioncina riguardo la cosidetta
'ottimizzazione', volevo solo aggiungere che, al giorno
d'oggi, le tecniche di ottimizzazione si sono notevolmente
raffinate, nonche' integrate nei compilatori.
Alcuni anni fa era sicuramente un'ottima cosa mettere gli
statement in modo da ottimizzare 'ad occhio' il codice,
mentre adesso e' pressoche' inutile.
Addirittura, lavorando personalmente con ottimizzatori su
macchine Alpha, ho visto che il fare 'a mano' una prima
ottimizzazione puo' addirittura risultare controproducente.
Il bello delle nuove tecnologie e' che adesso ci possiamo
concentrare di piu' sul codice e meno su come 'darlo in
pasto' al compilatore, quindi non perdiamo le nostre energie
a dire come e' meglio ottimizzare una parte di codice. Esiste
una specializzazione di laurea solo per quello!
Il discorso resta invece valido se si scrive il codice
'pensando' su quale architettura dovra' girare: nell'esempio
della ricerca di una occorrenza di stringa, qui proposta
giorni or sono, c'e' stato un posting del metodo 'banale',
ovvero mi metto tutto il file in memoria e quindi cerco la
stringa. Su architetture che permettono tale soluzione, e'
una soluzione ottima, mentre su altre, per esempio con
memoria limitata per vari motivi, e' inutilizzabile. Senza
poi parlare di programmi matematici che lavorano sotto
processori a calcolo parallelo o non! In queste situazioni si
puo' giocare la carta dell'esperienza! ^__^
Bye all, - Andrea
-- 
------------------------------------
arimicci @@ aritaly. com  .~~~.  ))
                (\__/)  .'     )  ))
  Andrea        /o o  \/     .~
      Rimicci  {o_,    \    {
                 / ,  , )    \     .
 * Developer *   `~  '-' \    } ))
C C++ cgi miva  _(    (   )_.'
Java           '---..{____}
OS/2 Warp Server for Ebusiness admin
--------- OS/2 V5 "Phoenix" --------

 mentre adesso e' pressoche' inutile.
ecc.ecc.
desidero ringraziarti per questa tua nota. In effetti lo sviluppo preso
dal thread, e il mio spulciare nell'assembly generato dalla compilazione
C, aveva il fine di chiarire alcune idee emerse nella discussione,
tentare di mettere un punto fermo in mezzo a troppe opinioni, almeno
IMHO, s'intende. Tutto qui ;)
Condivido in generale quanto dici, del resto ho esperienza su
architetture parallele, in particolare su clusters per il calcolo.
ciao.