Hi
I have a program, which implements a double-linked list, with a struct
as data element. This is a simple C program, intended for teaching
purposes on my universtiy. So far the program runs fine using Linux
and GCC, but compiling this using the Visual Studio compiler results
in a crash.
The interesting part about this is, that if running the program in
debug mode, the whole thing runs fine, and performs the correct
results. I have changed the compiler to produce C code.
After extensive testing, the problem is situated after the third call
to malloc. The first two calls are fine, and perform as expected, but
the third call leads to a crash of the program. I have attached the
code below, the main comments are in german, but if you copy the
program in Visual Studio, the crash occurs in line 87.
If anyone has got an idea, my students really need to get this thing
working, and although I prefer doing these things on Linux, they need
the solution in C
regards, Roland
/*********************************************
*** Laboruebung 1
***
*** Erstellen einer Printqueue
*********************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/** ####################### GLOBALE DEKLARATIONEN
####################### **/
/** TYP DEFINITION SPJob_t
*
* Definiert unser Printjob Element. Wir haben vorab festgelegt,
* dass wir das Element extra fuehren
*/
typedef struct _SPJob {
unsigned long pid;
char * szText;
} SPJob_t;
/** TYP DEFINITION SQueue_t
*
* Definiert unsere Queue. Der Vorteil, dass wir die Queue ausserhalb
* der Definition unseres Printjobs erledigen, ist die hoehere Wieder-
* verwendbarkeit des Codes.
*/
typedef struct _SQueue {
struct _SQueue * prev; /** Vorgaenger */
struct _SQueue * next; /** Nachfolger */
SPJob_t * element;
} SQueue_t;
/** Wir benoetigen einen globalen Zeiger auf die Liste. Wenn wir nicht
mit diesem globalen
* Zeiger arbeiten wuerden, muessten wir den Listenzeiger bei jedem
Funktionsaufruf mit
* uebergeben
*/
SQueue_t * myQueue;
/** ####################### FUNKTIONEN DEKLARATIONEN
####################### **/
/** FUNKTION push
*
* Parameter: pid und szText
*
* Haengt ein neues SPJob_t Element an das Ende der Queue an.
*/
int push(unsigned long pid, char * szText) {
SPJob_t * queueElement;
/** Wir laufen zum Ende der Queue */
while ( myQueue->next != 0 )
myQueue = myQueue->next;
/** Wir stehen auf alle Faelle am Ende der Queue. Aber was wir noch
* schauen muessen ist, ob die Queue mehr als ein Element besitzt.
* Wenn nicht, ist element == 0.
* Warum wir das genau so machen, siehe createQueue()
*/
if ( myQueue->element != 0 ) {
/** Wir sind nicht am Listenanfang, also legen wir ein
naechstes Element */
myQueue->next = (SQueue_t *) malloc (sizeof (SQueue_t *));
/** Setzen die Listenzeiger auf den Vorgaenger und den Nachfolger
auf 0, sowie das Element auf 0 */
myQueue->next->prev = myQueue;
myQueue->next->next = 0;
myQueue->next->element = 0;
/** und setzen den Zeiger um eines weiter */
myQueue = myQueue->next;
}
/** Wir sind jetzt sicher in einem Element, dass noch keinen Printob
hat,
* hier legen wir den neuen Printjob in das Element
*/
myQueue->element = (SPJob_t *) malloc (sizeof (SPJob_t *));
myQueue->element->pid = pid;
/** #########################
After push is being called the second time, the following line
results in a crash, but only if not run while debugging
######################### */
myQueue->element->szText = (char *) malloc ( strlen ( szText ) +
1 );
strcpy ( myQueue->element->szText, szText );
}
/** FUNKTION pop
*
* Parameter: keine
* Liefert: den gesuchten Printjob
*
* Haengt das erste Element aus der Queue aus, und liefert den
Printjob. In den meisten Faellen
* macht es keinen Sinn Zeiger zurueck zu geben. Wir wissen nicht was
im Hauptprogramm damit basiert,
* und daher sollten wir bei so einfachen Programmen immer eine
Struktur zurueck geben.
*/
SPJob_t pop(void) {
SQueue_t * queueEntry;
SPJob_t returnElement;
/** Wir laufen an den Anfang der Queue */
while ( myQueue->prev != 0 )
myQueue = myQueue->prev;
/** Wir speichern das zurueckgebende Element zwischen */
returnElement.pid = myQueue->element->pid;
returnElement.szText = (char *)malloc (strlen(myQueue->element-
[quoted text, click to view] >szText) + 1);
strcpy(returnElement.szText, myQueue->element->szText);
/** Wir geben den String zurueck, sowie das Element */
free(myQueue->element->szText);
free(myQueue->element);
/** Gibt es ausser uns noch weitere Elemente in der Queue? Wenn ja,
muessen wir denen
* mitteilen, dass es uns gleich nicht mehr geben wird.
*/
if ( myQueue->next != 0 ) {
/** Setzen den Zeiger auf den Nachfolger */
myQueue = myQueue->next;
/** Speichern die Adresse des zu loeschenden Elements */
queueEntry = myQueue->prev;
/** Sagen dem Nachfolger, dass es uns nicht mehr geben wird */
myQueue->prev = 0;
/** Setzen den Zeiger auf unseren Nachfolger auf 0, um sicher zu
gehen, dass der Compiler nicht
* ueberreagiert
*/
queueEntry->next = 0;
/** Und wir verabschieden uns */
free(queueEntry);
}
/** Wir geben das geholte Element raus */
return returnElement;
}
/** FUNKTION createQueue
*
* Parameter: keine
* Liefert: nichts
*
* Erzeugt eine leere Queue
*/
void createQueue(void) {
myQueue = (SQueue_t *) malloc ( sizeof ( SQueue_t * ) );
/** Wir setzen den Vorgaenger standardmaessig auf 0. */
myQueue->prev = 0;
/** Wir setzen den Nachfolger standardmaessig auf 0. */
myQueue->next = 0;
/** Wir setzen das Element standardmaessig auf 0. */
myQueue->element = 0;
}
/** FUNKTION printJobs
*
* Parameter: keine
* Liefert: nichts
*
* Gibt die Liste der Elemente auf der Standardausgabe aus.
*/
void printJobs(void) {
/** Wir holen uns einen eigenen Iterator, fuer die Darstellung.
* Ein Iterator ist ein eigener Zeiger, dessen Aufgabe es ist, eine
Liste von Zeigern zu
* durchlaufen, ohne dabei den urspruenglichen Listenzeiger zu
verwenden.
* In der letzten while Schleife dieser Funktion kann der Iterator
auch 0 werden, und
* wuerden wir das mit unserem normalen Listenzeiger machen,
koennten wir anschliessend nicht
* mehr auf die Liste zugreifen.
*/
SQueue_t * queueIterator;
queueIterator = myQueue;
/** Ist element == 0 ist die Liste leer, siehe createQueue */
if ( myQueue->element == 0 ) {
printf ( "Queue ist leer\n" );
return;
}
/** Wir laufen mit dem Iterator an den Listenanfang */
while ( queueIterator->prev != 0 )
queueIterator = queueIterator->prev;