Programmabsturz bei Pointern

Manda

Erfahrenes Mitglied
Hoffe es macht nichts aus, wenn ich "schon wieder " eine Frage stelle. Bräuchte mal einen Tip von euch.
Habe ein struct, lese dort in einer Funktion Werte ein. In einer anderen Funktion, habe ich Formeln (die richtig sind!) und möchte dort einfach Werte ausgeben lassen.
Leider stürzt das Programm dort ab.
Hier mal ein kurzer Blick:

C++:
struct test
{
	double i;
	double j;
	double k;
	double fmin;
	double fmax;
	int schritte;
	double **ue_fkt;
};

main()
{
    parameter();
}

void parameter(void)
{
        struct test ptr;
	struct test *start_pointer = &ptr;
	
	//bsp werte setzen
	ptr.i			 = 100.00;
	ptr.j			 = 0.01500000;
	ptr.k			 = 0.00000180;
	ptr.fmin	    = 100.00;
	ptr.fmax		 = 1000.00;
	ptr.schritte = 21;
       //Unsicher! Ist das der richtige aufurf
	berechnen(start_pointer);
}

void berechnen(test_t *test)
{
for(x=0; x<test->schritte; x++)
	{
		//Formeln zur berechnung
		f = test->fmin + x * (test->fmax - test->fmin) / (test->schritte - 1);
		w = 2 * PI * f;

		hilf1 = pow(w * test->i * test->k,2);
		hilf2 = 1 - w * w * test->j * test->k;
		Re    = hilf1 / (pow(hilf2,2) + hilf1);
		Im    = w * test->i * test->k * hilf2 / (pow(hilf2,2) + hilf1);
		
		//Testen ob man was ausgeben kann - ABER STÜRZT HIER AB!!
		test->ue_fkt[x][0] = f;
		test->ue_fkt[x][1] = Re;
		test->ue_fkt[x][2] = Im;
		test->ue_fkt[x][3] = sqrt(Re*Re / Im*Im);
		test->ue_fkt[x][4] = 180/PI*atan2(Im,Re);
		printf("\nWerte fuer F: %lf"); //erstmal nur f ausgeben
	}
}

Könnt ihr mir sagen ob ich die Funktion richtig aufrufe? Denn, ich bin mir nicht sicher ob die Funktion überhaupt so die Werte mitbekommt um sie anschließend auszugeben:confused:

Danke schonmal!
 
Hallo Manda!

Dein Hauptproblem liegt hier:
Code:
double **ue_fkt;

Dieser Zeiger wird nicht intialisiert, oder anders gesagt: Dieser Zeiger zeigt eigentlich auf nichts (bzw. auf keinen gültigen Speicher). Das bedeutet, dass du diesen Zeiger zuerst initialisieren musst. Die Frage ist natürlich, ob die Grösse des 2-dimensionalen Felder schon anfänglich bekannt ist, oder ob das variabel sein soll. Bei einer fixen Grösse kannst du einfach die Deklration deiner struct ändern:
Code:
double ue_fkt[20][5];

Damit wäre dein Felder jetzt eine "Tabelle" von 20 auf 5 Zeilen/Spalten. Allerdings denke ich, dass du das eher dynamisch möchtest. Das bedeutet, du musst den Speicherplatz während der Laufzeit besorgen. Dies geschieht mit malloc (ich gehe mal davon aus, du orientierst dich eher an C, nicht C++). Wir initialisieren also am Anfang der Funktion berechnen alle unsere Zeiger, zum Beispiel so:
Code:
        test->ue_fkt = (double**)malloc(sizeof(double*) * test->schritte);
	for(int i = 0; i < test->schritte; ++i)
		test->ue_fkt[i] = (double*)malloc(5 * sizeof(double));

Wir initialisieren hier also zuerst die erste Dimension und anschliessend für jedes Feld der ersten Dimension noch die 5 Felder der zweiten Dimension.

