Dynamische Speicherverwaltung in C

Schnetze

Cadet 2nd Year
Registriert
Okt. 2021
Beiträge
20
Hallo zusammen,
Ich steh mittlerweile schon etwas länger auf dem Schlauch und verstehe nicht, was bei meinem Programm falsch ist.
und zwar: ich habe eine folgendes Programmcode:

typedef double H;
struct Vec
{
H *dat;
size_t siz;
};
void vec_init(struct Vec *sel, size_t n, const H *ini)
{

sel=malloc(n*sizeof(struct Vec));
if(sel)
{
for(int i=0;i<n;i++)
{
*(sel->dat)=*ini;
sel++;
}
}
else
{
printf("Fehler\n");
}
}
Das Programm soll den Inhalt von allen n Vectors mit dem Initialwert füllen. Leider liefert es mir einen Segmentation Fault, aber ich weiß nicht warum. Der Segmentation Fault tritt in der Zeile *(sel->dat)=*ini auf. Eigentlich müsste malloc ja den Speicherbereich von n Vectors reservieren? Wo liegt hier mein Denkfehler?

MfG. und Danke im Voraus!
 
Editiere bitte erstmal dein snippet und packe es in einen code block, da wo die 3 senkrechten punkte sind, Symbol sieht so aus: </>
 
  • Gefällt mir
Reaktionen: kuddlmuddl und Schnetze
typedef double H; struct Vec { H *dat; size_t siz; }; void vec_init(struct Vec *sel, size_t n, const H *ini) { sel=malloc(n*sizeof(struct Vec)); if(sel) { for(int i=0;i<n;i++) { *(sel->dat)=*ini; sel++; } } else { printf("Fehler\n"); } }}
 
Dein Problem ist hier der Umgang mit Pointern und dessen Intialisierung und Allozierung und Zugriff.
Schau dir unter diesem Aspekt nochmal das Member "dat" der Struktur "Vec" an.
Ich hoffe das hilf etwas um auf das Problem zu kommen.
 
  • Gefällt mir
Reaktionen: lokked und Schnetze
Erstmal danke für den Input. Leider hab ich schon relativ viel probiert (auch meine jetzige Überlegung, statt sel=malloc(n*sizeof(struct Vec)), sel->dat=malloc(n*sizeof(H)) zu machen hat auch nix gebracht.) Bin ich mit meiner jetzigen Überlegung auf dem richtigen Weg?
 
Wenn es mit n Vektoren nicht funktioniert, mach doch mal einen Schritt zurück. Wie würdest du denn einen einzelnen Vector mit 4 Einträgen anlegen, und diese 4 Einträge auf 42 setzen.

Code:
typedef double H;
struct Vec {    
  H *dat;
  size_t siz;
 };

int main(){
  struct Vec myvec;

   //was muss jetzt gemacht werden, um einen Vektor mit den Elementen [42,42,42,42] zu erhalten ?
}


Außerdem: Die Funktion vec_init soll n Vektoren anlegen. Aber wie viele Elemente soll jeder Vektor enthalten?
Vom Namen her würde für mich die Funktion mehr Sinn machen, falls sie einen einzelnen,existierenden Vektor mit n Werten befüllen soll.
 
Zuletzt bearbeitet:
in einer funktion als zeiger übergeben so oder?
for(int i=0;i<4;i++) { *(myvec->dat)=*ini myvec->dat++; }
ja glaub auch, dass nur ein einziger vektor angelegt werden muss.
 
Zuletzt bearbeitet:
Schnetze schrieb:
Erstmal danke für den Input. Leider hab ich schon relativ viel probiert (auch meine jetzige Überlegung, statt sel=malloc(n*sizeof(struct Vec)), sel->dat=malloc(n*sizeof(H)) zu machen hat auch nix gebracht.) Bin ich mit meiner jetzigen Überlegung auf dem richtigen Weg?

Der Vorschlag von striker ist hier gold richtig. Ich denke auch du solltest nochmal einen Schritt zurück gehen und erstmal ohne eine struct im vector arbeiten.

Versuche doch einmal einen vektor z.B. von int anzulegen und wie vorgeschlagen alle Elemente mit 42 zu initialisieren.

Wie würdest du es statisch machen (z.B. fix mit 4 Elementen) und entsprechend initialisieren ?
Wie würdest du es dynamisch machen, also beliebige Anzahl von elementen ?
 
  • Gefällt mir
Reaktionen: Schnetze
habs jetzt mal mit integers in der main probiert. kommt der gleiche fehler...

Dynamisch gehts mittlerweile auch, aber ohne struct. Wenn ich die struct wieder einfüge kommt der segmentation fault. dat derefernziere ich ja mit *(sel->dat) oder? Stehe grad echt auf dem Schlauch
 
