Speicherfehler

Schnelle objektorientierte, kompilierende Programmiersprache.
Antworten
Daniel200289
Beiträge: 20
Registriert: Mo Aug 11, 2014 12:17 pm

Speicherfehler

Beitrag von Daniel200289 » Di Sep 09, 2014 7:37 pm

Hey Leute,
nun folgendes Problem:
ich will Zeilenweise aus einer Datei laden (maximal 255 Zeichen pro Zeile und maximal 1000 Zeilen) und möchte jede Zeile nun in einem String-Array speichern.

Hier mein Versuch:

Code: Alles auswählen

int zahler2=0;
int i=0;
char histo[1000][256];
int b2;
char ccc2[10000];
char *hilfs;
hilfs=malloc(512);

        while((b2 = fgetc(datei)) != EOF){
		ccc2[p]=b2;
		if(b2!='\n'){
			hilfs[i]=b2;
		}else{
			hilfs[i]='\n';
			strcpy(histo[zahler2],hilfs);
			zahler2++;
			memset(hilfs,'\0',512);
			i=-1;
		}
		if(ccc2[p]=='\n'){
			histzahl++;
		}
		p++;
		i++;
	}
free(hilfs);
fclose(datei);
Nach dem Einlesen soll jede Zeile abrufbar sein wie folgt:

histo[1] wäre Zeile 1,
histo[2] wäre Zeile 2

und so weiter.

Ich glaube mein Code ist auch nicht gerade toll, vielleicht hat jemand eine bessere Idee oder Vorschläge.

Danke schonmal :)

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Speicherfehler

Beitrag von Xin » Di Sep 09, 2014 8:25 pm

Was spricht gegen fgets()?

Wenn möglich kopiere bitte komplette Programme in den Thread. Bei so kleinen Programmen direkt in den Thread, bei größeren Programmen die fraglichen Abschnitte in den Thread und alle erforderlichen Quellen als Anhang.

Nur dann kann man das Programm testen und so den Speicherfehler finden.
Weiterhin: formatiere bitte Deinen Quelltext.

Bitte lies Dir folgendes FAQ durch, damit wir Dir sinnvoll helfen können: Frage formulieren
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Daniel200289
Beiträge: 20
Registriert: Mo Aug 11, 2014 12:17 pm

Re: Speicherfehler

Beitrag von Daniel200289 » Di Sep 09, 2014 8:30 pm

Hier nochmal überarbeitet. Ich würde gerne fgets() benutzen aber kriege die Eingabe nicht als String Array gespeichert.

So funktioniert der Code, nur bei großer Anzahl der Zeilen in der Datei nicht.

Code: Alles auswählen

#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <ctype.h>
#include <unistd.h>



int main(){
	
	char *histo2 = (char*) malloc(12*sizeof(char));
	
	char pfad_his[256];
	FILE *datei;
	int histzahl;
	int b2;
	char ccc2[1000];
	char file[] ="/.testdat";
	int p=0;
	char histo[1000][256];
	
	
	/* Stand History laden */
	
	getcwd(pfad_his, 256);
	strcat(pfad_his,file);
		
	datei = fopen(pfad_his, "r+");
	
	if (datei == NULL){
		histzahl=0;
	}else{
	
	int a=0;
	while((b2 = fgetc(datei)) != EOF){
		
		ccc2[p]=b2;

		if(ccc2[p]=='\n'){
			strcpy(histo2,ccc2);
			histzahl++;
			strcpy(histo[a],ccc2);
			a++;
			memset(ccc2, '\0', sizeof(ccc2));
			p=0;
		}else{
		p++;
		}
	}
	
	//Zum Test
	printf("1: %s",histo[0]); // erster Wert der Datei
	printf("2: %s",histo[0]); // weiter Wert der Datei
			
	
	fclose(datei);
	free(histo2);
}
	
	return 0;
}
Wäre für die Lösung des Problems mit fgets() echt dankbar, am besten noch wenn der Speicher auch dynamisch reserviert wird.

In der Datei .testdat steht im Moment:

nummer1
nummer2
nummer3
nummer4

Das bekomme ich soweit auch raus, aber die Methode ist bei großen Datenmengen irgendwie zum Abstürtzen, keine Ahnung warum.

Hauptproblem: Datei zeilenweise einlesen, abspeichern und abrufen können

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Speicherfehler

Beitrag von Xin » Di Sep 09, 2014 9:05 pm

Daniel200289 hat geschrieben:Hier nochmal überarbeitet.
Viel besser, aber noch nicht gut.
Entweder öffnende Klammer über schließende:

Code: Alles auswählen

if...
{
  ...
}
oder die öffnende Klammer hinter das Konstrukt und die schließende unter das Konstrukt.

Code: Alles auswählen