Somit haben wir also ein Feld, dass test->schritte * 5 Zeilen/Spalten hat.

Wichtig ist, dass wir diesen Speicher auch wieder freigeben, wenn wir ihn nicht mehr benötigen!
Code:
	for(int i = 0; i < test->schritte; ++i)
		free(test->ue_fkt[i]);
	free(test->ue_fkt);

Der Aufruf deiner Funktion ist soweit korrekt, allerdings verwirrt mich der Parameterteil deiner Funktion:
void berechnen(test_t *test)

Deine struct heisst test, nicht test_t, oder?

Gruss
 
@Cromon - Danke erstmal. Deine Annahmen waren alle korrekt! Speicher dynamisch und ich orientiere mich an C.
Mein struct heist: struct test {..}; Allerdings habe ich noch ein typedef struct test test_t; drin, deswegen dachte ich, ich könnte das so schreiben.
Ich will einfach nur Tabellarisch etwas ausgeben, so etwa:
f - Re - Im - Betrag - Phase
100.00 - 0.0129 - 0.1128 - 0.1136 - 83.4785

(Hoffe man sieht die "Tabelle").
Das mit f klappt schonmal. Was würde denn passieren, wenn ich jetzt beim malloc 5*sizeof(double) nicht mache?
Würde ich denn, nicht 5 Werte ausgeben können?
 
Ja, klar, mit dem typedef geht das natürlich problemlos, dann kannst du test_t lassen.

Wenn du die einzelnen Felder nicht noch initialisierst, dann erhälst du wieder einen Fehler, weil die einzelnen Felder sind ja auch ein Zeiger, aber haben keinen Speicher zugeordnet. Hier mal ein Bild dazu:
http://img29.imageshack.us/img29/4964/ptr.jpg

Wir sehen also, dass ue_fkt in dieser Situation auf ein Feld von 3 Zellen des Typs double* zeigt. Daher müssen wir für diesen Zeiger speicherplatz von 3 * sizeof(double*) reservieren. Ausserdem sehen wir, dass jede dieser 3 Zellen im Bild auf ein Feld von 2 Zellen des Typs double zeigen. Nun müssen wir also für alle 3 zellen Speicherplatz der Grösse 2 * sizeof(double) bereitstellen. Erst dann können wir auf die (in diesem Falle 6) Felder mit ue_fkt[a][b] zugreifen.
 
Ah Super! Habs kapiert, sehr nette Grafik. Danke dir! Falls ich noch Fragen haben sollte, werd ich mich wieder melden, aber ich denke erstmal komme ich weiter.

Schönen Gruß
Manda
 
Hallo zusammen. Ich habe schwierigkeiten beim Speichern der Daten in eine Datei.
Habe folgende Funktion dafür:
C++:
void parameter(void)
{
    struct test ptr;
    struct test *start_pointer = &ptr;

    printf("++++++++++++++++++++++++++++++++++++++++++");
    printf("\nParameter:\n");
    printf("++++++++++++++++++++++++++++++++++++++++++\n");
    ptr.i             = 100.00;
    ptr.j             = 0.01500000;
    ptr.k             = 0.00000180;
    ptr.fmin             = 100.00;
    ptr.fmax         = 1000.00;
    ptr.schritte = 21;

    liste(start_pointer);//Die Daten abspeichern. So richtig?
    berechnen(start_pointer);
}
//HIER wird nur müll gespeichert  :confused:
void liste(test_t *test)
{
    FILE *file;

    file = fopen("test.csv", "w");
    if(file == NULL)
    {
        perror("Fehler beim Oeffnen");
        exit(EXIT_FAILURE);
    }

    while(test != NULL)
    {
        fwrite(test, sizeof(test_t), 1, file);       
    }
    fclose(file);   
}