Zuletzt bearbeitet:
Welcher Fehler kommt denn bei der dynamischen Version Vektor mit int? Der Code sollte ohne Probleme funktionieren, siehe https://godbolt.org/z/ddP4cevas


Du kannst auch bei dynamisch allokierten Arrays ganz normal dat[i] = 42 schreiben. Man muss nicht *(dat + i) = 42 schreiben.

intVec.dat++ Warum wird das gemacht? dat soll doch immer auf der erste Element des Vektors zeigen.

In deiner statischen Version wird durch printf("%i",*(intVec.dat)); in jeder Schleifeniteration das erste Element ausgegeben, nicht das i-te Element.

Übrigens: In keinem deiner Codes wird die Membervariable size initialisiert.



Ich habe hier mal eine Vorlage für ein Program erstellt. Kannst du es vervollständigen?

Code:
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

struct Vec
{
   int *dat;
   size_t siz;
};

void construct_vector(struct Vec* vec, size_t num_elements, int init_value);
void destruct_vector(struct Vec* vec);
void print_vector(struct Vec vec);


void construct_vector(struct Vec* vec, size_t num_elements, int init_value){
    // initialize Vec member dat
    
    
    
    // initialize Vec member siz
    
    

    // set all elements of vector to init_value


    
}

void destruct_vector(struct Vec* vec){
    // deallocate memory of Vec member dat
    
    
    
}

void print_vector(struct Vec vec){
    //print all elements of the vector
    
    
    
}

int main()
{
    struct Vec intVec;
    construct_vector(&intVec, 4, 42);

    print_vector(intVec);

    destruct_vector(&intVec);
    return 0;
}
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Schnetze
Schnetze schrieb:
Das Programm soll den Inhalt von allen n Vectors mit dem Initialwert füllen. Leider liefert es mir einen Segmentation Fault, aber ich weiß nicht warum. Der Segmentation Fault tritt in der Zeile *(sel->dat)=*ini auf. Eigentlich müsste malloc ja den Speicherbereich von n Vectors reservieren? Wo liegt hier mein Denkfehler?
Ich glaube du hast nicht verstanden worauf @svkra1973 hinauswollte.
Code:
*(sel->dat) = *ini
ist einfach eine Dereferenzierung eines nicht initialisierten Pointers. Das gibt eine Schutzverletzung/einen Segfault, da im Zeiger erstmal irgendein undefinierter Wert steht, der als Speicheradresse interpretiert wird.

Was mir nicht klar ist, ist wie deine Vector-Implementation gedacht ist.
Sinvoll wäre so eine Struct zur Verwaltung von Heap-Objekten.
Es gibt eine Member Variable wie size und einen Pointer auf einen sog. backing array, der im Heap liegt und damit nicht erst kopiert werden muss.

Das wäre bei dir dann der Array vom Typ H
Code:
*ini
in deiner Funktion vector_initialize().
In dem Fall würde:
Code:
sel->dat = ini;
sel->siz = n;
schon ausreichen.
Du kopierst einfach die Speicheradresse vom ini-Array und legst sie in deiner Struct ab.
Lebenszeit und Gültigkeit zu managen ist dann deine Aufgabe. Kopieren musst du - ja sollst du eigentlich nichts. Oder was war der Gedanke dahinter?
 
  • Gefällt mir
Reaktionen: Schnetze
also funktionieren tuts jedenfalls ohne segmentation fault. wenn ich die init variable jetzt aber wieder als const zeiger übergeb bekomm ich wieder den segmentation fault. woran liegt das, wenn ich ja eh den Zeiger mit *(sel->dat)=*ini dereferenzier? Mein aktueller Code sieht so aus:

@lokked das geht leider nicht, da laut Vorgabe, der Pointer *ini konstant sein muss. wenn ich statt *ini irgendeinen Wert wie z.B. 4 einsetze bekomm ich den gleichen Fehler..
 
Zuletzt bearbeitet:
Schnetze schrieb:
vec->dat=malloc(num_elements*sizeof(int)); if(vec->dat) { *(vec->dat)=init_value; vec->siz=num_elements; vec=vec-vec->siz; }
Möchte @striker159 jetzt nicht zuvorkommen, aber schonmal etwas feedback geben.

Du hast nun schon mal das Member dat korrekt angelegt. Das meinte ich ursprünglich, allerdings ist das nur die eine Hälfte der Medaille ;)

