Guten Abend,
ich versuche im Moment ein Programm für die PlayStation Portable zu zu
schreiben. Dabei möchte ich eine ganze Textdatei, ohne die
Formatierungszeichen (EOF und Zeilenumbruch) in einen String speichern
um ihn später weiterverarbeiten zu können.
Leider hängt sich die PlayStation sofort nach dem starten des Programms
auf. Habt Ihr eine Idee woran es liegen könnte?
Hier mein Code
1
int main() {
2
3
SetupCallbacks();
4
pspDebugScreenInit();
5
6
int Zeichenanzahl = 0;
7
char Zeichen;
8
char *Inhalt;
9
10
FILE *tf;
11
tf = fopen("test.txt","rb");
12
if(tf==NULL) {
13
pspDebugScreenPrintf("Laden der Datei fehlgeschlagen\n"); }
14
else{ pspDebugScreenPrintf("Laden der Datei war erfolgreich\n");}
15
16
while(!feof(tf))
17
//while(Zeichen!=EOF)
18
{
19
Zeichen = fgetc(tf);
20
21
if(Zeichen!='\n')
22
{
23
Zeichenanzahl++;
24
Inhalt = (char *) malloc(Zeichenanzahl);
25
strcat(Inhalt,Zeichen);
26
}
27
}
28
29
fclose(tf);
30
pspDebugScreenPrintf("Inhalt der Datei lautet:\n\n%s",Inhalt);
31
32
sceKernelSleepThread();
33
return 0;
34
}
Das gesammte Projekt lässt sich problemlos compilieren. Keine Warnungen
oder sonstiges. Auf dem Bildschirm wird aber auch keine Ausgabe
getätigt. Daher vermute ich, das es ein proböem beim Laden der Datei
gibt. In etlichen vorherigen Projekten gab es aber keine Probleme.
MfG
>if(tf==NULL) {>pspDebugScreenPrintf("Laden der Datei fehlgeschlagen\n"); }
Da sollte es dann auch nicht weitergehen, also exit() einfügen oder
etwas ähnliches, ansonsten knallt es weiter unten.
Auch sehe ich malloc aber kein free, lass das nicht den Karl-Heinz
sehen!
Du allozierst für jedes Zeichen den ganzen Puffer, jeweils eine Stelle
mehr.
Wenn da also 100 Zeichen kommen, allozierst du 100+99+98... Stück. Das
ist auf alle Fälle schonmal Banane.
Naja, zumindest muss Dein Code ja "Laden [...] erfolgreich" oder "...
fehlgeschlagen" ausgeben; daran siehst Du ja, ob die Datei erfolgreich
geöffnet wurde.
Diese zwei Zeilen:
1
Inhalt = (char *) malloc(Zeichenanzahl);
2
strcat(Inhalt,Zeichen);
an der gezeigten Stelle sind natürlich völliger Blödsinn, da nach jedem
gelesenen Zeichen ein neuer Speicherbereich allokiert wird und das neue
Zeichen an den Anfang dieses Bereichs kopiert wird.
Ich ahne ungefähr, was Du vorhast; in diesem Falle wäre realloc()
angebracht.
Effizienter wäre es allerdings, den Speicher nicht byteweise zu
reallokieren, sondern blockweise (z. B. in 4K-Blöcken).
So, das Problem liegt wie Ihr alle auch schon sagtet, bei
1
Inhalt = (char *) malloc(Zeichenanzahl);
Wenn ich es so mache, läuft es ohne Probleme. Nur habe ich jetzt eine
feste Größe definiert. Ich möchte es aber dynamisch haben.
1
char Inhalt[5000];
2
3
...[...]...
4
5
while(!feof(tf))
6
//while(Zeichen!=EOF)
7
{
8
Zeichen = fgetc(tf);
9
10
if(Zeichen!='\n')
11
{
12
Zeichenanzahl++;
13
Inhalt[Zeichenanzahl]=Zeichen;
14
}
15
}
16
17
fclose(tf);
Also muss ich mir nur noch einmal anschauen, wie man einen String
dynamisch vergrößern kann. Habe sowas seit Ebigkeiten nicht mehr
gemacht.
Danke ann alle.
MfG
Klaus Wachtler schrieb:> realloc()
Das ist mein Problem. Bei realloc hängt sie sich jedes mal auf. Ich
schau mir schon verzweifelt die Referenzen an. Irgendwo muss ich was
übersehen haben.
Hallo Freak
Statt realloc() kannst du einfach einen genug grossen Speicher am Anfang
reservieren.
mit fseek() springs du ans ende der Datei, dann fragst du mit ftell()
die Position ab, somit weisst du wie gross die Datei ist.
Danach reserviertst du size + 1 mit malloc, das ist auf jeden Fall genug
Speicher.
Danach kannst du Zeichen für Zeichen einlesen (wenn auch nicht besonders
performant) und schreibst als letztes ein 0 ('\0') in das Array, und
somit hast du einen String.
Das du zufiel Speicher reserviert hast ist nicht so schlimm, sofern die
der Speicher nicht ausgeht, du könntest dann mit strlen() und strncpy()
das in einen neuen Speicher kopieren, der die exakte Grösse hat.
FILE * fp = fopen(...);
fseek(fp, 0, SEEK_END); // ans ende
long size = ftell(fp);
fseek(fp, 0, SEEK_SET); // wider an den Anfang
char * tmp = malloc(size + 1);
// hier einlesen
int len = strlen(tmp);
char * str = malloc(len + 1);
strncpy(str, tmp, len);
free(tmp); // Speicher freigeben!
Auch str muss mit free freigegeben werden, wenn nicht mehr gebraucht.
Alle angaben ohne Gewähr, nicht getestet...
mfg Andreas
Freak schrieb:> Klaus Wachtler schrieb:>> realloc()>> Das ist mein Problem. Bei realloc hängt sie sich jedes mal auf. Ich> schau mir schon verzweifelt die Referenzen an. Irgendwo muss ich was> übersehen haben.
realloc ist eigentlich problemlos, man muss nur darauf achten dass keine
Speicherlecks entstehen wenn die Funktion fehlschlägt:
Inhalt[Zeichenanzahl-1]=Zeichen; //Da Array bei 0 beginnt
16
}
17
}
Ich öffne die Datei und lese das erste Zeichen. Damit wird Zeichenanzahl
auf 1 erhöht. Anschließend erweitere ich den String auf 2
(Zeichenanzahl+1), da das Terminierungszeichen am Ende dazukommt.
Schlussendlich schreibe ich an Position Zeichenanzahl-1 (da Arrays mit 0
beginnen) das ausgelesene Zeichen.
Aber warum klappt es nicht?
Initialisierst du auch Inhalt mit NULL?
Probier mal lieber das Beispiel von Andreas B.
Du kannst ja ganz am Ende nochmal ein realloc machen, wenn du meinst du
hast zuviel Speicher belegt.
Wer keine Rückgabewert anschaut, wird nicht lange programmieren.
Sollen wir raten, was realloc bei dir liefert?
Oder was in den Programmteilen steht, die keiner sieht?
Freak schrieb:> Ich versteh es langsam nicht mehr.>...> Aber warum klappt es nicht?
WAS heisst "klappt nicht"?
Der Code den du gepostet hat hat keinen Offensichtlichen Fehler din.
Bendenke aber, normalerweise vergrössert realloc den Speicher nicht,
sondern alloziiert einen neuen Speicherbereich und kopiert alles vom
alten Speicher in den neuen Speicher, und gibt dann den alten Speicher
frei.
Das ist extrem langsam. (Komplexität O(n^2) in etwa, falls dir das was
sagt)
Wenn dann machst du ein realloc alle 1024 Zeichen oder so, oder eben
ftell.
mfg Andreas
Andreas B. schrieb:> Das ist extrem langsam. (Komplexität O(n^2) in etwa, falls dir das was> sagt)
evtl. langsam ja, aber wieso O(n^2)? Bei einem realloc(): nein oder bei
allen zusammengenommen: notfalls ja?
Andreas B. schrieb:> Der Code den du gepostet hat hat keinen Offensichtlichen Fehler din.
Das würde ich so nicht sagen.
Den Rückgabewert von realloc() zu ignorieren, ist nicht nett.
Klaus Wachtler schrieb:> Andreas B. schrieb:>> Das ist extrem langsam. (Komplexität O(n^2) in etwa, falls dir das was>> sagt)>> evtl. langsam ja, aber wieso O(n^2)? Bei einem realloc(): nein oder bei> allen zusammengenommen: notfalls ja?
Ja sorry, hättes besser weggelassen.
Ich meinte alles Zusammen O(n^2) weil realloc oftmals kopieren muss.
Wird statt realloc am Anfang genug Speicher reserviert läuft das ganze
mit O(n).
Beweisen kann ich die Behauptung nicht, da ich mich nicht mit der PSP
auskenne...
Aber wahrscheinlich ist es schneller ohne realloc...
mfg Andreas
Wie du schon sagtest: man muß ja nicht byteweise verlängern.
In so einem Fall bietet es sich an, entweder erst die Dateilänge zu
bestimmen, oder bei Bedarf immer zu verdoppeln o.s.ä..
Klaus Wachtler schrieb:> Oder was in den Programmteilen steht, die keiner sieht?
Da steht folgendes. Nichts relevantes für das Problem.
1
int main() {
2
3
SetupCallbacks();
4
pspDebugScreenInit();
5
6
int Zeichenanzahl = 0;
7
char Zeichen;
8
char *Inhalt;
9
//char Inhalt[5000];
10
11
FILE *tf;
12
tf = fopen("test.txt","rb");
13
if(tf==NULL) {
14
pspDebugScreenPrintf("Laden der Datei fehlgeschlagen\n");
15
sceKernelExitGame();
16
}
17
else{ pspDebugScreenPrintf("Laden der Datei war erfolgreich\n");}
Andreas B. schrieb:> Der Code den du gepostet hat hat keinen Offensichtlichen Fehler din.
So sehe ich das auch und trotzdem stimmt was nicht. Ich gehe aber nun
davon aus, dass es systembedingt ist.
Nun bleibt noch die Möglichkeit - wie auch schon gesagt wurde - vorher
die Dateigröße/Zeichenanzahl zu bestimmen. Nur wollte ich mir die
Rechenzeit dafür sparen. Wenn es aber nicht anders geht, dann eben so.
Ich danke allen die mir bei der Problembeseitigung geholfen haben.
Einen guten Rutsch. :)
MfG
Freak schrieb:> Nur wollte ich mir die> Rechenzeit dafür sparen. Wenn es aber nicht anders geht, dann eben so.> Ich danke allen die mir bei der Problembeseitigung geholfen haben.
Und du meinst, das ständige realloc mit umkopieren ist schneller?
Und realloc muss beim ersten Aufruf einen NULL-Zeiger bekommen.
Man könnte so ein Programm natürlich auch mal auf dem PC ausprobieren
(ohne PSP Spezifika) und dort debuggen... nur so eine Idee...
Und wer wenn nix läuft beginnt auf einzelne bytes und ein paar
millisekunden für das bestimmen der Dateigröße hin optimiert dem ist eh
nicht mehr zu helfen ;)