Ich möchte nur die Daten die ich in der Funktion Parameter habe, einfach in eine Datei speichern. Leider sehe ich, wenn ich sie dann öffne, nur Sonderzeichen und sie ist viele MB groß, was nicht sein kann.
Mache ich beim fwrite was falsch?
 
Code:
while(test != NULL)

Das ist irgendwie komisch. Überlege dir mal, welche Möglichkeiten diese Schleife hat in deinem Fall:
Entweder keinmal oder unendlichmal durchlaufen.

Da du ja nur eine struct abspeichern willst, reicht es, wenn du die Schleife ganz weglässt.

Dass da nur kryptische Zeichen drinstehen ist normal, da du ja einfach ein Abbild des Speichers an der Stelle, auf die test zeigt in die Datei schreibst. Wenn du die Datei dann öffnest (mit dem Texteditor), dann wandelt dieser byte für byte in Zeichen um.
 
Hmm ok, ich dachte mir, es sollte es solange schreiben, bis der *test auf NULL zeigt. Aber das mit den kryptischen Zeichen versteh ich nicht ganz. Wie würde er denn das umwandeln wenn ich es als txt Datei öffne?
Also was ich erreichen will ist ja nur, dass ich das sehe was in der Funktion parameter() steht (Den Text und die Werte).

Kann ja mal die ganze Funktion zeigen
C++:
void parameter(void)
{
	struct test ptr;
	struct test *start_pointer = &ptr;
	
	//bsp werte setzen
	ptr.i			 = 100.00;
	ptr.j			 = 0.01500000;
	ptr.k			 = 0.00000180;
	ptr.fmin	    = 100.00;
	ptr.fmax		 = 1000.00;
	ptr.schritte = 21;
	
	system("cls");
	printf("++++++++++++++++++++++++++++++++++++++++++");
	printf("\nParameter:\n");
	printf("++++++++++++++++++++++++++++++++++++++++++\n");
	printf("\nWert I		  : %.2lf", ptr.i);
	printf("\nWert J		  : %lf", ptr.j);
	printf("\nWert K	  	  : %lf", ptr.k);
	printf("\nUntere Grenze	  : %.2lf", ptr.fmin);
	printf("\nObere  Grenze	  : %.2lf", ptr.fmax);
	printf("\nSchritte	  : %d", ptr.schritte);
	printf("\n++++++++++++++++++++++++++++++++++++++++++");
	liste(start_pointer);
	berechnen(start_pointer);
}
 
Du musst dir vorstellen, dass ja deine struct grundsätzlich nichts anderes ist als eine Zusammenfassung von Variabeln in einem Speicherbereich. fwrite nun möchte als Parameter den Typ void* und die Grösse in bytes, die in die Datei geschrieben werden sollen.

Dann werden einfach diese Anzahl bytes ab der Adresse des void*-Parameters in die Datei geschrieben. Du weisst vielleicht, dass ein Zeichen grundsätzlich ja eine Zahl zwischen 0 und 255 ist (oder anders gesagt: ein Byte). Und genau das verwendet der Texteditor. Er liest Byte für Byte ein und stellt das Zeichen dar, wofür diese Zahl steht.

So würde folgendes zum Beispiel in der Textdatei "A" reinschreiben:
Code:
struct sB
{
unsigned char val;
};

int main()
{
    sB sb;
    sb.val = 65;
    FILE* pFile = fopen("Test.txt", "w");
    if(pFile)
        fwrite(&sb, sizeof(sB), 1, pFile);
}

Warum ist das so? 65 ist der ASCII Code für 'A'. Der Texteditor liest also Byte für Byte aus und findet da 65. Dies heisst für ihn 'A', also stellt er 'A' dar.

Möchtest du wirklich die 65 drin haben, so müsstest du das so einrichten:
Code:
struct sB
{
unsigned char val;
};

int main()
{
    sB sb;
    sb.val = 65;
    FILE* pFile = fopen("Test.txt", "w");
    if(pFile)
        fprintf(pFile, "%u", sb.val);
}
 
