Zum Inhalt springen
View in the app

A better way to browse. Learn more.

Fachinformatiker.de

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Speicherzugriffsfehler

Empfohlene Antworten

Veröffentlicht

Hallo,

Ich bekomme bei einem C Programm an einer bestimmten Stelle in einer Funktion immer einen Speicherzugriffsfehler. Das Problem an der Sache ist, wenn ich die Funktion mehrmals hintereinander aufrufe dann klappt sie ohne Probleme. Habe da aber ein Menü zu "programmiert" und jetzt kommt an einer Stelle eben immer der Fehler...

Das C Programm ist ein Krawattenhalter, die Funktion fügt eine neue Krawatte immer an der letzten Position ein und setzt den Zeiger der aktuellen Krawatte *k auf diese. Das ganze ist eine einfach verkettete Liste und war schon unglaublich stolz auf mich das es Funktioniert hat, nur nachdem ich die Funktion jetzt aus dem Menü aufrufe eben nicht mehr!

main.c


int main() {


	Krawatte *k = 0;

	char menuInput = '\0';


	char insColor;

	char insPattern;


	////////// Wenn ich die nächsten Zeile auskommentiere, dafür das Menü kommentiere läuft alles wie es soll

	/*

	Daten d1, d2;

	d1.color = ROT;

	d1.pattern = KARIERT;


	d2.color = BLAU;

	d2.pattern = GESTREIFT;


	einfuegen(&k, d1);

	einfuegen(&k, d2);

	einfuegen(&k, d1);

	einfuegen(&k, d2);


	ausgabe(&k);


	printf("Fertig");*/

	//////////


	while (menuInput != 'q') {


		printf("Menu\n");

		printf("----\n");

		printf("Press [i] to insert\n");

		printf("Press [q] to quit\n");

		printf("Press [p] to print\n");

		printf("Eingabe: ");

		scanf("%1s", &menuInput);


		switch(menuInput) {


			case 'i':

				//Krawatte einfügen

				printf("Krawatte einfuegen:\n");

				Daten *insData = (Daten *) malloc(sizeof(Daten));

				//Farbe

				printf("Farbe:\n");

				printf("Rot [r]\n");

				printf("Gelb [g]\n");

				printf("Blau [b]\n");

				printf("Eingabe: ");

				scanf("%1s", &insColor);

				switch(insColor) {

					case 'r':

						insData->color = ROT;

						break;

					case 'g':

						insData->color = GELB;

						break;

					case 'b':

						insData->color = BLAU;

						break;

					default:

						insData->color = ROT;

				}

				//Muster

				printf("\nMuster:\n");

				printf("Kariert [k]\n");

				printf("Gestreift [s]\n");

				printf("Gepunktet [p]\n");

				printf("Eingabe: ");

				scanf("%1s", &insPattern);

				switch(insPattern) {

					case 'k':

						insData->pattern = KARIERT;

						break;

					case 's':

						insData->pattern = GESTREIFT;

						break;

					case 'p':

						insData->pattern = GEPUNKTET;

						break;

					default:

						insData->pattern = KARIERT;

				}


				printf("\n");

				einfuegen(&k, *insData);

				free(insData);

				break;

			case 'p':

				ausgabe(&k);

				break;


		}


	}

	return 0;


}

listType.h

        typedef enum farbe {ROT, GELB, BLAU} Farbe;

	typedef enum muster {KARIERT, GESTREIFT, GEPUNKTET} Muster;


	typedef struct Daten {


		Farbe color;

		Muster pattern;


	} Daten;


	typedef struct Krawatte {


		Daten data;

		struct Krawatte *nextTie;


	} Krawatte;

listType.c

void einfuegen(Krawatte **k, Daten d) {

	//Neue Krawatte erstellen

	Krawatte *newTie = (Krawatte *) malloc(sizeof(Krawatte));

	if (newTie == NULL) {

		printf("Fehler: Kein Speicher mehr vorhanden!\n");

		exit(1);

	}


	//Überprüfen ob schon eine Krawatte im Halter exisitiert

	if (*k == NULL) {

		newTie->data = d;


		//Erste und letzte Krawatte im Halter

		newTie->nextTie = newTie;

		*k = newTie;

	}

	else {

		Krawatte *lastTie = (Krawatte *) malloc(sizeof(Krawatte));

		lastTie = *k;

		printf("lastTie: %p\n", lastTie);

		printf("lastTie->nextTie: %p\n", lastTie->nextTie);

		printf("*k: %p\n", *k);


		//Suche letzte Krawatte im Halter

		while (lastTie->nextTie != *k) {

			[COLOR="red"]//IN DER NÄCHSTEN ZEILE LIEGT DER SPEICHERZUGRIFFSFEHLER!!

			lastTie = lastTie->nextTie;[/COLOR]

		}

		newTie->data = d;


		//Füge Krawatte an letzter Position ein und setze Zeiger auf neu eingefügte Krawatte

		newTie->nextTie = *k;

		lastTie->nextTie = newTie;

		*k = newTie;


		//Speicher freigeben

		free(lastTie);

	}


	/*

	printf("\n\n----\n");

	printf("newTie: %p\n", newTie);

	printf("newTie->nextTie: %p\n", newTie->nextTie);

	printf("*k: %p\n", *k);

	printf("----\n\n");

	*/


	printf("Krawatte wurde eingefuegt:\n");

	ausgabeKrawatte(newTie->data.color, newTie->data.pattern);

}

Ein paar Sachen waren vorgegeben: Die Structs inkl Aufbau und Namen und die Signatur von einfuegen. Der Rest ist verhandelbar...;)

