Zeiger in typedef Variable
-
Hallo.
Mein Programm stürzt ständig ab. Ich habe folgenden Code für die Subfunction, welche den Absturz verursacht (Achtung - Ihr müsst dazu nicht den ganzen Code verstehen - habe im Anschluss beschrieben, um welche Stelle es geht):
int CalcINPF(unsigned long * fpInternalNodes, TNode * fpNode, TQuad * fpQuad, unsigned long fnNode, unsigned long fnQuad, unsigned long fnInternalNodes, unsigned long fMEPN, unsigned int AreaInfluence){ unsigned long fi=0, fj=0, fk=0, fl=0; double * Areas = (double *)calloc(fMEPN+1, sizeof(double)); double * Dist = (double *)calloc(fMEPN+1, sizeof(double)); double SArea=0., SDist=0.; TNode P, E; unsigned int OutputINPFs = 1; for (fi=0;fi<=fnInternalNodes;fi++){ P = fpNode[fpInternalNodes[fi]-1]; do{ Areas[fj] = fpQuad[P.EP[fj]-1].Area; Dist[fj] = sqrt(pow(fpQuad[P.EP[fj]-1].P.x - P.x,2) + pow(fpQuad[P.EP[fj]-1].P.y - P.y,2)); SArea+=Areas[fj]; SDist+=(1./Dist[fj]); }while(++fj<P.nP); SArea/=fj; P.Gamma = (double *)calloc(fj, sizeof(double)); for (fk=0;fk<fj;fk++){ if (AreaInfluence == 1){ P.Gamma[fk] = (((1./Dist[fk]))/(SDist))*(Areas[fk]/SArea); } else { P.Gamma[fk] = (1./Dist[fk])/SDist; } Areas[fk] = 0.; Dist[fk] = 0.; printf("Interpolation factor: %f\n", P.Gamma[fk]); } SArea = 0., SDist = 0., fj=0; } my_free(Areas); my_free(Dist); if (OutputINPFs==1){ for (fi=0;fi<=fnInternalNodes;fi++){ printf("Node number: %lu\n", fpInternalNodes[fi]); P = fpNode[fpInternalNodes[fi]-1]; for (fj=0;fj<P.nP;fj++){ printf("Index fj: %lu\n", fj); printf("Interpolations factor to Element number %lu: %f\n", P.EP[fj], P.Gamma[fj]); } printf("\n"); } } return 0; }
In dem Code kommt eine benutzerdefinierte Variable TNode vor. Diese ist wie folgt definiert:
typedef struct{ double x; double y; double Value[NV]; unsigned int nP; unsigned long * EP; double * Gamma; }TNode;
Die eigentliche Berechnung findet in den Zeilen 9 bis 33 statt. Die Ausgabe in Zeile 30 ist auch korrekt. Anschließend wollte ich die Werte nochmal ausgeben zur Kontrolle. Jedoch führt 44 zum Absturz - also keine Fehlermeldung (beim TCC Compiler). Wenn ich es mit dem LCC Compiler compiliere, bekomme ich Segmentation violation.
Der Fehler wird duch P.Gamma[fj] verursacht. Wenn ich Zeile 44 durch folgenden Code ersetze, läuft das Programm durch:
printf("Interpolations factor to Element number %lu:\n", P.EP[fj]);
Zeile 44 wird kein einziges Mal ausgeführt - es liegt also auch nicht daran, dass fj in der Schleife 42 bis 45 über den Index hinausläuft.
Kurz noch, was das Programm macht. Ein Knoten vom Typ TNode ist Teil von mehreren Vierecken. Also, eine gewisse Anzahl von Vierecken, die sich berühren teilen sich diesen Knoten. Die Anzahl dieser Vierecke ist in TNode.nP gespeichert.
Die Elementnummer der Vierecke ist in TNode.EP[i] gespeichert. Die Vierecke an sich sind in dem Array fpQuad gespeichert, wobei diese vom Typ TQuad sind (auch eine benutzerdefinierte Variable).
Gamma soll jetzt einen Interpolationsfaktor beinhalten, der in 25 oder 27 berechnet wird, je nach Ansatzfunktion. Aber ich denke, dass das nicht so wichtig ist.Vielen Dank für Eure Mühe.
Gruß, CJens
-
Mal ganz kurz die erste Schleife
TNode P, E; // hier hast du eine richtige struct Variable, kein Zeiger for (fi=0;fi<=fnInternalNodes;fi++){ P = fpNode[fpInternalNodes[fi]-1]; // hier wird eine Kopie der struct von fpNode in P abgelegt P.Gamma = (double *)calloc(fj, sizeof(double)); // hier bekommt die Kopie einen neuen Wert für Gamma }
Was kommt von den Werten aus P denn in fpNode an?
.
.
.
.
.
.
.
.
.
.
.
.
Nichts!
-
...das heißt, ich habe den Pointer an eine Kopie von P gegeben, die anschließend wieder überschrieben wird. Ich habe es auf Deinen Rat hin umgebastelt und es funktioniert jetzt, da ich TNode * P den Pointer auf den jeweiligen fpNode Eintrag übergebe. Danke Dirk, folgender Code funktioniert jetzt:
int CalcINPF(unsigned long * fpInternalNodes, TNode * fpNode, TQuad * fpQuad, unsigned long fnNode, unsigned long fnQuad, unsigned long fnInternalNodes, unsigned long fMEPN, unsigned int AreaInfluence){ unsigned long fi=0, fj=0, fk=0; double * Areas = (double *)calloc(fMEPN+1, sizeof(double)); double * Dist = (double *)calloc(fMEPN+1, sizeof(double)); double SArea=0., SDist=0.; TNode * P; unsigned int OutputINPFs = 1; for (fi=0;fi<=fnInternalNodes;fi++){ P = &fpNode[fpInternalNodes[fi]-1]; do{ Areas[fj] = fpQuad[P->EP[fj]-1].Area; Dist[fj] = sqrt(pow(fpQuad[P->EP[fj]-1].P.x - P->x,2) + pow(fpQuad[P->EP[fj]-1].P.y - P->y,2)); SArea+=Areas[fj]; SDist+=(1./Dist[fj]); }while(++fj<P->nP); SArea/=fj; P->Gamma = (double *)calloc(fj, sizeof(double)); for (fk=0;fk<fj;fk++){ if (AreaInfluence == 1){ P->Gamma[fk] = (((1./Dist[fk]))/(SDist))*(Areas[fk]/SArea); } else { P->Gamma[fk] = (1./Dist[fk])/SDist; } Areas[fk] = 0.; Dist[fk] = 0.; } SArea = 0., SDist = 0., fj=0; } my_free(Areas); my_free(Dist); if (OutputINPFs==1){ for (fi=0;fi<=fnInternalNodes;fi++){ printf("Node number: %lu\n", fpInternalNodes[fi]); P = &fpNode[fpInternalNodes[fi]-1]; for (fj=0;fj<P->nP;fj++){ printf("Index fj: %lu\n", fj); printf("Interpolations factor to Element number %lu: %f\n", P->EP[fj], P->Gamma[fj]); } printf("\n"); } } return 0; }
Vielen Dank DirkB.
-
Du solltest auf die unsinnige Variable P verzichten und überall statt
P besser fpNode[fpInternalNodes[fi]-1] verwenden, oder wegen der Übersichtlichkeit
meinetwegenTNode *p; ... p = &fpNode[fpInternalNodes[fi]-1]; und dann natürlich statt P. besser p->
verwenden.
Dein calloc braucht auch irgendwann ein free, das solltest du auch bedenken.
-
...das mit dem TNode * P = &fpNode[i] und P->x habe ich eingefügt. Funktioniert jetzt.
Das free brauche ich nicht, denn diese Daten benötige ich im weiteren Programmverlauf. Jedes calloc reserviert einen Speicherbereich, in welchen die Interpolationsfaktoren für jeden Punkt und jedes der umliegenden Vierecke geschrieben werden. Wenn die Berechnung abgeschlossen ist, gebe ich den Pointer auf das erste Element des Feldes an P->Gamma zurück. Es ist vielleicht etwas unübersichtlich, aber jedes calloc speichert Interpolationsfaktoren für einen weitere Knoten TNode.
Später werde ich immer wieder auf diese Interpolationsfaktoren jedes TNodes zurückgreifen müssen.
-
Trotzdem gilt der letzte Satz von Wutz.
Irgendwann musst du für die Daten ein free machen.
-
...ist doch auch der Speicher wieder frei, oder?
Sonst müsste mein Rechner jetzt schon swappen ohne Ende, denn ich fahre ihn immer nur in den StandBy und hab den Code in der Entwicklungsphase jetzt sicher schon ein paar hundert mal ausgeführt
Lasse mich da aber auch gerne eines besseren belehren...
-
Das Betriebssystem gibt den allokierten Speicher am Ende des Prozesses zwar wieder komplett frei (zumindestens auf den gängigen Betriebssystemen mit virtuellem Speicher), du solltest jedoch dies immer innerhalb deines Programmes tun.
Irgendwann möchtest du diese Funktionen z.B. in einem anderen Kontext laufen lassen (z.B. in einer größeren Schleife) und müßtest dann nachträglich die Speicherfreigabe programmieren.