Tut mir leid, dass ich vielleicht nerve, aber ich habe das Gefühl, dass ich das fwrite eigentlich so benutze, wie du es meinst.
Oder ich stell mich bisschen zu blöd an:(
Ich poste mal meine Funktion, die ich bisher habe (so wie sie sein sollte):
Die Funktion wird aus einem Menü aus gestartet, mit den parametern, die dort deklariert worden sind (diese zeigen auf NULL). Hier werden sie dann benutzt.
C++:
void schwingkreisparameter(FILE *out, schwingkreis_t *schwingkreis)
{
	struct schwingkreis ptr;
	schwingkreis = &ptr;
	out			 = stdout;
		
	ptr.r			 = 100.00;
	ptr.l			 = 0.01500000;
	ptr.c			 = 0.00000180;
	ptr.fmin	    = 100.00;
	ptr.fmax		 = 1000.00;
	ptr.schritte = 21;

	system("cls");
	printf("++++++++++++++++++++++++++++++++++++++++++");
	printf("\nSchwingkreisparameter:\n");
	printf("++++++++++++++++++++++++++++++++++++++++++\n");

	fprintf(out, "\nWiderstandswert			 : %.2lf  Ohm", ptr.r);
	fprintf(out, "\nInduktionswert			 : %lf H", ptr.l);
	fprintf(out, "\nKapazitaetswert			 : %lf F", ptr.c);
	fprintf(out, "\nFrequenzintervall - untere Grenze: %.2lf   Hz", ptr.fmin);
	fprintf(out, "\nFrequenzintervall - obere  Grenze: %.2lf  Hz", ptr.fmax);
	fprintf(out, "\nAnzahl der Schritte		 : %d", ptr.schritte);
	
	printf("\n++++++++++++++++++++++++++++++++++++++++++");

	out = fopen("schwingkreis.csv", "w");
	if(out == NULL)
	{
		perror("Fehler beim Oeffnen");
		exit(EXIT_FAILURE);
	}
       //Ich glaube ich benutze es so, wie man es machen muss.
	fwrite(schwingkreis, sizeof(schwingkreis_t), 1, out);
	
	/*
	printf("\nWiderstandswert			 : %.2lf   Ohm", ptr.r);
	printf("\nInduktionswert			 : %lf H", ptr.l);
	printf("\nKapazitaetswert			 : %lf F", ptr.c);
	printf("\nFrequenzintervall - untere Grenze: %.2lf   Hz", ptr.fmin);
	printf("\nFrequenzintervall - obere  Grenze: %.2lf  Hz", ptr.fmax);
	printf("\nAnzahl der Schritte		 : %d", ptr.schritte);	
	*/
	getch();
//	liste(start_pointer);
EDIT:	menu(out, schwingkreis);		
}
Ich kriege eine Ausgabe auf der Konsole (die richtig ist) und er erstellt auch eine Datei. Nur beim Öffnen (als txt-Datei) kriege ich nicht das raus, was ich auf der Konsole sehe, sondern nur Zeichen.
Wahrscheinlich ist das ein blöder Fehler, den ich jetzt überhaupt nicht sehe :confused:

Könnte ich den pointer "out" auch wieder zurückgeben an das menu? Und das dann weiter an eine andere Funktion, so dass erstmal alle Daten gesammelt werden und ganz zum Schluss es die Datei erzeugt?
Am Ende rufe ich dann eine Funktion auf:
C++:
void liste(FILE *out, schwingkreis_t *schwingkreis, char tz)
Die dieses file dann bekommt und (tz=trennzeichen; Daten sollen durch komma getrennt sein) und hier dann das File erzeugt?
So könnte ich es in der Funktion "parameter", das File erzeugen rausnehmen oder?
Ich hoffe ich bringe dich gerade nicht durcheinander :)
 
Zuletzt bearbeitet:
Zurück