Zum Inhalt springen

[C]: Speicherfehler


TDM

Empfohlene Beiträge

hi,

Ich hab hier ein kleines Problem mit meinem C Programm. :(

Es soll eine Art Warteschlange (FIFO) simulieren.

Soweit geht auch alles, nur wenn ich das Programm beenden will, dann bekomm ich immer einen Speicherfehler O.o

Weis jemand woran es liegt ?

Ist bestimmt nur eine Kleinigkeit und ich seh den Wald vor lauter Bäumen nicht...


//Einsprungspunkt für FIFO.cpp


#include <iostream>


using namespace std;


#if !defined(CASE) || !defined(DEFAULT)

#define CASE break;case

#define DEFAULT break;default

#endif


#if !defined(CLS)

#include <stdlib.h>

#define CLS system("CLS")

#endif


#define MAX_ATTEMPT 3										/* Anzahl der Fehlversuche */


//Struct Deklaration

struct sNode;


//Typedef

typedef int Element;

typedef sNode Node, *Link;									/* Node = Elemente */

															/* Link = Verweise */

//Funktion

void print_menu(unsigned int Orders);

void push(Element data);

void pop(void);

Element show(void);


//Struct Definition

struct sNode 

{

	Element Elem;

	Link    PPrev;

	Link    PNext;

};


//Kopf und Schwanz (erste und letzte)

Link head;

Link tail;


int main()

{

	short int Quit = MAX_ATTEMPT, Wahl; 

	unsigned int Orders = 0;

	Element data;

	while (Quit)

	{

		print_menu(Orders);

		scanf("%d", &Wahl);

		switch (Wahl)

		{

		case 1:

		     CLS;

			 printf("Zahl eingeben:\t");

			 scanf("%d", &data);

			 push(data);

			 Orders++;

		CASE 2:

			 CLS;

			 printf("Aktueller Auftrag:\t%d\n\n",show());

		CASE 3:

			 pop();

			 CLS;

			 Orders--;

		CASE 4:

			 Quit = 0;

		DEFAULT:

			 CLS;

			 printf("ungueltige Eingabe\n\n");

			 Quit--;

		}

	}

	return 0;

}




void print_menu(unsigned int Orders)

{

		printf("********************************************************************************"

		       "*                                                                              *"

		       "*                                   1 = Neuen Auftrag erzeugen                 *");

		if (Orders)

		printf("*                                   2 = Aktuellen Auftrag anzeigen             *"

		       "*                                   3 = Aktuellen Auftrag loeschen             *");

		printf("*                                   4 = Programm beenden                       *"

		       "*                                                                              *"

		       "********************************************************************************");

}


void push(Element data)

{

	static bool IsHead = true;

	Link tmp;

	tmp = (Link) malloc(sizeof(sNode));

	tmp -> Elem = data;										/* Daten eintragen */

	if (IsHead)

	{

		head = tmp;

		tmp -> PPrev = NULL;								/* Anfang auf NULL setzen */

		IsHead = false;										/* nicht mehr das erste Element */

	}

	else

	{

		tmp  -> PPrev = tail;								/* Verlinkung zum Vorherigen */

		tail -> PNext = tmp;								/* Verlinkung zum Nächsten */

	}

	tmp -> PNext = NULL;									/* Nächste vom Nächsten gibts nicht */

	tail = tmp;												/* Neues Ende */

}


inline Element show(void)

{

	return head -> Elem;

}


void pop(void)

{

	static bool WasLast = false;

	if (!WasLast)

	{

		Link tmp;

		tmp = head -> PNext;

		tmp -> PPrev = NULL;

		free(head);

		head = tmp;

		if (head == tail)									/* erste gleich letzte (nur noch 1 Element) */

		{

			WasLast = true;

		}

	}

	else

	{

		head -> Elem = tail -> Elem = NULL;

		free(head);

	}

}

Link zu diesem Kommentar
Auf anderen Seiten teilen

Deine Vorgehensweise mit den statischen bool-Variablen funktioniert so nicht. Wenn man z.B. ein Element anlegt und gleich wieder löscht, versuchst du in pop() auf head -> PNext -> PPrev zuzugreifen. head -> PNext ist aber 0.

Mit funktionsstatischen Variablen kannst du nicht die Sonderfälle erkennen. Du musst das über die Zeiger selbst prüfen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

ja, schon...

nur das ja ne ausnahme, man wird bestimmt keine verkette Liste benutzen wenn man nur einen Auftrag hatt

Notfalls kann ich das über "unsigned int Orders"

aber mal abgesehen von dem Problem geht das ja...

nur dann halt bei Wahl = 4 bekomm ich den blöden Speicherfehler und ich weis nicht warum :(

kann doch nicht sein dass das mit der static Variable zusammenhängt O.o'

Link zu diesem Kommentar
Auf anderen Seiten teilen

aber mal abgesehen von dem Problem geht das ja...

Tut mir leid, aber dein Programm geht nur, wenn man zu Beginn mindestens zwei Einträge anlegt, und zwischendurch nicht wieder alle löscht.

nur dann halt bei Wahl = 4 bekomm ich den blöden Speicherfehler und ich weis nicht warum :(
Ich bekomme bei Wahl = 4 keinen Speicherfehler. Ich bekomme einen handfesten Absturz wegen Dereferenzierung eines Nullzeigers, wenn ich ein Element hinzufüge und gleich wieder lösche. Geht das bei dir etwa?

kann doch nicht sein dass das mit der static Variable zusammenhängt O.o'
Warum kann das nicht sein? Du versuchst, mit diesen statischen Variablen die Sonderfälle für push (noch kein Eintrag da) und pop (nur noch ein Eintrag da) zu unterscheiden. Das geht aber nicht, weil sich die Anzahl der Einträge eben in push und pop ändern kann.

Wenn ich den letzten Eintrag in pop lösche, müsste IsHead in push ja auf magische Weise wieder true werden, damit das funktioniert.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Irgentwie ging Edit nicht...:

*keine Probleme mag*


void pop(void)

{

	if (head -> PNext)

	{

		Link tmp;

		tmp = head -> PNext;

		tmp -> PPrev = NULL;

		free(head);

		head = tmp;

	}

	else if (head == tail && head -> Elem)									/* erste gleich letzte (nur noch 1 Element) */

	{

		head -> Elem = NULL;

	}

	else

	{

		head -> Elem = tail -> Elem = NULL;

		free(head);

	}

}

Nun hab ich aber immernoch das Speicherproblem beim beenden :/

Edit: OK... IsHead hab ich vergessen :X

Link zu diesem Kommentar
Auf anderen Seiten teilen


Link head = (Link) malloc(sizeof(sNode));

Link tail;


int main()

{

	short int Quit = MAX_ATTEMPT, Wahl; 

	unsigned int Orders = 0;

	Element data;

	head -> Elem = NULL;

	while (Quit)

	{

		print_menu(Orders);

		scanf("%d", &Wahl);

		switch (Wahl)

		{

		case 1:

		     CLS;

			 printf("Zahl eingeben:\t");

			 scanf("%d", &data);

			 push(data);

			 Orders++;

		CASE 2:

			 CLS;

			 printf("Aktueller Auftrag:\t%d\n\n",show());

		CASE 3:

			 pop();

			 CLS;

			 Orders--;

		CASE 4:

			 Quit = 0;

		DEFAULT:

			 CLS;

			 printf("ungueltige Eingabe\n\n");

			 Quit--;

		}

	}

	return 0;

}


void push(Element data)

{

	Link tmp;

	tmp = (Link) malloc(sizeof(sNode));

	tmp -> Elem = data;										/* Daten eintragen */

	if (!head -> Elem)

	{

		head = tmp;

		tmp -> PPrev = NULL;								/* Anfang auf NULL setzen */

	}

	else

	{

		tmp  -> PPrev = tail;								/* Verlinkung zum Vorherigen */

		tail -> PNext = tmp;								/* Verlinkung zum Nächsten */

	}

	tmp -> PNext = NULL;									/* Nächste vom Nächsten gibts nicht */

	tail = tmp;												/* Neues Ende */

}


ok... jetzt gehts eigentlich auch nachdem alles gelöscht wurde


nur der speicherfehler kommt immernoch

Link zu diesem Kommentar
Auf anderen Seiten teilen

Warum meckert der bei short int ? O.o
Ich nehme mal an, dass du auf einem 32Bit-Windows mit MSVC unterwegs bist.

Da hat ein short int zwei Byte, und ein int vier. scanf mit %d geht von einem int aus, also wird die Adresse, die du mitlieferst, als Zeiger auf einen vier Byte großen Speicherbereich interpretiert, und der eingegebene Wert da rein geschrieben. Von diesen vier beschriebenen Bytes gehören aber nur die ersten beiden zu Wahl, die anderen beiden könnten theoretisch zu einer anderen Variablen gehören.

Der Wert, der ihn Wahl landet, ist der gleiche, weil dein Windows Little-Endian ist.

Link zu diesem Kommentar
Auf anderen Seiten teilen

ok... nicht mit Lifo... aber trotzdem wieder ein speicher fehler :/

stdflifo.h:


#if !defined(CASE) || !defined(DEFAULT)

#define CASE break;case

#define DEFAULT break;default

#endif


#if !defined(CLS)

#include <stdlib.h>

#define CLS system("CLS")

#endif


#define MAX_ATTEMPT 3												/* Anzahl der Fehlversuche */

#define FEHLEINGABE CLS; printf("ungueltige Eingabe\n\n");Quit--


#define VL_MODE_DEFAULT	0


#ifndef VL_MODE

#define VL_MODE VL_MODE_DEFAULT

#endif


//Struct Deklaration

struct sNode;


//Typedef

#ifndef Element

typedef int Element;

#endif

typedef sNode *Link;											/* Link = Verweise */


//Struct Definition

struct sNode 

{

	Element ID;

	Element Elem;

	Link    PPrev;

	Link    PNext;

};


#define NEW_ADDRESS (Link) malloc(sizeof(sNode))


#if !VL_MODE

//Kopf und Schwanz (erste und letzte)

Link head = NEW_ADDRESS;

Link tail;

#else 

Link tail = NEW_ADDRESS;

#endif


//Funktion

void print_menu(unsigned int Orders)

{

		printf("********************************************************************************"

		       "*                                                                              *"

		       "*                                   1 = Neuen Auftrag erzeugen                 *");

		if (Orders)

		printf("*                                   2 = Aktuellen Auftrag anzeigen             *"

		       "*                                   3 = Aktuellen Auftrag loeschen             *");

		printf("*                                   4 = Programm beenden                       *"

		       "*                                                                              *"

			   "*                                   Noch %d Autraege                            *"

		       "********************************************************************************",Orders);

}


/*//////////////////////////////////////////////////////////////////

// LIFO Funktionen

//////////////////////////////////////////////////////////////////*/


#if !VL_MODE

void push(Element data)

{

	Link tmp;

	tmp = NEW_ADDRESS;

	tmp -> Elem = data;												/* Daten eintragen */

	if (!head -> Elem)

	{

		head = tmp;

		[b]//tmp -> ID = 0;[/b]

		tmp -> PPrev = NULL;										/* Anfang auf NULL setzen */

	}

	else

	{

		[b]//tmp  -> ID    = (tmp -> PPrev -> ID + 1);[/b]

		tmp  -> PPrev = tail;										/* Verlinkung zum Vorherigen */

		tail -> PNext = tmp;										/* Verlinkung zum Nächsten */

	}

	tmp -> PNext = NULL;											/* Nächste vom Nächsten gibts nicht */

	tail = tmp;														/* Neues Ende */

}


inline Element show(void)

{

	return head -> Elem;

}


inline void set_default(void)

{

	head -> Elem = NULL;

}


void pop(void)

{

	if (head -> PNext)												/* Wenn es ein nächstes gibt */

	{

		Link tmp;

		tmp = head -> PNext;

		tmp -> PPrev = NULL;

		free(head);

		head = tmp;

	}

	else if (head == tail && head -> Elem)							/* erste gleich letzte (nur noch 1 Element) */

	{

		head -> Elem = tail -> Elem = NULL;

		free(head);													/* Addresse freigeben */

	}

}


/*//////////////////////////////////////////////////////////////////

// FIFO Funktionen

//////////////////////////////////////////////////////////////////*/


#else

void push(Element data)

{

	Link tmp;

	tmp = (Link) malloc(sizeof(sNode));

	tmp  -> Elem  = data;

	tmp  -> PPrev = tail;

	tail -> PNext = tmp;

	tmp  -> PNext = NULL;

	tail = tmp;

}


inline Element show(void)

{

	return tail -> Elem;

}


inline void set_default(void)

{

	tail -> PPrev = NULL;

}


void pop(void)

{

	if(tail -> PPrev)												/*nicht das Letzte */

	{

		Link tmp;

		tmp = (Link) malloc(sizeof(sNode));

		tmp = tail -> PPrev;

		tmp -> PNext = NULL;

		free(tail);

		tail = tmp;

	}

	else

	{

		free(tail);													/* letzte löschen */

	}


}

#endif

wenn ich jetzt die die ID zeilen (die dicken) wieder auskommentiere, dann bekomm ich einen speicherfehler in der art von

Die Ausnahme "unknown software exception" (0x80000003) ist in der Anwendung an der Stelle 0x77f65a58 aufgetreten.

Klicken sie auf "Ok", um das Programm zu beenden.

Klicken sie auf "Abbrechen", um das Programm zu debuggen.

Woran kann das liegen ?

Nur an den beiden zeilen ? O.o'

Link zu diesem Kommentar
Auf anderen Seiten teilen

ok habs gefunden...


	if (!head -> Elem)

	{

		head = tmp;

		tmp -> ID = 0;

		tmp -> PPrev = NULL;										/* Anfang auf NULL setzen */

	}

	else

	{

		tmp  -> PPrev = tail;										/* Verlinkung zum Vorherigen */

		tmp  -> ID    = (tmp -> PPrev -> ID + 1);

		tail -> PNext = tmp;										/* Verlinkung zum Nächsten */

	}

:)

Link zu diesem Kommentar
Auf anderen Seiten teilen

		[b]//tmp  -> ID    = (tmp -> PPrev -> ID + 1);[/b]
tmp -> PPrev = tail;[/code] Hier greifst du auf tmp -> PPrev zu, bevor du es setzt. Das machst du nämlich erst in der nächsten Zeile ;) Übrigens, von Konstrukten wie
[code]#define NEW_ADDRESS (Link) malloc(sizeof(sNode))

rate ich dringend ab. Schreib besser eine Funktion dafür.

Und warum benutzt du eigentlich malloc und free, wenn du sowieso C++ erzeugst?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wieso C++ erzeugen ?

der Compiler macht einfach nur Cpp dateien draus (man kann nur C++ Projekte erstellen O.o)

sicher... da gibts auch irgentwo ne option aber egal...

wollt halt mal nen "reinen" C code schreiben

und das mit den PPrev hab ich ja schon mitgekriegt ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wieso C++ erzeugen ?

der Compiler macht einfach nur Cpp dateien draus (man kann nur C++ Projekte erstellen O.o)

MSVC? Der kann auch C. Er richtet sich da nach der Dateiendung.

wollt halt mal nen "reinen" C code schreiben
Dein Code ist aber kein C. Du initialisierst globale Variablen mit nichtkonstanten Werten, du benutzt NULL für integrale Datentypen und an einigen Stellen fehlt "struct". Ein C-Compiler wird dir das um die Ohren hauen. Den cast in deinem NEW_ADDRESS-Makro brauchst du nur, weil das C++ ist. In C wäre der unnötig (und eventuell sogar gefährlich).
Link zu diesem Kommentar
Auf anderen Seiten teilen

Visual Studion .Net

und ich dachte malloc ist da damit man eine neue freie Addresse findet O.o?

da NULL so und so in der stdlib.h als


#define NULL 0 

definiert ist, ist es doch eigentlich egal ob ich nun 0 oder NULL nehme O.o'

Wenn globale variablen konstante werte hätten, wären es konstanten und keine variablen

Link zu diesem Kommentar
Auf anderen Seiten teilen

und ich dachte malloc ist da damit man eine neue freie Addresse findet O.o?
"Frei" ist in dem Sinne keine Adresse. malloc "beschafft" Speicher vom Heap. Aber in C++ nimmt man dafür eigentlich new/delete, das hat den Vorteil, dass man Konstruktoren und Destruktoren verwenden kann.

da NULL so und so in der stdlib.h als


#define NULL 0
[/Code]

definiert ist, ist es doch eigentlich egal ob ich nun 0 oder NULL nehme O.o'

So sieht das #define für NULL aber nur in C++ aus. In C ist NULL ein void*-Nullzeiger. Das geht aber in C++ nicht, weil dort im Gegensatz zu C ein void* nicht implizit in jeden anderen Zeigertyp konvertierbar ist.

Wenn globale variablen konstante werte hätten, wären es konstanten und keine variablen
In C darfst du globale Variablen nur mit Konstanten [i]initialisieren[/i], d.h. du kannst z.B. nicht mit dem Rückgabewert von malloc initialisieren. Das geht nur in C++.
Link zu diesem Kommentar
Auf anderen Seiten teilen

also wär dann das define

#define NULL void*0x00000000

oder wie ?

In meiner stdlib.h steht:

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif[/code]

aber die stdlib ist doch für c programme O.o
Sie ist aber auch Bestandteil von C++. Der Header heißt zwar im C++-Standard <cstdlib>, aber der C-Header funktioniert unter MSVC auch noch.
Link zu diesem Kommentar
Auf anderen Seiten teilen

erm... mir ist grad wieder eingefallen warum ich NULL genommen hatte...

Wenn da steht "Aufträge" und man "nur" Zahlen eingibt ist das bissl doof oder ?

hatte mir am anfangen überlegt ob ich vielleicht auf strings umsteig

(wollte das halt nur anfangs mit zahlen probieren)

Link zu diesem Kommentar
Auf anderen Seiten teilen

ok, hast mich überzeugt...

btw: was ist der Unterschied zwischen #ifndef und if !defined() ?

Prinzipiell schon, aber einen kleinen unterschied gibt es, oder? Ich meine, wenn man mehrere 'defines' prüfen will, kenne ich nur

if !defined(BLA) && !defined(BLA_2)

da geht es doch garnicht mit '#ifndef' oder irre ich mich jetzt total. ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...