Betrachten Sie das folgende einfache C-Programm, das eine Datei in einen Puffer liest und diesen Puffer der Konsole anzeigt:
%Vor%Die zu lesende Datei enthält einfach:
Hallo Welt!
Die Ausgabe ist:
Hallo Welt! ²²²²▌▌▌▌▌▌▌↔☺
Es ist eine Weile her, seit ich etwas Bedeutendes in C / C ++ gemacht habe, aber normalerweise würde ich annehmen, dass der Puffer größer als nötig zugewiesen wurde, aber das scheint nicht der Fall zu sein.
fileLen endet mit 12, was genau ist.
Ich denke jetzt, dass ich nur den Puffer falsch anzeigen muss, aber ich bin mir nicht sicher, was ich falsch mache.
Kann mir jemand sagen, was ich falsch mache?
Der Ansatz von JesperE wird funktionieren, aber Sie könnten daran interessiert sein, dass es einen alternativen Weg gibt, um damit umzugehen.
Sie können immer eine Zeichenfolge mit bekannter Länge drucken, selbst wenn kein NUL-Terminator vorhanden ist, indem Sie die Länge auf printf
als Genauigkeit für das Zeichenfolgenfeld angeben:
Dadurch können Sie die Zeichenfolge drucken, ohne den Puffer zu ändern.
JesperE ist in Bezug auf das Null-Abbruch-Problem in Ihrem Beispiel korrekt, ich füge nur hinzu, dass wenn Sie Textdateien verarbeiten, es besser wäre, fgets () oder etwas Ähnliches zu verwenden, da dies Zeilenumbrüche auf verschiedenen Plattformen korrekt behandelt und wird immer die Zeichenfolge für Sie beenden. Wenn Sie wirklich mit binären Daten arbeiten, dann möchten Sie printf () nicht verwenden, um die Daten auszugeben, da die printf-Funktionen Zeichenfolgen erwarten, und ein Null-Byte in den Daten bewirkt eine Kürzung der Ausgabe.
Ihr Ansatz, die Dateigröße zu bestimmen, indem Sie bis zum Ende der Datei suchen und dann ftell()
verwenden, ist falsch:
"b"
im zweiten Parameter für den Aufruf fopen()
geöffnet wurde, kann ftell()
Ihnen möglicherweise nicht die Anzahl der Zeichen mitteilen, die Sie aus der Datei lesen können. Zum Beispiel verwendet Windows zwei Bytes für das Ende der Zeile, aber beim Lesen ist es ein char
. Tatsächlich ist der Rückgabewert von ftell()
für im Textmodus geöffnete Streams nur in Aufrufen von fseek()
nützlich, und nicht zum Ermitteln der Dateigröße. "b"
im zweiten Parameter zu fopen()
geöffnet wurde, dann sagt der C-Standard:
Das Festlegen des Dateipositionsindikators auf das Dateiende, wie bei
fseek(file, 0, SEEK_END)
, hat ein undefiniertes Verhalten für einen binären Datenstrom (wegen möglicher abschließender Nullzeichen) oder für jeden Datenstrom mit zustandsabhängiger Codierung, der nicht sicher endet im anfänglichen Schaltzustand.
Also, was Sie tun, wird nicht unbedingt in Standard C funktionieren. Am besten verwenden Sie fread()
zum Lesen, und wenn Sie mehr Speicher benötigen, verwenden Sie realloc()
. Ihr System stellt möglicherweise mmap()
zur Verfügung oder kann Garantien geben, den Dateipositionsindikator auf das Dateiende für binäre Datenströme zu setzen - aber darauf angewiesen, dass diese nicht portierbar sind.
Siehe auch diese C-FAQ: Worin besteht der Unterschied zwischen Text und binären E / A? . p>
Sie können calloc
anstelle von malloc
verwenden, um bereits initialisierten Speicher zuzuweisen. calloc
übernimmt zusätzliches Argument. Es ist nützlich für die Zuordnung von Arrays; Der erste Parameter von calloc
gibt die Anzahl der Elemente im Array an, denen Sie Speicher zuweisen möchten, und das zweite Argument ist die Größe jedes Elements. Da die Größe von char
immer 1 ist, können wir einfach 1
als zweites Argument übergeben:
In C muss der Rückgabewert von malloc
oder calloc
nicht umgesetzt werden. Das Obige stellt sicher, dass die Zeichenfolge null beendet wird, selbst wenn das Lesen der Datei aus irgendeinem Grund vorzeitig beendet wird. calloc
dauert länger als malloc
, weil es den gesamten Speicher, den Sie angefordert haben, auf Null setzen muss, bevor Sie es Ihnen geben.