2013-05-06 24 views
8

Sono nuovo alla programmazione, partendo da Objective-C ma ho deciso di tornare alle basi prima di progredire ulteriormente. Sto passando un po 'di tempo in C, e sto lottando attraverso la confusione del puntatore. La mia domanda è su come K & R dice che fgets è implementato (p165, 2a ed.) Il codice qui sotto è diretto dal testo con un paio di miei commenti.implementazione di fgets (K & R)

char* fgets(char* s, int n, FILE *iop) 
{ 
    register int c; 
    register char* cs; 
    cs = s; 

    while(--n > 0 && (c = getc(iop)) != EOF) 
    { 
    // put the input char into the current pointer position, then increment it 
    // if a newline entered, break 
    if((*cs++ = c) == '\n') 
     break;   
    } 

    *cs = '\0'; 
    return (c == EOF && cs == s) ? NULL : s; 
} 

1) Passiamo un char * s alla funzione fgets, alla cui posizione abbiamo memorizzare l'input dell'utente. Perché è necessario dichiarare il char * cs locale e quindi inizializzarlo su s? Perché non possiamo manipolare/aggiungere direttamente a s all'interno dell'istruzione if? Vedere come cs è inizializzato al punto s, non sta aggiungendo i caratteri in cs esattamente la stessa cosa?

2) Legato con il precedente ... Quando la funzione ritorna, viene effettuato un test per vedere se cs == s. Perché è necessario?

Penso che possa mancare qualcosa di fondamentale: ho controllato SO e Google ma non riesco a capirlo. Grazie!

+2

"Iniziare con Objective-C ma ho deciso di tornare alle basi prima di progredire ulteriormente" - eccellente, ** ogni principiante dovrebbe farlo. ** –

+1

Stavo cominciando a sentire che stavo colpendo una specie di falcata in Obj-C. Da quando torno a C mi sento di nuovo un klutz completo, ma nonostante abbia ripetutamente sbattuto la testa contro i difetti di segmentazione e il comportamento strano del programma, ne vale sicuramente la pena. – drjimmie1976

+0

Ne vale sicuramente la pena. La padronanza di C è inevitabile per la comprensione dell'Obiettivo-C. –

risposta

7

È a causa del controllo sull'ultima riga, cs == s. Questo confronto controlla il puntatore modificato cs rispetto all'originale s per vedere se abbiamo letto qualsiasi carattere. Se non lo abbiamo, restituiamo NULL.

Utilizzando viene mantenuto il puntatore originale s. Se s sono stati manipolati direttamente (*s++ anziché *cs++), dovremmo trovare un altro modo per verificare se alcuni caratteri sono stati letti.

Si può anche sostenere che è una buona pratica lasciare solo i parametri di funzione e trattarli come const. Alcuni programmatori seguono questa pratica come un modo per migliorare la chiarezza del codice.

+0

Grazie mille John. Ciò rende l'intenzione più chiara, ma ancora un paio di domande se posso ... quando "cs" è assegnato con "cs = s", ho pensato che i puntatori ora puntassero esattamente alla stessa area di memoria; quindi l'esecuzione di '* cs ++' sarebbe esattamente equivalente a '* s ++'. Questa supposizione è sbagliata? – drjimmie1976

+0

Scusa il mio commento è scaduto, e sto facendo anche il commento sul markup sbagliato ... È per questo che non ho capito la battuta finale. Ho pensato che visto che entrambi i puntatori erano "condivisi", allora sarebbero identici quando l'espressione c == cs valutata. Grazie in anticipo. – drjimmie1976

+0

@ GasMan14 Indicano lo stesso indirizzo dopo l'assegnazione, è corretto. '* cs ++' non modifica 's', comunque. Assicurati di aver compreso la precedenza: '* cs ++' è uguale a '* (cs ++)' not '(* cs) ++'. 'cs ++' incrementa 'cs', facendo in modo che punti al prossimo indirizzo, quindi al' * 'dereferences che indirizza. 's' non è cambiato perché' s' e 'cs' sono due variabili separate. Se l'istruzione fosse '(* cs) ++' invece che * avrebbe * cambiato il valore di '* s'. (Attenzione, non 's', ma' * s'.) –