C Speicherzugriffsfehler warum?

Warhorstl

Commodore
Registriert
Nov. 2008
Beiträge
4.613
Hi!

Mein Tutor ist leider Gottes eine Flasche und nach 2 Stunden Fehlersuche bekomme ich immer noch einen Fehler.

Ausgabe ist:
yolo
yolo
yolo
yolo
yolo
wow, much math
Speicherzugriffsfehler (Speicherabzug geschrieben)

Sprich, das Programm läuft komplett durch, aber trotzdem wird irgendwo ein Fehler produziert.

Das Programm besteht aus einer Bib project.h und einer main.c. Ich habe beide Dateien mal auf den relevanten Part verkürzt.

Kurze Erklärung: Es wird ein Vektor der Struktur Vector erzeugt, mit der Länge 5 und Nullen als Einträgen initialisiert und dann soll er wieder restlos entfernt werden.

project.h
Code:
#ifndef __PROJECT_H
#define __PROJECT_H


// data types
typedef struct {
 	int nrows;
  	double *value;
} 	Vector;

// initialize vector
void createvec(Vector *x, int n){
	
	x->nrows = n;

	// allocate memory
	x = (Vector *)malloc(sizeof(Vector));
	x->value = (double*)malloc(n*sizeof(double));
	
	// fill with zero
	int i;
	for(i=0; i<n; i++){
		x->value[i] = 0;
	}
}

// delete vector
void deletevec(Vector *x){
	
	int i;
	for(i=0; i<x->nrows; i++){

	printf("yolo\n");
		x->value[i] = 0;
	}
	free(x); 
}	

#endif

main.c
Code:
#include <stdio.h>
#include <stdlib.h>
#include "project.h"

int main()
{
	Vector *x;
	createvec(x,5);
	deletevec(x);
	
	printf("wow, much math \n");
}

Schonmal danke für jede Hilfe.

Gruß
Warhorstl
 
Mein C ist leider etwas eingerostet und ich weiß nicht ob es dadurch kommt, aber auf jeden Fall fehlt ein free für x->value vor dem free(x).
 
Sinn macht das natürlich, habe es auch vo dem free(x) eingefügt. Allerdings ändert es leider gar nichts an der Ausgabe :(
 
Bin C mäßig auch etwas eingerostet aber:

Müsstest du x vor der Verwendung und Übergabe nicht initalisieren (zb auf 0)?

Und vor allem nicht auf x schreiben bevor du speicher dafür allozierst?!

Wie soll das hier funktionieren:
x->nrows = n;
?
 
Ich kann nur sagen:

1. Zeile 14 ...
2. Initialisiere Vector* x mit NULL und beobachte welchen Wert die Variable hat, nachdem createvec(...) ausgeführt wurde.
 
Was mir so auffällt:

1. In der main() Methode erstellst du einen Pointer auf Vector und übergibst diesen an createvec(). In createvec() greifst du direkt auf das nrows Feld zu. Dabei ist die Datenstruktur noch gar nicht initialisiert. Da sollte es eigentlich schon zu einer Zugriffsverletzung kommen.

2. Nachdem du x->nrows = n; durchführst reservierst du Speicher für die Datenstruktur. Damit überschreibst du quasi deine vorherige Zuweisung. Daher: in nrows wird irgendein zufälliger Wert drin stehen.

3. Bei der Allokierung müsstest du x = (Vector *)malloc(n*sizeof(Vector)); machen. Schließlich soll es ja ein Vector Array werden.

4. Darunter kannst du dir das n*sizeof(double) sparen. Wohl in der falschen Zeile eingefügt?

Edit: Sorry habe mich bei Punkt 3 bzw. 4 verlesen. ;) Deine Methode ist schon richtig.
 
Zuletzt bearbeitet:
Call-by-reference und Call-by-value ist scheinbar unklar. Beispiel:
Das x in der main-Funktion liegt an einer (beliebigen) Adresse und hat einen anfangs beliebigen Inhalt (irgendeine Adresse). Dieser Inhalt(!) wird in die createvec()-Funktion kopiert. Diese Kopie(!) (das lokale x der createvec-Funktion) wird dann per malloc auf eine gültige Adresse initialisiert und etwas damit gemacht. Danach wird diese Kopie abgeräumt (beim Verlassen der Funktion). Nun wird das lokale x der Main-Funktion in die delete-Funktion übergeben und dort gelöscht. Da es aber nach wie vor ins Nirvana zeigt, wird versucht etwas zu löschen, was es nicht gibt. Wenn du den Inhalt des Zeigers der main-Funktion ändern möchtest, dann musst du auch den Zeiger auf diesen Zeiger übergeben, d.h.:
createvec(&x);

void createvec(Vector **x);

P.S.: Lass dir mal Adresse und Inhalt der Zeiger in allen Funktionen ausgeben. Dann wird's verständlich.
printf("Adresse %p, Wert %d", x, *x);
 
Zuletzt bearbeitet:
x->nrows = n; steht jetzt an der richtigen Stelle.

void createvec(Vector *x, int n) mit nur einem Zeiger ist blöderweise vorgegeben: "Schreiben Sie eine Funktion void createvec(Vector *x, int n), die Speicher für einen neuen Vektor der Dimension n bereitstellt und mit Nullen initialisiert."

Aber wie ihr ja schon alle festgestellt habt und ich jetzt auch, sind alle meine Veränderungsversuche in createvec vergebens. Ich habe es jetzt so versucht, dass ich Vector x; in der Main mache und dann createvec(&x,5); aufrufe. Ändert aber auch nichts. Ist die Aufgabenstellung einfach doof? Laut Prof müssten wir aber nie doppelte Zeiger nutzen. Er hat damit gestern erst was vorgeführt und für uns dann ausgeschlossen.


Edit: Fehler gefunden, x selbst darf keinen Speicher alloziert bekommen.

Code:
// initialize vector
void createvec(Vector *x, int n){
	
	// allocate memory
	x->value = (double*)malloc(n*sizeof(double));
	 
	x->nrows = n;
	// fill with zero
	int i;
	for(i=0; i<n; i++){
		x->value[i] = 0;
	}
}

Printf in der Main zeigt dann, dass die Werte alle gespeichert sind.
 
Zuletzt bearbeitet:
Matze hat dir eigentlich schon genau den richtigen Denkanstoß gegeben (und die halbe Lösung).
Stell dir mal den folgenden Code vor
Code:
void init(int i) {
    i = 5;
}

int main() {
    int integer;
    init(integer);
    printf("%i", integer);
}

Es ist denke recht offensichtlich, dass das so nichts wird. Genau das versuchst du aber mit deinem Pointer.
 
Besser ist es übrigens, den Pointer auf die erstellte Struktur einfach zurückzugeben:

Code:
Vector* CreateVector(...);
...
Vector *foo = CreateVector(bar, blub);
So macht die SDL es beispielsweise.
 
In der Aufgabenstellung war aber void createvec(...) vorgegeben, der Prof wollte damit schon das Verstaendniss ueberpruefen.
Finde das keine dumme Aufgabe, genau durch solche Fehler lernt und versteht man die Problematik ;)
 
Zurück
Oben