Die danach folgende Initialisierung ist noch nicht korrekt und auch die print_vector funktion erscheint mir nicht korrekt. Dadurch das beide Stellen nicht korrekt umgesetzt sind, wirkt es als wäre es korrekt von der Ausgabe her, es passiert aber nicht das was du eigentlich möchtest.

Ich denke das wird deutlich wenn du versuchen würdest anstelle fix den Wert 42, den Vektor theroretisch wie folgt zu befüllen : 42,43,44,45 (ich weiß das die bisherige API das nicht hergibt, du solltest es, stand jetzt, auch nicht umsetzen. Es soll nur als denk-anstoss dienen).

In der print_vector Methode hast du eine Schleife mit der Variablen "i", du benutzt "i" aber überhaupt nicht.
Du möchtest ja eigentlich alle Elemente des vec->dat Members ausgeben.
Analog gilt dies für deine "befüllung" des "dat" members in der "construct_vector" funktion.
Orientiere dich hier vielleicht nochmal an der Schablone von striker.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Schnetze
ist mir mittlerweile auch aufgefallen :)
warum funktionierts hier aber wenn ich die init value als double pointer übergeb nicht?
und warum funktioniert vec=vec-vec->siz? müssts nicht eigentlich lauten vec->dat=vec->dat-vec->siz? weil ja nur siz Elemente von int *dat reserviert wurden und vec ja nur aus einer einzelnen Adresse besteht?
 
Zuletzt bearbeitet:
Schnetze schrieb:
warum funktionierts hier aber wenn ich die init value als double pointer übergeb nicht?
Wenn ich ehrlich bin, verstehe die Frage jetzt nicht 100% .
Eine double braucht mehr Platzt im Speicher, als eine int. Du kannst eine double nicht ohne Datenverlust in einer int speichern. Du müsstest dafür an allen relevanten Stellen eine double verwenden, oder aber damit leben das die Übergebene double auf einen integer-wert gerundet wird bei der Übergabe an construct_vector.

Schnetze schrieb:
und warum funktioniert vec=vec-vec->siz? müssts nicht eigentlich lauten vec->dat=vec->dat-vec->siz? weil ja nur siz Elemente von int *dat reserviert wurden und vec ja nur aus einer einzelnen Adresse besteht?
Was ist deine Intention von der Zeile generell ? Aus meiner Sicht ergibt das keinen Sinn.
Der verschiebst hier die Adresse von vec um num_elements bytes nach links.
Mir ist nicht klar, was du erreichen möchtest.
 
  • Gefällt mir
Reaktionen: Schnetze
seh grad, das mit dem verringern hat keine auswirkungen. aber warum gehts mit int ini, aber mit const double *ini nicht?

Edit: habs geschafft, war ein fehler von der print funktion, die ich fehlerhaft modifiziert hatte.
Vielen Dank für eure Mühe mir das Thema näherzubringen!
 
Zuletzt bearbeitet:
Schnetze schrieb:
Edit: habs geschafft, war ein fehler von der print funktion, die ich fehlerhaft modifiziert hatte.
Vielen Dank für eure Mühe mir das Thema näherzubringen!
Na dann , glückwunsch :)
 
  • Gefällt mir
Reaktionen: Schnetze
Hier noch eine verbesserte Print Funktion aus Post #14 , die vec.dat nicht modifiziert. Deine Version funktioniert zwar auch, aber nur, weil der Vektor per Kopie an die Funktion übergeben wird, nicht per Pointer .

Code:
void print_vector(struct Vec vec){ 
   //print all elements of the vector   
   printf("%lu\n", vec.siz) ;
   for(int i=0;i<vec.siz;i++)  {  
       printf("%i\n",vec.dat[i]);
    }      
 }

Falls du noch weiter üben willst, könntest du eine Funktion schreiben, die die Größe eines existierenden Vektors verdoppelt. Die Elemente, die vorher in dem Vektor vorhanden sind, sollen nach dem Vergrößern unverändert an der gleichen Position zu finden sein.
 
  • Gefällt mir
Reaktionen: Schnetze
Danke! :)
hab jetzt leider wieder ein neues Problem, wo ich nicht weiter weiß...
die zweite aufgabe lautet, man soll zum schluss ein element anhängen, aber es scheitert bereits bei der initialisierung. Der Test 1 passed zwar (initialisiere und free das dynamisch erzeugte Feld), aber der Test 2 (hänge hinten ein Element ran und lösche das letzte Element) failed, weil angeblich die initialisierung, vec.dat==NULL nicht gegeben ist, und jetzt weiß ich nicht wo ich den fehler suchen soll, weil die initialisierung passed ja. Könnte ich jemanden vllt privat den Code schicken? Weil ich möchte den Code nur ungern veröffentlichen.🙄
 
Zurück
Oben