2015-10-23 8 views
6

Ich studiere K & R Buch. Derzeit lese ich die Funktion getop() auf S.78. Ich verstehe den Code, aber ich brauche Erläuterungen über 2 Dinge.getop() Funktion K & R Buch p 78

Der Code von getop() ist wie folgt: ca.

int getch(void); 
void ungetch(int); 

/* getop: get next character or numeric operand */ 
int getop(char s[]) 
{ 
    int i, c; 
    while ((s[0] = c = getch()) == ' ' || c == '\t') 
     ; 
    s[1] = '\0'; 

    if (!isdigit(c) && c != '.') 
     return c; /* not a number */ 

    i = 0; 
    if (isdigit(c)) /* collect integer part */ 
     while (isdigit(s[++i] = c = getch())) 
      ; 
    if (c == '.') /* collect fraction part */ 
     while (isdigit(s[++i] = c = getch())) 
      ; 
    s[i] = '\0'; 

    if (c != EOF) 
     ungetch(c); 

    return NUMBER; 
} 

Meine Frage: s[0] in:

while ((s[0] = c = getch()) == ' ' || c == '\t') 

Die Idee hinter der while-Schleife ist Räume und horizontale Register zu überspringen, Warum speichern wir also 'c' in s [0]? Warum haben die Autoren nicht einfach schreiben:

while (c= getch() == ' ' || c == '\t') 

Wir werden keine Leerzeichen und Tabulatoren später zu verwenden, warum brauchen wir c in s[0] zu retten? Was ist die Notwendigkeit für s[0] hier? über

Meine zweite Frage lautet:

s[1] = '\0'; 

Warum sind wir '\ 0' (Ende der Zeichenfolge) zu s[1] hier zuweisen?

Ich habe einige der vorherigen Antworten auf stackoverflow.com darüber gelesen, aber ich bin nicht ganz davon überzeugt!

Die akzeptierte Antwort zu der obigen Frage lautet: "Da die Funktion möglicherweise zurückkehrt, bevor die verbleibende Eingabe gelesen wird, muss s eine vollständige (und abgeschlossene) Zeichenfolge sein."

Ok. Was aber, wenn die Eingabe am Anfang einen Leerraum hat und von einem Operanden oder Operator gefolgt wird? In diesem Fall wird s[1] = '\0' die Zeichenfolge zu früh schließen? nicht wahr?

Antwort

5

Als Antwort auf Ihre erste Frage ist die Zuweisung an s[0] in diesem Fall eine bequeme Codierungsverknüpfung. Der Wert c wird in s[0] für alle Zeichen gelesen von getch() kopiert, unabhängig davon, ob es verwendet oder verworfen wird. Wenn es verworfen werden soll, keine große Sache; Es wird bei der nächsten Iteration der Schleife while() überschrieben. Wenn es verwendet werden soll, wurde es bereits an den erforderlichen Ort im Ziel-Array s[] kopiert.

In Antwort auf Ihre zweite Frage,

Aber was, wenn der Eingang am Anfang einen weißen Raum hat und durch einen Operanden oder Operator gefolgt?

Man beachte, dass die vorherige while() Schleife Leerzeichen (Leerzeichen und Tabulatoren) verhindert, dass von der Schleife in s[0] nach Austritt erscheinen. Deshalb wird nach Ausführung von

s[1] = '\0'; 

der s[] String wird aus einem einzigen Zeichen bestehen, die weder einen Raum noch eine Lasche ist, durch ein String-Terminator.

In der nächsten Anweisung

if (!isdigit(c) && c != '.') 
    return c; /* not a number */ 

die Funktion zurück, wenn der Charakter ist alles andere als eine Ziffer oder ein Komma. Aus diesem Grund war es notwendig, die Zeichenfolge zu beenden.

+0

Gute Erklärung, obwohl ich positive Adjektive wie "bequem" entfernen würde, da dies darauf hindeutet, dass dieser unordentliche K & R-Code einer guten C-Kodierungspraxis folgt, während er bis zum Rand mit dem Gegenteil gefüllt ist. – Lundin

+0

@Lundin: Ich stimme völlig zu, dass der fragliche K & R-Code aus einer "guten Programmierpraxis" heraus schrecklich ist, aber der Code zeigt bestimmte Neuheiten der C-Sprache, die für Anfänger wichtig sind. Aus der Sicht des Algorithmusentwurfs, und ich glaube, aus der Perspektive des ursprünglichen Verfassers des Codes (lange bevor die "guten Kodierungspraktiken" von heute erdacht wurden), ist die Zuordnung zu s [0] an diesem Punkt im Code a Bequemlichkeit, da es nicht später durchgeführt werden muss. – sifferman

2

Aber was ist, wenn Eingang am Anfang einen Leerraum hat und von einem Operanden oder Operator gefolgt wird? In diesem Fall wird s [1] = '\ 0' die Zeichenfolge zu früh schließen? nicht wahr?

Nö,

i = 0; 
if (isdigit(c)) /* collect integer part */ 
    while (isdigit(s[++i] = c = getch())) 

Dies stellt sicher, dass, wenn es etwas zu lesen ist, wird es auf \0 überschrieben, wie i=0 und s[++i] würde bedeuten, in s[1] speichern, die die \0 enthält

+0

thx für die Beantwortung meiner zweiten Frage, weil nicht

s[0] = '\0'; 

gespeichert wir schon damals! Irgendein Kommentar zu meiner ersten Frage? –

0

für Ihre erste Frage zu: s [0] in:

while ((s[0] = c = getch()) == ' ' || c == '\t') 

weil die Spar 'c' in s [0] in fortgeschrittenen zu speichern erste Zahl helfen, damit wir unseren nächsten Code beginnen ab einfach gleich i auf 1.

i = 0; 
if (isdigit(c)) /* collect integer part */ 
    while (isdigit(s[++i] = c = getch())) 

der obige Code zum Speichern nächste Zeichenfolge verwendet, die aus dem Index ist beginnen i = 1

Über Ihre zweite Frage:

können wir erste Zahl in Zeichenfolge in s [0]

siehe

(s[0] = c = getch())