if... {
  ...
}
In beiden Fällen dazwischen einrücken. Es kann nicht sein, dass zwei schließende Klammern untereinander stehen.
Daniel200289 hat geschrieben:Ich würde gerne fgets() benutzen aber kriege die Eingabe nicht als String Array gespeichert.
Ich habe bisher noch nix von Dir mit fgets gesehen, was nicht funktioniert hat.
Daniel200289 hat geschrieben: So funktioniert der Code, nur bei großer Anzahl der Zeilen in der Datei nicht.

Bitte schreib mal hinter die Variablen, warum Du diese nutzt. Und dann benenne sie auch so. Gerade für ccc2 und p interessiert mich das.
histo2 ist wohl eher ein Experiment von Dir?
Daniel200289 hat geschrieben:Wäre für die Lösung des Problems mit fgets() echt dankbar, am besten noch wenn der Speicher auch dynamisch reserviert wird.
Ich werde Dir keine Lösung präsentieren, denn das gehört zum Programmieren lernen dazu und das ist wirklich eine schöne Übung.

Ich helfe Dir gerne dabei, wenn Du Fragen formulieret.
Daniel200289 hat geschrieben:Das bekomme ich soweit auch raus, aber die Methode ist bei großen Datenmengen irgendwie zum Abstürtzen, keine Ahnung warum.
Auch da müsstest Du konkreter sein, was "große Datenmengen" sind.
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Daniel200289
Beiträge: 20
Registriert: Mo Aug 11, 2014 12:17 pm

Re: Speicherfehler

Beitrag von Daniel200289 » Di Sep 09, 2014 9:09 pm

ich habe versucht einfach nur diese 4 Zeilen

nummer1
nummer2
nummer3
nummer4

in ein Array einzulesen mit fgets, jedoch bekomme ich dann nur irgendwelche Zeichen gespeichert. (habe gerade keinen Code da, versuche es ja mit fgetc)

Hast du spontan einen Einfall, wie es gehen würde, wenn ich die Datei ".test" habe mit dem oben genannten Inhalt und diese in einem Array speichern will? Muss nicht ausformuliert sein aber vielleicht sehe ich dann meinen Denkfehler.
Wichtig ist, dass ich die Zeilen einzeln im dem Array später aufrufen kann.

(Datenmengen der Datei: ist variabel aber bis zu 1000 Zeilen mit je max. 256 Zeichen)

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Speicherfehler

Beitrag von Xin » Di Sep 09, 2014 9:16 pm

Daniel200289 hat geschrieben:jedoch bekomme ich dann nur irgendwelche Zeichen gespeichert. (habe gerade keinen Code da, versuche es ja mit fgetc)
Dein gepusteter Code läuft bei mir - ich bekomme zwei Zeilen angezeigt - entsprechend wie es im Code steht zweimal die gleiche.
Daniel200289 hat geschrieben:Hast du spontan einen Einfall, wie es gehen würde, wenn ich die Datei ".test" habe mit dem oben genannten Inhalt und diese in einem Array speichern will?
Lass die Dateien bitte nicht mit einem Punkt beginnen, das hat unter Unix-Systemen eine Bedeutung - und unter Windows auch.
Nenn sie test.txt, das passt und da ist der Punkt auch richtig verwendet.

Was hast Du denn für Probleme mit fgets()?
Daniel200289 hat geschrieben: Muss nicht ausformuliert sein aber vielleicht sehe ich dann meinen Denkfehler.
Wichtig ist, dass ich die Zeilen einzeln im dem Array später aufrufen kann.
Ich sehe in Deinem Programm keinen Denkfehler, was aber auch daran liegen kann, dass es unglaublich kompliziert aufgebaut ist. :-D

Wirf mal alle Variablen raus, die Du nicht brauchst und den übrigen gib lesbare Namen.
Daniel200289 hat geschrieben:(Datenmengen der Datei: ist variabel aber bis zu 1000 Zeilen mit je max. 256 Zeichen)
Und wo kommt es da zu Speicherfehlern?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

Daniel200289
Beiträge: 20
Registriert: Mo Aug 11, 2014 12:17 pm

Re: Speicherfehler

Beitrag von Daniel200289 » Di Sep 09, 2014 9:23 pm

sobald das Programm ein paar Zeilen einliest (aber auch nur unter Linux, Problem ist jedoch Programm muss unter Linux lauffähig sein). Den Ausschnitt den ich eben gepostet habe ist nur ein kleiner Teil von einem größeren Programm, aber wenn ich in der Datei genug Zeilen gespeichert habe, und die dann beim erneuten aufrufen des Programms abrufen will, kommt es bei folgenden Zeilen zum Speicherabbruch:

Code: Alles auswählen

strcpy(histo2,ccc2);
         ....
         strcpy(histo[a],ccc2);
Ich habe von einem Bekannten schon als Tipp bekommen, das der Speicher halt am besten dynamisch für diese Eingabe alloziiert werden soll und danach wieder freigegeben werden muss.
Jedoch blicke ich da nicht so ganz durch (Programmiere normal nur in Java).

Ich hoffe, ich habe das irgendwie verständlich erklärt :-D

mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: Speicherfehler

Beitrag von mfro » Mi Sep 10, 2014 7:06 am

