Textdatei: bestimmte Zeile ausgeben
-
#include <fstream> #include <iostream> #include <string> using namespace std; int main() { ifstream in("dat.txt"); string tmp; string lastLine(""); getline(in, tmp); while(!in.eof()) { lastLine = tmp; getline(in, tmp); } cout << "Letzte Zeile:\n" << lastLine; }
-
Wir sind hier nicht in C++ Herr Kollege.
U.g. sollte die letzte Zeile einer Textdatei ausgeben, auch korrekt, falls die Datei mit '\n' endet.
Schaue dir einfach erstmal nur die main-Funktion an, den Rest dann später.int getline(FILE *f,char **z) { int r=1,c; while( (c=fgetc(f))!=EOF ) { if(r==1) **z=0; if( c=='\n' ) return r-1; else { char ch=c; strncat(*z=realloc(*z,++r),&ch,1); } } return r-1?r-1:EOF; } int main() { FILE *f=fopen("bla.txt","rt"); char *zeile=malloc(1); setvbuf(f,0,_IOLBF,4096); while( getline(f,&zeile)!=EOF ); fclose(f); puts(zeile); free(zeile); return 0; }
-
Wutz schrieb:
Wir sind hier nicht in C++ Herr Kollege.
chicksgirl schrieb:
arbeite gerade etwas mit C und C++.
Welches ist denn das richtige Forum dafür, Herr Kollege?
-
Wir sind hier nicht in C++ Herr Kollege.
-
Lies mal richtig, Herr Kollege. Die Dame macht etwas in "C und C++". Wo ist bitte das C und C++ - Forum hier?
Das C++ - Forum wirst Du mir hier ja kaum empfehlen können, denn da "sind wir ja nicht in C".
-
Eigentlich sagt sie folgendes:
chicksgirl schrieb:
Lohnt es sich überhaupt das in C zu machen oder sollte man hier eher auf C++ umsteigen?
Die ideale C-Lösung wäre vermutlich folgende (und normalerweise wird sie schneller als die C++-Variante sein, weil nicht alles ausgelesen wird und vor allem benötigt sie nicht so viel Speicher):
#include <stdio.h> #include <stdlib.h> int main (int argc, char *argv[]) { FILE *f; long i; char c; if (argc != 2) { fprintf (stderr, "usage: %s filename\n", argv[0]); return 1; } f = fopen (argv[1], "r"); fseek (f, 0, SEEK_END); i = ftell (f) - 1; fseek (f, i, SEEK_SET); // Springe zum i-ten Zeichen if (i >= 1 && fgetc (f) == '\n') --i; // letzte (und nur letzte) Leerzeile überspringen do fseek (f, i, SEEK_SET); while (--i>=0 && fgetc (f) != '\n'); while ((c = fgetc (f)) != EOF && c != '\n') // f ist bei der letzten Zeile putchar (c); putchar ('\n') fclose (f); return 0; }
Ansonsten geht das auch, in dem man jede Zeile in einen
buf[255]
einliest und am Schluss den letzten ausgibt, ist vielleicht für einen Anfänger besser.
-
Soso, so sieht also vermutlich die ideale Lösung aus.
Ich vermute, sie produziert undefiniertes Verhalten,
der Inhalt von argv[0] ist undefiniert
bei Dateigrößen = 0 Byte ist die Lösung undefiniert
bei Dateigrößen > LONG_MAX ist die Lösung undefiniert
-
Wutz schrieb:
Soso, so sieht also vermutlich die ideale Lösung aus.
Ich gebe zu, das war etwas übertrieben.
Wutz schrieb:
Ich vermute, sie produziert undefiniertes Verhalten
Soweit würde ich aber nicht gehen
Wutz schrieb:
der Inhalt von argv[0] ist undefiniert
Nein, im schlimmsten Fall ist er 0. Der Standard definiert ein mit 0 abgeschlossenes argv[]-Array
Wutz schrieb:
bei Dateigrößen = 0 Byte ist die Lösung undefiniert
bei Dateigrößen > LONG_MAX ist die Lösung undefiniertDoch, sie ist definiert. ftell gibt bei einem Fehler -1 zurück, es wird nur noch ein fseek auf -1 ausgeführt, auch definiert.
Ich rate dir, auf meinei >= 1
bzw.--i >= 0
zu achten.
-
Der Inhalt von argv[0] ist undefiniert, das wollten andere vor dir hier auch nicht glauben: http://www.c-plusplus.net/forum/275028-10
Bei Dateigröße 0 liefert dein ftell 0L (und keinen Fehler), minus 1 ist -1L. -1L an fseek übergeben liefert für die 0 Byte große Datei undefiniertes Verhalten, zumal du den Rückgabewert gar nicht auswertest. Für >LONG_MAX Dateien springst du mit deinem fseek überall hin, nur nicht ans Dateiende. Und der _FILE_OFFSET_BITS Kram ist nicht ANSI C.
-
Der Standard definiert argc und argv wie folgt:
ISO/IEC 9899:1999 5.1.2.2.1 (2) schrieb:
If they are declared, the parameters to the main function shall obey the following
constraints:
— The value of argc shall be nonnegative.
— argv[argc] shall be a null pointer.
— If the value of argc is greater than zero, the array members argv[0] through argv[argc-1] inclusive shall contain pointers to strings, which are given implementation-defined values by the host environment prior to program startup. The intent is to supply to the program information determined prior to program startup from elsewhere in the hosted environment. If the host environment is not capable of supplying strings with letters in both uppercase and lowercase, the implementation shall ensure that the strings are received in lowercase.
— If the value of argc is greater than zero, the string pointed to by argv[0] represents the program name; argv[0][0] shall be the null character if the program name is not available from the host environment. If the value of argc is greater than one, the strings pointed to by argv[1] through argv[argc-1] represent the program parameters.
— The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination....woraus sich ergibt, dass argv[0] keinesfalls undefiniert ist. Allerdings kann es passieren, dass argc == 0 ist (etwa bei merkwürdige exec*-Aufrufen), in welchem Fall argv[0] == NULL und
fprintf (stderr, "usage: %s filename\n", argv[0]);
undefiniert ist.
Was das ursprüngliche Problem angeht, mit "Rest unverändert" meinte ich, dass die get_line-Funktion aus dem vorherigen Codestück unverändert übernommen werden sollte.
Die Kritik am fseek-Ansatz ist prinzipiell berechtigt; der C-Standard scheint sich nicht mit dem Gedanken zu befassen, dass Daten größer als LONG_MAX werden könnten und definiert die Fähigkeiten von fseek generell ziemlich eng. Da aber sowohl POSIX als auch die MSDN zusätzliches Verhalten definieren, welches die Anwendung von fseek vereinfacht, sollte man so ziemlich überall mit
fseek(fd, i, SEEK_END);
und negativem i davonkommen.
Allerdings ist das nicht unbedingt ein performanter Ansatz, zumindest nicht in der angegebenen Form, wo jeweils ein Zeichen zurückgesucht wird. Es hängt vom darunterliegenden Medium ab - nehmen wir, wegen der extremen Anschaulichkeit beispielsweise ein Kassettenlaufwerk und stellen uns vor, wie sich das verhielte, wenn man ihm ein "ein Zeichen vor, zwei Zeichen zurück"-Suchmuster gäbe. Wie auch bei der getline-Funktion scheint es sinnvoll, die Daten blockweise einzulesen und im Speicher nach Zeilenumbrüchen zu suchen.
Und Wutz, du solltest wirklich aufhören, Anfängern deine grauenvoll ineffiziente getline-Implementation aufs Auge zu drücken. Jemand könnte auf die Idee kommen, sie zu verwenden.
-
Sowohl realloc als auch fgetc/setvbuf arbeiten nicht zeichen- sondern blockweise, was Leute mit beschränktem Horizont leicht übersehen.
-
Hi Jungs
Also sorry, egal welchen eure Codes ich bei mir in Visual STudio reinhau, er sagt jedes mal beim debuggen okay und beim öffnen der Konsolenanwendung öffnet die Konsole kurz und schließt sich gleich wieder"The program '[5164] PPSTEST.exe: Native' has exited with code 0 (0x0)."
-
ist doch super, heißt soviel wie "alles richtig gemacht".
-
Wutz schrieb:
Sowohl realloc als auch fgetc/setvbuf arbeiten nicht zeichen- sondern blockweise, was Leute mit beschränktem Horizont leicht übersehen.
Nette Behauptung. Sie ist nur stumpf nicht wahr - lies es im Standard nach (7.20.3.4).
Das wäre dir übrigens auch aufgefallen, wenn du mal einen Debugger auf das Programm losgelassen hättest. Mit __FILE__ statt "blabla.txt" in deinem Code meint valgrind Folgendes:
==30558== Memcheck, a memory error detector ==30558== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. ==30558== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info ==30558== Command: ./a.out ==30558== } ==30558== ==30558== HEAP SUMMARY: ==30558== in use at exit: 0 bytes in 0 blocks ==30558== total heap usage: [b]464 allocs, 464 frees, 6,509 bytes allocated[/b] ==30558== ==30558== All heap blocks were freed -- no leaks are possible ==30558== ==30558== For counts of detected and suppressed errors, rerun with: -v ==30558== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
...und das für 494 Byte in 32 Zeilen!
Du bist inzwischen lange genug dabei, um dir um Effizienz Gedanken zu machen und Behauptungen in diese Richtung zu prüfen, bevor du sie machst. Einen beschränkten Horizont lasse ich mir angesichts dieser Leistung von dir ganz bestimmt nicht vorwerfen.
@chicksgirl: Das sieht mir nach MSVC aus. Probier's mal mit Strg + F5 (wenn ich das gerade richtig im Kopf habe). Wenn du es mit "Debuggen" starten willst, setz halt einen Haltepunkt in die letzte Zeile.
-
Starte Dein Konsolenprogramm aus der Konsole!
-
wie mache ich das ?
-
chicksgirl schrieb:
wie mache ich das ?
rtfm?
-
Ne das lag dadran, dass kein system("pause") eingefügt war!!!
Jetzt hab ichs eingefügt, programm schmiert immer ab und Konsole bleibt NICHT offen !?!?! WOrang liegt das ?
hab für den filname mdie Adresse eingegeben wo er die daten ziehn soll, also Z\\blabla.txt
-
chicksgirl schrieb:
WOrang liegt das ?
rtffaq:
http://www.c-plusplus.net/forum/111042
Mit C hat das übrigens gar nichts zu tun.
-
sorry, aber funktioniert trotz einfügen der WAIT-Funktion nicht.
Weis leider nicht woran es liegt ^^ bin schon die ganze Zeit am rumprobieren, Funktion klappt aber leider nicht