Hilfe bei Zeigerproblemen; variable Dateinamen
-
Ich habe mal wieder zwei Fragen:
Zuerst die unwichtigere - ist es möglich, in C Pfade zu Dateien durch Variablen zu ergänzen? Beispiel (funktioniert natürlich nicht, aber das macht vielleicht den Gedanken klar):int main() { int i=0; FILE * Ziel; for(i=0 ; i<20 ; i++) { Ziel = fopen("C:\Quelle"+i+".txt" , "w"); fclose(Ziel); } printf("Es wurden %i Dateien erfolgreich erstellt." , i); return(0); }
Ich habe schon etliche Kombinationen innerhalb des Dateipfades probiert, aber nichts wirksames gefunden.
Das zweite Problem habe ich relativ oft, ich vermute mal, dass entweder Unwissenheit oder Unverständnis das Problem ist (vielleicht auch beides
):
int main() { char * Eingabe=malloc(20*sizeof(char)); char * Puffer=malloc(50*sizeof(char)); FILE * Quelle=fopen("C:/Quelle.txt" , "r"); for(i=0 ; i<20 ; i++) { fscanf(Quelle,"%s", Puffer); Eingabe[i]=malloc(50*sizeof(char)); strcpy(Eingabe[i],Puffer); } }
Ziel dieser Aktion ist es, eine Datei Zeilen- oder auch Wortweise einzulesen (zeilenweise habe ich leider nicht hinbekommen). Dazu wird das Array "Eingabe" erstellt, dass die Adressen der Arrays speichern soll, die später die Strings tragen.
Nun fangen schon in der zweiten Zeile der for-Schleife die Fehler an:
Ich will doch die Adresse zu einem Array in meinem "Eingabe"-Array speichern (meiner Meinung nach fehlt da weder ein Pointer noch ein Cast), ich bekomme die Fehlermeldung: "assignment makes integer from pointer without a cast". Was stimmt nicht?
In der letzten Zeile der for-Schleife bekomme ich dann einen weiteren Fehler:
"passing arg 1 of 'strcpy' makes pointer from integer without a cast".Ich vermute mal, die beiden Fehlermeldungen hängen zusammen - muss ich mein "Eingabe"-Array sozusagen mit dem Datentyp "Pointer" versehen? Ich habe noch von keinem solchen Typ gehört - ich hoffe mal, dass mich jemand aufklären kann, was ich falsch mache. Schonmal vielen Dank dafür im Voraus!
-
Stiefel2000 schrieb:
Ich habe mal wieder zwei Fragen:
Zuerst die unwichtigere - ist es möglich, in C Pfade zu Dateien durch Variablen zu ergänzen? Beispiel (funktioniert natürlich nicht, aber das macht vielleicht den Gedanken klar):http://www.cs.cf.ac.uk/Dave/C/node19.html
Zur zweiten Frage:
Eingabe
ist ein einfacher Zeiger, du kannst damit also nur eindimensionalen Arrays speichern. Strings sind bereits eindimensional, d.h. wenn du ein Array von Strings willst, brauchst du zweidimensionale Arrays.Eingabe[i]
ist von Typchar
,malloc
liefert einvoid*
zurück, sieht du den Fehler?Richtig wäre (ohne Fehlerüberprüfung):
char **Eingabe; Eingabe = malloc(20 * sizeof *Eingabe); ... for(i=0; i < 20; ++i) { ... Eingabe[i]=malloc(50 * sizeof **Eingabe); strcpy(Eingabe[i],Puffer); }
In diesem Fall gilt:
Eingabe[i][j]
ist das j+1.te Zeichen des i+1.te Zeile.Und nicht vergessen: zu jedem
malloc
gehört einfree
!edit: btw.
malloc
sollte man verwenden, wenn man zur Compilezeit nicht weiß, wie viel Speicher benötigt wird. Wenn du von Anfang an weißt, dassPuffer
50 Byte breit sein wird, kannst du gleichchar Puffer[50];
schreiben, ebenso für
Eingabe
char Eingabe[20][50];
damit ersparst du dir die
mallocs/frees
.
-
Variabler Dateiname, guckst du:
#include <stdio.h> int main () { char file [FILENAME_MAX+1] = {0}; char* fbase = "test"; char* fext = ".txt"; char I [64] = {0}; int i = 0; for ( i=0; i<20; i++ ) { memset (file, 0, sizeof(file)); sprintf ( I, "%d", i ); if ( strlen (fbase) + strlen(fext) + strlen (I) <= FILENAME_MAX ) { sprintf ( file, "%s%s%s", fbase, I, fext ); printf ("I am your new filename: %s\n", file ); } else { puts ("String too long."); } } return 0; }
-
Das geht aber mit snprintf auch weniger umständlich:
#include <stdio.h> int main () { char file [FILENAME_MAX+1] = {0}; char* fbase = "test"; char* fext = ".txt"; int i = 0; for ( i=0; i<20; i++ ) { int len = snprintf(file, FILENAME_MAX + 1, "%s%d%s", fbase, i, fext ); if (len <= FILENAME_MAX) printf ("I am your new filename: %s\n", file ); else puts ("String too long."); } return 0; }
(nicht getestet)
-
Vielen Dank für eure Antworten :). Die Sache mit den zweidimensionalen Arrays habe ich in den letzten rund vier Stunden noch rausgefunden - zumindest war das Programm am Ende "lauffähig". Die Idee, Strings als Dateinamen zu nutzen, ist auch super. Daran hatte ich leider noch nicht gedacht.
Ich werde noch ein wenig rumprobieren, falls ich weitere Hilfe brauche, melde ich mich
.
-
namespace invader schrieb:
Das geht aber mit snprintf auch weniger umständlich:
da haddu recht, das spart die eine oder andere zeile.
-
Ich habe jetzt ein ziemlich nerviges Problem: Mein Programm stürzt ständig ab. Ich habe ein Array von Arrays erstellt und kann im Quelltext keinen Fehler finden. Da ich mit einem zweiten Programm, das auch ein Pointer-Array nutzt, den gleichen Fehler bekomme, muss wohl ein mir unbekanntes Problem vorliegen. Dabei ist zu bemerken, dass ich das zweite Programm vorhin unter Linux geschrieben und getestet habe - es war zwar noch nicht ganz fertig, lief aber sonst sehr gut. Unter Windows scheint es jedoch schon nach wenigen Code-Zeilen abzustürzen. Programm 1 hänge ich mal an - es handelt sich um das gleiche, das ich schon vorhin gepostet habe (mit ein paar Änderungen):
int main() { int i,k; char * Puffer=malloc(100*sizeof(char)); char ** Eingabe; FILE * Quelle=fopen("C:/Quelle.txt" , "r"); for(k=0 ; !feof(Quelle) ; k++) { fscanf(Quelle , "%s" , Puffer ); } rewind(Quelle); Eingabe=malloc(k*sizeof(char)); for(i=0 ; i<k ; i++) { fscanf(Quelle,"%s", Puffer); Eingabe[i]=malloc(j*sizeof(char)); strcpy(Eingabe[i],Puffer); printf("\n"); } for(i=0 ; i<k ; i++) { printf(*(Eingabe+i)); printf("\n"); } return(0); }
Die Zeile, die "printf("\n");" enthält gibt vielleicht etwas Aufschluss über das Problem: Lasse ich das Programm laufen, solange diese Zeile vor oder in der zweiten for-Schleife steht, erhalte ich zumindest einen Teil der letzten Ausgabe (ca. 25% - dann stürzt das Programm ab). Nehme ich die printf-Zeile heraus, stürzt das Programm unmittelbar nach dem Start ab
. Ich habe den Quelltext auf das nötigste zusammengekürzt, ich hoffe, der Fehler ist noch enthalten ;).
-
du solltest die Beiträge, die man für dich verfasst wurden, gründlich lesen. Vergleiche deinen Code mit meinem. Tipp: Zeile 12 von dir, du reserviert zu wenig Platz.
Außerdem wiederhole ich mich ungern, aber wenn du von Anfang an weißt, wie viel Platz du reservieren willst, wieso nimmst du nicht gleich ein Array? Und nochmal Wiederholung: zu jedem malloc gehört ein free, doch habe ich deinem Code kein einziges free gesehen, warum wohl?
Drittens: Zeile 15, was ist
j
?Viertens:
printf(*(Eingabe+i));
oberhäßlich, was passiert, wenn in der Datei sowas vorkommt?zeile 1 zeile 2 zeile %s3 zeile 4
denk nach.
-
Was die Array-Größe angeht: Die lasse ich solange variabel, wie irgend möglich. Ich versuche schließlich ein Programm zu schreiben, das ich später mal ohne viel Nachdenken wiederverwenden kann - die einzige Möglichkeit, dauerhaft ausreichend Speicher zu haben, wäre wohl, das Array unglaublich groß zu machen.
Zu deiner Frage zum "j" - wie ich oben geschrieben habe, habe ich den Quelltext zurechtgestutzt. Mein "j" wird anfangs auf 100 gesetzt, weil ich keine Möglichkeit gefunden habe, es ermitteln zu lassen. Natürlich gibt es auch keinen Grund, in einem Quelltext-Auszug extra noch free's aufzuführen, wo mein Problem doch aus einer ganz anderen Ecke zu kommen scheint.
Ich muss sagen, dass ich nicht sehe, warum ich in Zeile 12 zu wenig Platz reserviere? Ich erstelle ein Array mit exakt K Speicherzellen, in der Schleife danach werden alle Elemente gefüllt (da ja i<k gilt und das Zählen bei 0 anfängt).
Zu guter Letzt: Das printf in der Datei ist nur zur Kontrolle des Arrays, das ich gerade eingelesen habe - wie ich im letzten Post erwähnte, scheint das "printf("\n");" in der zweiten for-Schleife sogar Macht über das Laufverhalten meines Programms zu haben - und ich habe keine Ahnung, weshalb das so sein sollte.
Ziel dieser Programm-Elements ist wirklich nur das Einlesen, dem Programm fehlt jegliche Verarbeitung (das dürfte doch auffallen, oder?), eine Ausgabe ist also wenig sinnvoll.EDIT: Was genau bewirkt das "i < ++i" in deiner for-Schleife?
-
Stiefel2000 schrieb:
Was die Array-Größe angeht: Die lasse ich solange variabel, wie irgend möglich
ok, das ist eine gute Begründung, dennoch musst du
malloc
richtig verwenden.Stiefel2000 schrieb:
Ich muss sagen, dass ich nicht sehe, warum ich in Zeile 12 zu wenig Platz reserviere? Ich erstelle ein Array mit exakt K Speicherzellen, in der Schleife danach werden alle Elemente gefüllt (da ja i<k gilt und das Zählen bei 0 anfängt).
ganz einfach: Eingabe ist ein zweifacher Zeiger auf char. Du willst damit ein Array von Strings realisieren. Ein String ist ebenfalls ein Array von chars.
Mit
Eingabe=malloc(k*sizeof(char));
reservierst du aber nur k-Bytes, was zu wenig Platz für für k-Zeiger (was auf x86 Rechnern 4*k Bytes entspricht) ist. Richtig wäre:
Eingabe = malloc(k * sizeof(char*));
denn du willst Speicher für k-char-Zeiger reservieren. Wärst du nach FAQ - ANSI C :: Dynamischer Speicher mit malloc/calloc/realloc/free vorgegangen, hättest du sogar so gemacht
Eingabe = malloc(k * sizeof *Eingabe));
was von Anfang, vom Typ von
Eingabe
unabhängig genau viele Bytes reserviert hätte, die du brauchst.Stiefel2000 schrieb:
Zu guter Letzt: Das printf in der Datei ist nur zur Kontrolle des Arrays, das ich gerade eingelesen habe - wie ich im letzten Post erwähnte, scheint das "printf("\n");" in der zweiten for-Schleife sogar Macht über das Laufverhalten meines Programms zu haben - und ich habe keine Ahnung, weshalb das so sein sollte.
das leigt an
printf(*(Eingabe+i));
wie ich schon vorhin gesagt habe. Da du die Zeilen (die Anscheinend keine Leerzeichen enthalten) mit scanf liest, enthalten sie kein '\n' Zeichen.printf
macht einfflush(stdout);
, wenn er das '\n'-Zeichen findet, was in *(Eingabe + 1) nicht vorkommt, somit werden die Ausgaben nicht sofort ausgegeben. Wenn das Programm mit segfault sich ins Nirvane verabschiedet, wird stdout nicht geflusht und somit erscheint nichts.Stiefel2000 schrieb:
EDIT: Was genau bewirkt das "i < ++i" in deiner for-Schleife?
sorry, Tippfehler von mir, es soll nur
++i
stehen.Weil du anscheinend das nicht sauber hinkriegen wirst (du liest die Posts und/oder dein C Tutorial/Buch einfach nicht genau), hier eine dynamisch Lösung:
#include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { FILE *fp; int c; char **lines, **tmp1; char *input, *tmp2; int num_lines, num_chars; if(argc != 2) { fprintf(stderr, "usage: %s file\n", argv[0]); return 1; } fp = fopen(argv[1], "r"); if(fp == NULL) { perror("fopen"); return 1; } lines = NULL; input = NULL; num_lines = num_chars = 0; for(;;) { c = fgetc(fp); if(c == '\n' || c == EOF) { /* Wir haben eine ganze Zeile gelesen, * ins array hinzufügen */ tmp1 = realloc(lines, (num_lines + 1) * sizeof *lines); if(tmp1 == NULL) { /* Kein Speicher mehr */ free(input); break; } lines = tmp1; lines[num_lines] = input; /* input bereinigen für neue Zeile */ input = NULL; num_chars = 0; if(c == EOF) break; /* Ende der Datei oder Lesefehler */ num_lines++; continue; } /* normales Zeichen, in input hinzufügen, +2 wegen \0 */ tmp2 = realloc(input, (num_chars + 2) * sizeof *input); if(tmp2 == NULL) { /* Kein Speicher mehr */ free(input); break; } input = tmp2; input[num_chars] = c; input[++num_chars] = 0; } /* Ausgabe */ int i; for(i=0; i < num_lines; ++i) printf("%0.3d %s\n", i+1, lines[i]); /* Freigabe des Speichers */ for(i=0; i < num_lines; ++i) free(lines[i]); free(lines); fclose(fp); return 0; }
-
supertux schrieb:
Stiefel2000 schrieb:
Ich muss sagen, dass ich nicht sehe, warum ich in Zeile 12 zu wenig Platz reserviere? Ich erstelle ein Array mit exakt K Speicherzellen, in der Schleife danach werden alle Elemente gefüllt (da ja i<k gilt und das Zählen bei 0 anfängt).
ganz einfach: Eingabe ist ein zweifacher Zeiger auf char. Du willst damit ein Array von Strings realisieren. Ein String ist ebenfalls ein Array von chars.
Mit
Eingabe=malloc(k*sizeof(char));
reservierst du aber nur k-Bytes, was zu wenig Platz für für k-Zeiger (was auf x86 Rechnern 4*k Bytes entspricht) ist. Richtig wäre:
Eingabe = malloc(k * sizeof(char*));
Danke für diese Klarstellung, daran hatte ich leider nicht gedacht. Das wird mir wohl ab jetzt die ein oder andere Fehlersuche ersparen :).
supertux schrieb:
Stiefel2000 schrieb:
Zu guter Letzt: Das printf in der Datei ist nur zur Kontrolle des Arrays, das ich gerade eingelesen habe - wie ich im letzten Post erwähnte, scheint das "printf("\n");" in der zweiten for-Schleife sogar Macht über das Laufverhalten meines Programms zu haben - und ich habe keine Ahnung, weshalb das so sein sollte.
das leigt an
printf(*(Eingabe+i));
wie ich schon vorhin gesagt habe. Da du die Zeilen (die Anscheinend keine Leerzeichen enthalten) mit scanf liest, enthalten sie kein '\n' Zeichen.printf
macht einfflush(stdout);
, wenn er das '\n'-Zeichen findet, was in *(Eingabe + 1) nicht vorkommt, somit werden die Ausgaben nicht sofort ausgegeben. Wenn das Programm mit segfault sich ins Nirvane verabschiedet, wird stdout nicht geflusht und somit erscheint nichts.Das bedeutet also, dass ich das printf entfernen kann und das Programm damit keine Probleme haben sollte? Oder muss ich an anderer Stelle noch einen Zeilenumbruch einfügen, damit später keine Probleme auftreten?
supertux schrieb:
Weil du anscheinend das nicht sauber hinkriegen wirst (du liest die Posts und/oder dein C Tutorial/Buch einfach nicht genau), hier eine dynamisch Lösung:
Danke für das Vertrauen in meine Fertigkeiten!
Und natürlich danke für den Quelltext und die Hilfe - wobei mir die Erklärungen der Fehler um einiges wertvoller sind als der fertige Quelltext. Wenn ich nicht genügend Verständnis für die Vorgänge in der Maschine aufbringen kann, dann ist mein Problem nicht die funktionsuntüchtige Software.
-
Stiefel2000 schrieb:
Das bedeutet also, dass ich das printf entfernen kann und das Programm damit keine Probleme haben sollte?
nein, das war nie das Problem, sondern, dass du zu wenig Speicher reservierst und weit über die Grenzen von
Eingabe
geschrieben hast, was früher oder später zu einem segfault führt. Dein printf hat nur den "Todesstoss" gegeben. Guck dir meinen Code an, vor allem im Bezug auflines
, was deinemEingabe
entspricht.Generell ist
printf(variable);
schlecht. Wennvariable
Zeichenfolgen wie '%s' oder ähnlcihes hat, kann das zu segfaults führen, weil printf erwartet, dass das erste Argument ein char* ist, aber beiprintf(variable);
ist das nicht der Fall, also liest irgendwas und das kann auch "verboten" sein, was zum segfault führt. Das ist aber ein anderes Problem, was vielleicht zu deinen Abstürtzen geführt hat, aber weil ich den Inhalt deiner DateiC:\Quelle.txt
nicht kenne, weiß ich es nicht.Stiefel2000 schrieb:
Danke für das Vertrauen in meine Fertigkeiten!
Bitte. Ich hab sowas nicht aus "Bösheit" gesagt, sondern aus Erfahrung, und ich kenne die Threads der letzten Tagen. Du stellst manchmal Fragen auf die du bereits eine Antwort bekommen hast, also was soll ich denn dann denken? Dass du die Sachen nicht genau liest. Viele deine Fehler würde man vermeiden, wenn man unsere Antworten genauer lesen würdest und wenn sie dennoch unverständlich sind, kannst du sagen 'den Teil verstehe ich nicht' anstann einfach loszulegen und irgendwas schreiben.
Stiefel2000 schrieb:
Und natürlich danke für den Quelltext und die Hilfe - wobei mir die Erklärungen der Fehler um einiges wertvoller sind als der fertige Quelltext.
ich hab jedenfalls dir schon paar mal in diesem Thread auf deine Fehler hingewiesen und erklärt und dennoch tust du sie. Darum der Code, als Anhaltspunkt.
-
Auch wenn die letzte Antwort schon ein wenig her ist, wollte ich mich nochmal bedanken. Ich hatte leider erst heute Zeit, das Programm fertigzustellen und muss sagen, dass der Quelltext von supertux an so mancher Stelle ziemlich "inspirierend" war :). Es hat zwar eine ganze Weile gedauert, bis ich alles verstanden hatte, aber danach konnte ich das Programm an einem Stück schreiben - ich musste nur wegen ein paar unerwarteter Steuerzeichen in der Datei hier und da feilen und dann gab's noch kleinere Probleme mit meinen Funktionen... Aber das Programm läuft jetzt wunderbar und ist dank der vielen reallocs sehr viel variabler geworden, als mein ursprünglicher Ansatz es ermöglicht hätte.
-
test
-
Hallo!
Ich hab eine Reihe von Dateien, die sehr ähnliche Namen haben und sich nur um Ziffern unterscheiden, welche ich ja durch Variablen ersetzen kann...
Seien diese drei Daten test1, test2, test3
über snprintf wie, am Anfang dieses Threads erläutert, hab ich mir nun über den char "test" und eine Schleife für i=1, i<4 die Namen dieser Dateien oben zusammengebastelt.
was ich nun machen will, ist die Ausgabe von snprintf, welche ich wie auch hier im Beispiel str genannt habe an fopen übergeben, damit nun in dieser Schleife für die i jeweils der Dateiname gebastelt und an fopen übergeben wird.
Nur erwartet fopen als Eingangsparameter ein char, snprintf gibt das str allerdings als string aus.
Der Rest meines Programmes funktioniert einwandfrei, ich möchte nur gerne diese Lücke überwinden und die generierten Filenamen an fopen übergeben können.
Die wesentliche Frage lautet also, wie ich eine string in eine char umwandeln kann... bei c++ gibt es wohl die Funktion c_str(), aber wie wird das in C gelöst?!
Womöglich ist diese Frage ein Standardfrage, dann gebe ich mich auch mit einem Link auf einen bestehenden Thread zufrieden!
Vielen Dank im Vorraus!
blaM
-
fopen erwartet doch gar keinen einzelnen char, sondern auch einen String, also einen char-Zeiger. Genau wie s(n)printf.
#include <stdio.h> int main(void) { for (int i = 1; i <= 3; i++) { char name[20]; sprintf(name, "test%d", i); FILE *file = fopen(name, "w"); fprintf(file, "Ich bin Datei %d!!!\n", i); fclose(file); } return 0; }
-
Oh Gott, das darf doch nicht wahr sein
Ich hatte schon alles richtig gemacht... der einzige Fehler lag darin, dass ich statt
fopen(str, "r");
in meiner File
fopen("str", "r");
stehen hatte....
Daher kam ständig der Speicherzugriffsfehler zu stande und ich dachte ständig, es läge am Aus- und Eingabeformat.... und das ist mir dann erst in deinem Beispielprog aufgefallen----
Aber dennoch vielen Dank für die Mühe namespace invade!!
-
blaM schrieb:
Die wesentliche Frage lautet also, wie ich eine string in eine char umwandeln kann...
gar nicht, es sind völlig unkompatible Typen. Ein char nimmt nur ein einzelenes Zeichen auf, keine Folge von Zeichen (== String).
blaM schrieb:
Daher kam ständig der Speicherzugriffsfehler zu stande
deshalb überprüft man IMMER, ob die Pointer NULL sind
FILE *file = fopen("str", "r"); if(file == NULL) { perror("fopen"); exit(1); }
-
oh... korrekt! danke vielmals für den Nachtrag!