ich seh' was:

Code: Alles auswählen

ccc2[p]=b2;
                
                if(ccc2[p]=='\n')
                {
                    strcpy(histo2,ccc2);
Hier rufst Du strcpy() auf, um die eingelesenen Zeile in deinen Puffer zu kopieren.
Dummerweise fehlt aber ccc2 das Stringende-Kennzeichen '\0', d.h. strcpy() werkelt, bis es zufälligerweise irgendwo auf eins stößt oder es eben knallt.
Wenn Du an der Stelle das '\n', das Du gerade gefunden hast, duch ein '\0' ersetzt, sollte dein Programm eigentlich funktionieren.

Dann ist es aber immer noch fürchterlich ineffizient (es gibt eigentlich keinen ersichtlichen Grund, die gerade eingelesenen Zeichen nochmal zeichenweise umzukopieren). Wesentlich effizienter wäre, am Anfang einmal per fstat() die Dateigröße zu ermitteln (dann könntest Du den Puffer gleich in der richtigen Größe allokieren) und die ganze Datei auf einen Rutsch per fread() einzulesen. Anschließend brauchst Du nur noch einmal über den Puffer zu laufen um die '\n's durch '\0's zu ersetzen und im gleichen Durchlauf die Zeiger auf die Zeilenanfänge (das jeweils nächste Zeichen) in einem Indexarray wegzuspeichern.

Alternativ speicherst Du die Zeilenanfänge nicht separat, sondern sorgst dafür, daß Du das Pufferende an einer "Doppelnull" ('\0,'\0') erkennst, dann mußt Du allerdings bei jedem Zugriff über den ganzen Puffer laufen und kannst keine Leerzeilen speichern (die mußt Du dann rauswerfen).
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

Benutzeravatar
Xin
nur zu Besuch hier
Beiträge: 8862
Registriert: Fr Jul 04, 2008 11:10 pm
Wohnort: /home/xin
Kontaktdaten:

Re: Speicherfehler

Beitrag von Xin » Mi Sep 10, 2014 9:09 am

mfro hat geschrieben:ich seh' was:
Hier rufst Du strcpy() auf, um die eingelesenen Zeile in deinen Puffer zu kopieren.
Gutes Auge. :-)
mfro hat geschrieben:Dann ist es aber immer noch fürchterlich ineffizient (es gibt eigentlich keinen ersichtlichen Grund, die gerade eingelesenen Zeichen nochmal zeichenweise umzukopieren). Wesentlich effizienter wäre, am Anfang einmal per fstat() die Dateigröße zu ermitteln (dann könntest Du den Puffer gleich in der richtigen Größe allokieren) und die ganze Datei auf einen Rutsch per fread() einzulesen.
Das geht in Richtung Parserbau, auch wenn es ein sehr einfacher Parser ist. Lass den Part erstmal fgets erledigen, so dass er für einzelne Zeilen Speicher anfordern kann.
mfro hat geschrieben:Anschließend brauchst Du nur noch einmal über den Puffer zu laufen um die '\n's durch '\0's zu ersetzen und im gleichen Durchlauf die Zeiger auf die Zeilenanfänge (das jeweils nächste Zeichen) in einem Indexarray wegzuspeichern.
Mit Zeilenanfang meinst Du die Start-Adresse der Zeile, so dass er ein Array

Code: Alles auswählen

char * Lines[1000]
benötigt? ^^
Hübsche Idee. Hüberscher als die nicht mehr mitgequotete Alternative ;-)


@daniel: Wie vertraut bist Du mit Zeigern bisher?
Merke: Wer Ordnung hellt ist nicht zwangsläufig eine Leuchte.

Ich beantworte keine generellen Programmierfragen per PN oder Mail. Dafür ist das Forum da.

mfro
Beiträge: 346
Registriert: Mi Jan 16, 2013 4:58 pm

Re: Speicherfehler

Beitrag von mfro » Mi Sep 10, 2014 10:20 am

Daniel200289 hat geschrieben:... sobald das Programm ein paar Zeilen einliest (aber auch nur unter Linux, Problem ist jedoch Programm muss unter Linux lauffähig sein)...
Hierzu noch was, weil man öfter mal hört "mein Programm läuft unter Windows fehlerfrei, aber mit Linux stürzt es immer ab": dein Programm hat immer denselben Fehler, egal ob unter Windows oder Linux.

Daß es bei Windows nicht abstürzt, liegt lediglich daran, daß sich der Fehler dort nicht unmittelbar auswirkt, weil irgendwo (mehr oder - wahrscheinlich - weniger zufällig) ein Nullbyte im Variablenstack steht, bevor die Page zuende ist, auf die Du legal zugreifen darfst.

Man kann sich jetzt drüber streiten was besser ist. Mir jedenfalls ist es lieber, wenn meine Programmfehler sich noch während des Programmierens deutlich zu erkennen geben und nicht erst Jahre später ;).
It's as simple as that. And remember, Beethoven wrote his first symphony in C.

Antworten