2009-05-14 10 views
6

In an answer gab es eine interessante Aussage:. „Es ist fast immer eine schlechte Idee, die fscanf() Funktion zu verwenden, wie es Ihr Dateizeiger an einem unbekannten Ort auf Versagen verlassen kann ich es vorziehen, fgets() zu verwenden, um jede Zeile in bekommen und dann sscanf() das. "Wann/warum ist es eine schlechte Idee, die Funktion fscanf() zu verwenden?

Können Sie erweitern, wenn/warum es besser sein könnte, fgets() und sscanf() zu verwenden, um eine Datei zu lesen?

Antwort

13

Stellen Sie sich eine Datei mit drei Linien:

1 
    2b 
    c 

fscanf() Mit ganzen Zahlen zu lesen, die erste Zeile lesen würde in Ordnung, aber in der zweiten Zeile fscanf() würden Sie an der ‚b‘ verlassen, nicht sicher, was zu tun ist von dort. Sie benötigen einen Mechanismus, um sich über die Mülleingabe hinaus zu bewegen, um die dritte Zeile zu sehen.

Wenn Sie eine fgets() und sscanf() machen, können Sie garantieren, dass sich der Dateizeiger um eine Zeile nach der anderen bewegt, was ein wenig einfacher zu handhaben ist. Im Allgemeinen sollten Sie immer noch die ganze Zeichenfolge betrachten, um irgendwelche ungeraden Zeichen darin zu melden.

Ich bevorzuge den letzteren Ansatz selbst, obwohl ich der Aussage nicht zustimmen würde, dass "es fast immer eine schlechte Idee ist, fscanf() zu verwenden" ... fscanf() ist völlig in Ordnung für die meisten Dinge.

+1

Bitte ändern 'gets()' auf 'fgets()'. 'gets()' sollte nie benutzt werden. – Wiz

+0

Must'a war ein Tippfehler :) Danke für das Abfangen. –

0

Im Grunde gibt es keine Möglichkeit, diese Funktion nicht zu verlassen, um außerhalb des Bereichs für den Speicherbereich zu gehen, den Sie dafür reserviert haben.

Eine Reihe von Ersetzungen sind herausgekommen, wie zB fnscanf, bei dem versucht wird, diese Funktionen zu korrigieren, indem ein Höchstwert für den Schreibzugriff des Lesers festgelegt wird, damit dieser nicht überläuft.

+1

Während Pufferüberläufe ein Problem mit der Funktionsfamilie scanf() sind, stehen sie in keinem Zusammenhang mit dem hier gestellten Problem. -1 – Sparr

+1

"Könnten Sie näher erläutern, warum es besser ist, fgets() und sscanf() zu verwenden, um eine Datei zu lesen." Ich erweiterte seine Frage. Ich lehne dein übertriebenes "-1" ab – cyberconte

+1

Ich nehme "erweitern warum", um zu meinen, dass deine Antwort auf der Prämisse basieren sollte, die bereits präsentiert wird, das das Dateizeigerproblem ist. Wenn er andere Gründe haben wollte, hätte er nicht mit dem Ursprung der Frage in Verbindung gebracht oder den relevanten Teil davon zitiert. – Sparr

2

Wenn fscanf() aufgrund eines Eingabefehlers oder eines Übereinstimmungsfehlers fehlschlägt, wird der Dateizeiger (d. H. Die Position in der Datei, von der das nächste Byte gelesen wird) an einer anderen Position als wo gelassen wäre die fscanf() gelungen. Dies ist typischerweise bei sequentiellen Dateilesevorgängen unerwünscht. Das Lesen von einer Zeile zu einer Zeit führt dazu, dass die Dateieingabe vorhersagbar ist, während Einzelzeilenfehler einzeln behandelt werden können.

1

Es ist fast immer eine schlechte Idee, die fscanf() Funktion zu verwenden, wie es Ihren Dateizeiger an einem unbekannten Ort auf Ausfall verlassen. Ich bevorzuge es, fgets() zu verwenden, um jede Zeile und dann sscanf() das zu erhalten.

Sie können immer verwenden, um die aktuelle Position in der Datei herauszufinden und dann zu entscheiden, was von dort zu tun ist. Grundlegend, wenn Sie wissen, was Sie erwarten können, dann zögern Sie nicht fscanf() zu verwenden.

4

Der Fall, in dem dies zum Tragen kommt, ist, wenn Sie Zeichenliterale übereinstimmen. Angenommen, Sie haben:

int n = fscanf(fp, "%d,%d", &i1, &i2); 

Betrachten wir zwei möglichen Eingaben "323,A424" und "323A424".

In beiden Fällen gibt fscanf() 1 zurück und das nächste gelesene Zeichen ist ein 'A'.Es gibt keine Möglichkeit festzustellen, ob das Komma übereinstimmt oder nicht.

Das heißt, das ist nur wichtig, wenn es wichtig ist, die tatsächliche Fehlerquelle zu finden. In den Fällen, in denen das Erkennen eines fehlerhaften Eingabefehlers ausreichend ist, ist fscanf() dem Schreiben von benutzerdefiniertem Analysecode tatsächlich überlegen.

2

Es gibt zwei Gründe:

  • scanf()stdin in einem Zustand hinterlassen, die schwer vorherzusagen sind; dies macht eine Fehlerwiederherstellung schwierig, wenn nicht unmöglich (dies ist weniger ein Problem mit fscanf()); und
  • Die gesamte scanf() Familie nehmen Zeiger als Argumente, aber keine Längenbeschränkung, so können sie einen Puffer überlaufen und ändern nicht verwandte Variablen, die zufällig nach dem Puffer sind, was scheinbar zufällige Speicher Korruption Fehler, die sehr schwer zu verstehen, zu finden, und Debugging, insbesondere für weniger erfahrene C Programmierer.

Novice C Programmierer sind oft verwirrt über Zeiger und die „Adresse-of“ Operator und häufig die & auslassen, wo sie gebraucht wird, oder es hinzufügen „für eine gute Maßnahme“, wo es nicht ist. Dies verursacht "zufällige" Segfaults, die für sie schwer zu finden sind. Das ist nicht scanf() 's Schuld, also lasse ich es von meiner Liste, aber es lohnt sich, daran zu denken.

Nach 23 Jahren haben mich noch daran erinnern, es ist ein großer Schmerz zu sein, wenn ich C Programmierung begonnen und wusste nicht, wie diese Art von Fehler zu erkennen und zu debuggen und (als jemand, der jahrelang Unterricht C an Anfänger) es ist sehr schwer, sie einem Neuling zu erklären, der Zeiger und Stapel noch nicht versteht.

Wer scanf() an einen Anfänger C Programmierer empfiehlt, sollte gnadenlos ausgepeitscht werden.

OK, vielleicht nicht gnadenlos, sondern eine Art von Auspeitschung ist auf jeden Fall in Ordnung; o)

+0

Die Anweisung "Zeiger als Argumente nehmen, aber keine Längenbeschränkung" ist irreführend: Für die meisten Typen sind die Größen festgelegt ('% i','% d', '% lf'), sodass keine Längenbeschränkungen erforderlich sind. Eine Ausnahme ist das Lesen von Strings mit '% s'.Aber auch damit kann ein Limit angegeben werden, indem eine Zahl zwischen '%' und 's' hinzugefügt wird:'% 99s' für eine Zeichenkette, die als 'char s [100]' deklariert ist. –

Verwandte Themen