fgetc und fputc mit denselben filepointer
-
Hallo Leute, bin nen C-Einsteiger und setzte mich im Moment mit Dateiverarbeitung in C auseinander. Ich hab hier ne Funktion geschrieben, die zunächst die Buchstaben aus einer .txt Datei liest und falls diese klein sind in groß umwandelt. Der Compiler(eclipse+minGW) gibt zwar keine Fehler an, allerdings wenn ich die .txt Datei in Windows öffne, ist diese unverändert??? Danke im Voraus. Hier ist der Code:
#include <stdio.h> #include <string.h> void klein2gross( char * ); int main( void ) { setvbuf(stdout, NULL, _IONBF, 0); char dateiPfad[100];; printf("Bitte geben Sie den Pfad der Datei an : "); gets(dateiPfad); //strcpy( dateiPfad , "C:\\test.txt" ); klein2gross( dateiPfad ); return 0; } void klein2gross( char *dateiPfad ) { FILE *fp; int temp; fp = fopen( dateiPfad, "r+" ); while ( ( temp = fgetc( fp ) ) != EOF ) { if ( temp >= 97 && temp <= 122 ) temp -= 32; fputc( temp , fp-1 ); } fclose(fp); }
-
Gleich mehrere Fehler:
- Du öffnest zum lesen, willst aber schreiben
- Was soll fp-1 sein? Ziemlich sicher nicht das, was Du denkst.
-
In diesem folgenden Link steht das "r+" für das Lesen&Schreiben steht, ka:
http://openbook.galileocomputing.de/c_von_a_bis_z/016_c_ein_ausgabe_funktionen_005.htm#mj2f57f419fdeadcd1c7dd4e001616d21aUnd fp-1 weil, fgetc ja nach dem Aufruf auf das nächste element zeigt und ich will ja in die addresse des eingelesenen zeichens das geänderte Zeichen reinschreiben, oder liege ich da falsch?
-
Es handelt sich bei fp nicht um einen Zeiger auf den Dateiinhalt selbst, sondern (üblicherweise) um einen Zeiger auf eine Struktur, die das beinhaltet, was die Laufzeitumgebung für den Zugriff auf den Dateiinhalt an der richtigen Stelle benötigt. Es wird vom Standard nicht genau beschrieben, wie FILE aussehen muss, aber in der Regel sind die Dinger verhältnismäßig groß und unübersichtlich.
Was du mit fp-1 betreibst, ist Zeigerarithmetik, wie man sie von Arrays kennt. Es wäre beispielsweise möglich,
FILE fds[2]; FILE *fp; int c; fds[0] = fopen("0.txt", "r+"); fds[1] = fopen("1.txt", "r+"); fp = &fds[1]; c = fgetc(fp); fputc(c, fp - 1);
zu schreiben, um ein Zeichen aus 1.txt in 0.txt zu schreiben. (Über die Sinnhaftigkeit dieses Vorgehens kann man allerdings seine Zweifel haben)
Wonach du suchst, dürfte fseek sein. Beispielsweise:
#include <ctype.h> #include <stdio.h> int main(void) { FILE *fd = fopen("test.txt", "r+"); int c; while((c = fgetc(fd)) != EOF) { fseek(fd, -1, SEEK_CUR); /* -1 Zeichen von aktueller Position */ fputc(toupper(c), fd); } return 0; }
Noch ein paar Anmerkungen:
if ( temp >= 97 && temp <= 122 ) temp -= 32;
ist ziemlich schlechter Stil. Mindestens könnte man
if(temp >= 'a' && temp <= 'z') { temp = temp - 'a' + 'A'; }
schreiben (das funktioniert dann auch mit EBCDIC). Konkret für diesen Fall gibt es aber in ctype.h Funktionen, die locale-abhängig auch Umlaute erschlagen können und sich an dieser Stelle deutlich besser eignen.
Zweitens:
abg1984 schrieb:
Du solltest dir eine bessere Informationsquelle suchen. Der Autor dieses Buches ist hier schon lange berüchtigt für sein Unverständnis, und ich gehe inzwischen sogar so weit, Galileo Computing in eine Reihe mit Markt+Technik und Data Becker zu stellen. Geh am besten zu deinem Buchhändler und besorg dir etwas von einem renommierten Technikverlag wie O'Reilly oder Addison-Wesley - die haben einen Ruf zu verteidigen. Das garantiert zwar auch nicht, dass alles, was sie verlegen, makellos ist, aber zumindest sammeln sich bei ihnen nicht die Musterbeispiele für den Dunning-Kruger-Effekt.
-
abg1984 schrieb:
... gets(dateiPfad); ... } .. fp = fopen( dateiPfad, "r+" ); while ( ( temp = fgetc( fp ) ) != EOF ) { if ( temp >= 97 && temp <= 122 ) temp -= 32; fputc( temp , fp-1 ); } ..
gets ist Müll weil unsicher und es bessere Lösungen gibt.
Im "+"-Modus musst du bei gleichzeitiger Verwendung von Lese- und Schreiboperationen aufpassen, zwischen einer Lese- und einer direkt nachfolgenden Schreiboperation muss immer eine (explizite!) Dateipositionierung liegen (oder EOF), in umgekehrtem Fall auch oder fflush, sonst hast du undefiniertes Verhalten vorliegen.
Dateipositionierung macht man standardkonform mit fsetpos, fseek oder auch mit rewind und nicht wie du mit fp-1, das ändert die Dateiposition nicht sondern dürfte höchstens fputc zum Abbruch bringen.
-
Noch mehrere allgemeine Kommentare
-
Wieso änderst du die buffereinstellungen? Die sind eigentlich genau dafür da dass deine fgetc Schleife sehr viel performanter durchläuft
-
Wutz hat es ja schon geschrieben aber ich möchte nochmal betonen:
Benutze _niemals_ gets. Was machst du wenn der Benutzer 120 Zeichen eingibt? gets hat keine Möglichkeit das abzufangen und dein Programm hat eine Sicherheitslücke so gross wie ein Scheunentor -
Ich weiss nicht auf welchem System du entwickelst aber zumindest unter *NIX Systemen ist es weit besserer Stil von der Standardeingabe zu lesen als sich einen Dateinamen übergeben zu lassen (und selbst mit Dateinamen ist das übergeben als Kommandozeilenparameter weitaus besserer Stil als danach zu fragen)
-
-
linux_c89 schrieb:
- Ich weiss nicht auf welchem System du entwickelst aber zumindest unter *NIX Systemen ist es weit besserer Stil von der Standardeingabe zu lesen als sich einen Dateinamen übergeben zu lassen (und selbst mit Dateinamen ist das übergeben als Kommandozeilenparameter weitaus besserer Stil als danach zu fragen)
Kannst du diesen Satz noch mal erklären.
Was ist jetzt besser, Standardeingabe (fragen und fgets) oder Kommandozeile (argv)?
-
Danke Leute für eure Antworten und insbesondere Infos über Dateipositionierung! Ich werde mich ma mit den Funktionen auseinandersetzen.
@seldon:
OK, dann werde ich mir ma ne neue Quelle suchen. Wusste nicht das diese Seite, umgenauer zu sein, dieses Buch nen schlechten Ruf hat. Apropo O'Reily: Was hälts du den von "C in a nutshell"???
@linux89:
1)Ach, das mit setvbuf mache ich im moment reflexmäßig per copy&paste wenn ich was programmiere. Hier in diesem code ist es nicht notwendig. Hatte halt bei den früheren Sachen, bezüglich printf und einem nachfolgendem scanf probleme wegen des newline zeichens.
2)Mir ist auch bewusst, dass die Eingabe des Pfades auf, sagen mir mal x-viele Zeichen begrenzt wird, keine optimale Lösung darstellt. Ich weiss halt nicht wie man es besser macht:) Nichts desto trotz werde ich mich ma über stdin&stdout informieren um es eleganter zu lösen.
3)Ich programmiere in Windows.
-
DirkB schrieb:
linux_c89 schrieb:
- Ich weiss nicht auf welchem System du entwickelst aber zumindest unter *NIX Systemen ist es weit besserer Stil von der Standardeingabe zu lesen als sich einen Dateinamen übergeben zu lassen (und selbst mit Dateinamen ist das übergeben als Kommandozeilenparameter weitaus besserer Stil als danach zu fragen)
Kannst du diesen Satz noch mal erklären.
Was ist jetzt besser, Standardeingabe (fragen und fgets) oder Kommandozeile (argv)?Du brauchst keine Nutzerinteraktion. Das ermöglicht dir, dein Programm in eine Kette von Pipes zu benutzen, was dem Workflow enorm entgegen kommt. Und du kannst es unbeaufsichtigt remote ausführen.
-
abg1984 schrieb:
OK, dann werde ich mir ma ne neue Quelle suchen. Wusste nicht das diese Seite, umgenauer zu sein, dieses Buch nen schlechten Ruf hat. Apropo O'Reily: Was hälts du den von "C in a nutshell"???
Ich habe gute Dinge darüber gehört. Ich habe allerdings auch gehört, dass es keine Einführung in die Programmierung im Allgemeinen bietet, sondern praktisch ausschließlich C und seine Eigenheiten behandelt - O'Reilly bewirbt es als Nachschlagewerk. Wenn du von einer anderen Programmiersprache zu C kommst, dürfte es ziemlich genau sein, was du suchst; wenn du aber nicht nur in C, sondern in der Programmierung insgesamt Anfänger bist, könnte es dich im Moment noch überfordern.
Wenn du eine Einführung in die Programmierung anhand von C suchst, ist dir mit "Practical C Programming" wahrscheinlich besser geholfen, auch wenn die ersten paar Seiten, die sich mit der Benutzung ehemals gängiger Entwicklungstools befassen, aufgrund des Buchalters inzwischen teilweise hinfällig sind (oder hat hier noch jemand Turbo-C?).
Ansonsten:
Dieser setvbuf-Kram wird mit einem Bug in der Eclipse/CDT-Konsole zusammenhängen; das läuft allem alle Nase lang wieder über den Weg. Wenn man ihr nicht den Buffer wegnimmt, zeigt sie Ausgaben in mehr oder weniger zufälliger Reihenfolge an; insbesondere sind stdout und stdin dann nicht synchronisiert. Genaueres hier. Da scheinbar immer noch keine Absicht besteht, das zu beheben, wäre ein Umstieg womöglich angebracht. Unter Windows ist MSVC praktisch Standard. Du kannst dir die Express-Version ja mal ankucken.
Was die Stilfrage angeht, so ist es weniger bedeutsam, ob von stdin gelesen wird oder direkt aus einer Datei; es stößt mir allerdings immer etwas unangenehm auf, wenn jemand direkt in einer Datei herumfuhrwerkt. Wenn zum falschen Zeitpunkt der Strom ausfällt, hast du auf die Art weder die Quelldaten noch das, was nachher als Ergebnis rauskommen sollte. Das ist in diesem speziellen Fall nicht wirklich problematisch, aber allgemein ist es in der Regel ein besseres Vorgehen (und auch einfacher), die Ausgabedaten in eine neue Datei zu schreiben. Wenn man die alte Datei unbedingt ersetzen will, kann man sie dann immer noch löschen und die neue zum alten Namen umbenennen.
-
Danke für die Tipps, Seldon!
Ja, ich suche auch eher ein Nachschlagewerk, da man was die Einführung betrifft durch Tutorials im Internet gut bedient ist.
Hmmm, eigentlich will ich bei Eclipse bleiben weil ich in die DSP-Programmierung einsteigen will und die Entwicklungssoftware der TI-Boards(code composer studio)
in die Eclipse-Umgebung einbunden ist.