Das malloc/free-Paar im else-Block der einfuegen-Funktion ist falsch.

Krawatte *lastTie = (Krawatte *) malloc(sizeof(Krawatte));
Hier holst du nochmal Speicher für eine Krawatte. Warum überhaupt?
lastTie = *k;
Hier verbiegst du den Zeiger lastTie auf den Listenanfang. Damit hast du keinen Zeiger mehr, der auf den gerade reservierten Speicher zeigt -> Speicherleck.
free(lastTie);

Da lastTie auf deinen alten Listenanfang zeigt, löschst du hier eine Krawatte aus deiner Liste. Der Vorgänger verweist allerdings noch darauf, darum fliegt es dir um die Ohren, wenn du das nächste Mal die Liste durchgehst.

Ja das kann schon sein, aber habe nur vergessen das wieder rauszunehmen, habe es Testweise eingefügt, den Fehler gab es schon vorher, bzw gibt es jetzt wieder. So sieht der else Block eigentlich aus:


else {

		Krawatte *lastTie = *k;

		printf("lastTie: %p\n", lastTie);

		printf("lastTie->nextTie: %p\n", lastTie->nextTie);

		printf("*k: %p\n", *k);


		//Suche letzte Krawatte im Halter

		while (lastTie->nextTie != *k) {

			printf("Suche nachechste Krawatte...\n");

			lastTie = lastTie->nextTie;

		}

		newTie->data = d;


		//Füge Krawatte an letzter Position ein und setze Zeiger auf neu eingefügte Krawatte

		newTie->nextTie = *k;

		lastTie->nextTie = newTie;

		*k = newTie;

	}

Vielen Dank schon mal:)

Mit diesem Code tritt das Problem bei mir nicht mehr auf.

Allerdings hast du noch einen Fehler beim Einlesen der Benutzereingaben: Wenn du mit %1s einliest, brauchst du ein char-Array mit mindestens zwei Elementen, weil automatisch eine Nullterminierung angehängt wird. Alternativ kannst du auch mit %c einlesen.

Ja das Problem daran war das dadurch manchmal scanf übersprungen wurde. (Hab auch dazu was in dem MSDN nachgelesen - programmiere zwar mit Linux aber durch %1s war das Problem dann trotzdem gelöst).

Aber mit dem Code oben klappts bei dir? Theoretisch sollte es bei mir ja auch. Wie man in der main.c sieht, wenn ich den oberen auskommentierten Code benutze, also einfach ein paar mal hintereinander einfuegen(x, y) aufrufe, funktioniert es. Durch das Menü kommt in der Funktion der Speicherzugriffsfehler...

Ok gesagt getan. Menü funktioniert immer noch, Fehler leider immer noch da:( Aber woran kann es denn bitte liegen das es ohne Menü funktioniert, mit aber nicht? Da muss das Menü doch irgendwo am Speicher rumwurschteln oder?


int main() {


	Krawatte *k = 0;

	char menuInput[1];

	menuInput[0] = '\0';


	char insColor[1];

	char insPattern[1];


	while (menuInput[0] != 'q') {


		printf("Menu\n");

		printf("----\n");

		printf("Press [i] to insert\n");

		printf("Press [q] to quit\n");

		printf("Press [p] to print\n");

		printf("Eingabe: ");

		scanf("%1s", menuInput);


		switch(menuInput[0]) {


			case 'i':

				//Krawatte einfügen

				printf("Krawatte einfuegen:\n");

				Daten *insData = (Daten *) malloc(sizeof(Daten));

				//Farbe

				printf("Farbe:\n");

				printf("Rot [r]\n");

				printf("Gelb [g]\n");

				printf("Blau [b]\n");

				printf("Eingabe: ");

				scanf("%1s", insColor);

				switch(insColor[0]) {

					case 'r':

						insData->color = ROT;

						break;

					case 'g':

						insData->color = GELB;

						break;

					case 'b':

						insData->color = BLAU;

						break;

					default:

						insData->color = ROT;

				}

				//Muster

				printf("\nMuster:\n");

				printf("Kariert [k]\n");

				printf("Gestreift [s]\n");

				printf("Gepunktet [p]\n");

				printf("Eingabe: ");

				scanf("%1s", insPattern);

				switch(insPattern[0]) {

					case 'k':

						insData->pattern = KARIERT;

						break;

					case 's':

						insData->pattern = GESTREIFT;

						break;

					case 'p':

						insData->pattern = GEPUNKTET;

						break;

					default:

						insData->pattern = KARIERT;

				}


				printf("\n");

				einfuegen(&k, *insData);

				free(insData);

				break;

			case 'p':

				ausgabe(&k);

				break;


		}


	}

	return 0;

}

Oh mein Gott das war echt doof von mir:D Dachte wenn ich ein Array erstelle mit [1] Elementen erzeugt der 0 und 1...Kurz drüber nachgedacht, korrigiert und jetzt funktioniert es;) Gibt wahrscheinlich einen guten Grund warum der Speicherfehler erst später auftritt aber ist ja schrecklich wenn man nach Fehlern suchen will.

Vielen vielen Dank!

Edit: Weil ich nicht der Typ bin der sich alles vorkauen lässt und gerne selber die Fehler findet (Höhö): Wie kann ich Speicherzugriffsfehler debuggen? Benutze Eclipse oder die Konsole unter Debian 6

Bearbeitet von demo88

Archiv

Dieses Thema wurde archiviert und kann nicht mehr beantwortet werden.

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.