dynamische speicherreservierung fuer arrays



  • Hy!
    also bin noch anfänger, bitte nicht gleich mit fach chinesisch auf mich zurennen! 😉 und auch nicht "das geht so viel einfacher... ", denn ich habe vorschriften von meinem prof die ich einhalten muss.

    das problem ist, dass ich, sobald ich das programm kompiliere und ablaufen lassen will, kackt er einfach ab, und es kommt diese debug fehler meldung von windoof.

    also ich poste einfach am besten noch die aufgabenstellung 🙂

    Dynamischer Speicher
    Realisieren Sie als Modul ein LIFO (Stack) für Strings mit folgender Schnittstelle:

    -> int push(char *string); speichert einen String; Ergebnis 0, wenn kein Speicherplatz
    vorhanden (auf einem PC praktisch nicht möglich).
    -> int empty(void); prüft, ob der Stack leer ist.
    -> char *top(void); liefert den "obersten" (jüngsten) String. Erzeugt
    Programmabbruch, wenn Stack leer.
    -> int pop(void); beseitigt den "obersten" string; Ergebnis 0, wenn der Stack danach
    leer ist. Kein Effekt, wenn er bereits vorher leer ist.
    -> void clear(void); beseitigt alle Einträge.

    Der Stack soll mit einem dynamischen Array realisiert werden, der bei Bedarf in
    Blöcken von 10 erweitert und ggf. auch wieder verkleinert wird. Jedes Arrayelement
    ist vom Typ char * und zeigt auf einen dynamisch angelegten String passender
    Größe. Man benötigt dazu einen Zeiger vom Typ char **, die Anzahl der Einträge und
    die Kapazität des Arrays. Vergessen Sie nicht, bei pop() und clear() auch den
    Speicher für die Strings freizugeben!

    das LIFO modul:

    // lifo.c // 
    
    #define _CRT_SECURE_NO_DEPRECATE
    
    #include <string.h>
    #include <malloc.h>
    #include <stdlib.h>
    #include <stdio.h>
    
    #include "lifo.h"
    
    #define BLOCK 10
    
    char **pp_string = NULL;
    int count = 0;
    
    /* int push(char *string); speichert einen String; Ergebnis 0, wenn kein Speicherplatz
    vorhanden (auf einem PC praktisch nicht möglich). */
    
    int push(char *string) {
    	int ret = 1;
    	if((count % BLOCK) == 0) {	// 0, wenn alle Speicherplaetze bereits voll
    		pp_string = (char **)realloc(pp_string, (count + BLOCK) * sizeof(char *));	// reserviert Speicherplatz fuer BLOCK neue Zeiger
    		if(pp_string = NULL)	// wenn NULL, dann Speicherplatz nicht vorhanden -> return 0
    			ret = 0;
    	}
    	pp_string[count] = (char *)malloc(1 + strlen(string));	// erstellt Speicherplatz fuer den uebergebenen String + /0
    	strcpy(pp_string[count], string);	// kopiert uebergebenen String in Speicherplatz
    	pp_string[++count] = NULL;	// setzt Zeiger auf nächsten/letzten Speicherplatz, also NULL
    
    	return ret;
    }
    
    /* int empty(void); prüft, ob der Stack leer ist. */
    
    int empty(void) {	// gibt 0 zurueck, wenn leer
    	int ret;
    	if(pp_string[0] == NULL)		// prueft ob erster Speicherplatz leer ist 
    		ret = 0;
    	else
    		ret = 1;
    	return ret;
    }
    
    /* char *top(void); liefert den "obersten" (jüngsten) String. Erzeugt
    Programmabbruch, wenn Stack leer. */
    
    char *top(void) {
    	if(empty() == 0)
    		exit(0);
    	else
    		return(pp_string[count - 1]);
    }
    
    /* int pop(void); beseitigt den "obersten" string; Ergebnis 0, wenn der Stack danach
    leer ist. Kein Effekt, wenn er bereits vorher leer ist. */
    
    int pop(void) {
    	int ret;
    	if(!(empty() == 0)) {
    		if((count - 1) % BLOCK == 0) {
    			free(pp_string[count]);
    		}
    		else
    			pp_string[count - 1] = NULL;
    	}
    	if(empty() == 0)
    		ret = 0;
    	else
    		ret = 1;
    
    	return ret;
    }
    
    /* void clear(void); beseitigt alle Einträge. */
    
    void clear(void) {
    	if(!(empty() == 0))
    		for(--count; count > 0; count--)
    			free(pp_string[count]);
    }
    
    char *get(int handler) {
    	if(!empty()) {
    		printf("Stack is empty ->exit\n");
    		exit(0);
    	}
    	return pp_string[handler];
    }
    

    das TESTPROGRAMM:

    // main.c // 
    
    #include <stdio.h>
    #include <stdlib.h>
    
    #include "lifo.h"
    
    int main (void)
    {
    	int vLoop;
    	int tmp;
    
    	//Strings zuweisen
    	if (!push ("Text1"))
    		exit(0);
    	if (!push ("Text2"))
    		exit(0);
    	if (!push ("Text3"))
    		exit(0);
    	if (!push ("Text4"))
    		exit(0);
    	if (!push ("Text5"))
    		exit(0);
    	if (!push ("Text6"))
    		exit(0);
    	if (!push ("Text7"))
    		exit(0);
    	if (!push ("Text8"))
    		exit(0);
    	if (!push ("Text9"))
    		exit(0);
    	if (!push ("Text10"))
    		exit(0);
    	if (!push ("Text11"))
    		exit(0);
    
    	//Testweise Abrufen der Strings
    	printf("Abrufen aller Strings\n");
    	for (vLoop = 0; vLoop < 11; vLoop++)
    	{
    		printf ("%s\n",get (vLoop));
    	}
    	getchar();
    	printf("Aufruf von top()\n");
    	printf ("%s\n",top());
    
    	getchar();
    	printf("Aufruf von pop()\n");
    	if (!pop())
    		printf("Stack is now empty\n");
    	else 
    		printf("Stack is not empty\n");
    
    	getchar();
    	//Testweise Abrufen der Strings
    	printf("Abrufen aller Strings, auch den schon befreiten\n");
    	for (vLoop = 0; vLoop < 11; vLoop++)
    	{
    		printf ("%s\n",get (vLoop));
    	}
    
    	getchar();
    	printf ("Erneutes beschreiben des letzen Platzes\n");
    	if (!push ("Text11: Erneutes beschreiben"))
    		exit(0);
    	printf("Abrufen aller Strings\n");
    	for (vLoop = 0; vLoop < 11; vLoop++)
    	{
    		printf ("%s\n",get (vLoop));
    	}
    
    	getchar();
    	printf ("\nClear, beseitigen aller Einträge\n");
    	clear();
    	printf("Abrufen aller Strings\n");
    	if (!empty())
    		printf("Stack is now empty\n\n");
    
    	getchar();
    	printf ("Erneutes beschreiben des letzen Platzes\n");
    	if (!push ("Text1: Erneutes beschreiben"))
    		exit(0);
    	printf("Abrufen aller Strings\n");
    	for (vLoop = 0; vLoop < 1; vLoop++)
    	{
    		printf ("%s\n",get (vLoop));
    	}
    
    	getchar();
    
    	return 0;
    }
    

    Ich find einfach nix, und mit dem Debugger komm ich einfach noch nicht zurecht. Wenn er mir ja wenigstens ne Fehlermeldung beim Kompilieren ausspucken würde, aber so 😕

    Schonmal vielen vielen vielen Dank! 🙂



  • lifo.c, Zeile 26.

    Außerdem sollst du den Rückgabewert von realloc nicht casten. Das hat aber nichts mit dem Fehler zu tun.



  • MFK schrieb:

    Außerdem sollst du den Rückgabewert von realloc nicht casten.

    ... und überprüfen ob der 0 ist. bei 'malloc' ebenso.
    🙂



  • Bezüglich malloc/realloc: http://www.c-plusplus.net/forum/viewtopic.php?t=206606

    Ich habe den Code nur mal überflogen und kann dir den Bug auch nicht nennen, aber isoliere doch erstmal die Stelle an der es kracht (z.B. durch auskommentieren und sukzessives Entkommentieren). Debuggen lernen solltest du auf jeden Fall.

    Ansonsten ein paar Dinge die mir auffallen:

    #include <string.h>
    #include <malloc.h>
    #include <stdlib.h>
    #include <stdio.h>
    

    malloc.h solltest du nicht einbinden müssen wenn du die stdlib.h eingebunden hast.

    int push(char *string) {
    	int ret = 1;
    	if((count % BLOCK) == 0) {	// 0, wenn alle Speicherplaetze bereits voll
    		pp_string = (char **)realloc(pp_string, (count + BLOCK) * sizeof(char *));	// reserviert Speicherplatz fuer BLOCK neue Zeiger
    		if(pp_string = NULL)	// wenn NULL, dann Speicherplatz nicht vorhanden -> return 0
    			ret = 0;
    	}
    	pp_string[count] = (char *)malloc(1 + strlen(string));	// erstellt Speicherplatz fuer den uebergebenen String + /0
    	strcpy(pp_string[count], string);	// kopiert uebergebenen String in Speicherplatz
    	pp_string[++count] = NULL;	// setzt Zeiger auf nächsten/letzten Speicherplatz, also NULL
    
    	return ret;
    }
    

    Hier überprüfst du zwar auf NULL, springst aber im Falle von NULL nicht direkt raus (sondern setzt nur ret) und würdest im Zweifelsfall eben jene NULL dereferenzieren. Das ist albern 😉

    int empty(void) {	// gibt 0 zurueck, wenn leer
    	int ret;
    	if(pp_string[0] == NULL)		// prueft ob erster Speicherplatz leer ist 
    		ret = 0;
    	else
    		ret = 1;
    	return ret;
    }
    

    Ich würde bei einer Funktion mit dem Namen "empty" erwarten, dass sie mir wahr zurückliefert wenn das Ding leer ist, und nicht umgekehrt.

    Weiter hab ich nicht gelesen 🤡



  • Tim schrieb:

    int empty(void) {	// gibt 0 zurueck, wenn leer
    	int ret;
    	if(pp_string[0] == NULL)		// prueft ob erster Speicherplatz leer ist 
    		ret = 0;
    	else
    		ret = 1;
    	return ret;
    }
    

    Ich würde bei einer Funktion mit dem Namen "empty" erwarten, dass sie mir wahr zurückliefert wenn das Ding leer ist, und nicht umgekehrt.

    ...und die könnte auch noch viel einfacher sein:

    int empty (void)
    {
       return pp_string[0] == 0;
    }
    

    bzw.

    #define empty() (pp_string[0] == 0)
    

    🙂



  • lifo-freak schrieb:

    Tim schrieb:

    int empty(void) {	// gibt 0 zurueck, wenn leer
    	int ret;
    	if(pp_string[0] == NULL)		// prueft ob erster Speicherplatz leer ist 
    		ret = 0;
    	else
    		ret = 1;
    	return ret;
    }
    

    Ich würde bei einer Funktion mit dem Namen "empty" erwarten, dass sie mir wahr zurückliefert wenn das Ding leer ist, und nicht umgekehrt.

    ...und die könnte auch noch viel einfacher sein:

    int empty (void)
    {
       return pp_string[0] == 0;
    }
    

    Ich könnte mir vorstellen, dass die explizitere Variante für einen Anfänger lesbarer ist. Das "Anfänger" kann man da fast sogar streichen. Und nach Compiler sollte das Ergebnis eh gleich aussehen.

    lifo-freak schrieb:

    bzw.

    #define empty() (pp_string[0] == 0)
    

    🙂

    Oh, wieder mal ein Macro ohne Grund. Brav. 🙄



  • Tim schrieb:

    Oh, wieder mal ein Macro ohne Grund. Brav.

    stimmt. diesmal ist es wirklich doof, denn er müsste noch ein 'extern char **pp_string;' hinschreiben. also vergesst das mit dem makro.
    🙂



  • MFK schrieb:

    lifo.c, Zeile 26.

    Außerdem sollst du den Rückgabewert von realloc nicht casten. Das hat aber nichts mit dem Fehler zu tun.

    Danke danke!!! Super 😃
    DAs ganze ist jetzt zwar noch nicht fehlerfrei, aber es kann ausgeführt werden!

    zu der Funktion empty:
    die pop() Funktion gibt schon 0 zurück, wenn der Stack leer ist, also hab ich das mit der empty Funktion genauso gemacht. Klar ist es eigentlich bescheuert, aber da liegt der "Fehler" schon bei meinem Prof. Aber auch wurst.

    Die ret / returns hab ich umgewandelt. dachte erst, man darf pro funktion nur ein return haben, egal ob mit if-cases verbaut und so.

    vielen dank auf jedenfall. hoffe den rest bekomme ich jetzt auch noch hin! 🤡 👍



  • Tim schrieb:

    int push(char *string) {
    	int ret = 1;
    	if((count % BLOCK) == 0) {	// 0, wenn alle Speicherplaetze bereits voll
    		pp_string = (char **)realloc(pp_string, (count + BLOCK) * sizeof(char *));	// reserviert Speicherplatz fuer BLOCK neue Zeiger
    		if(pp_string = NULL)	// wenn NULL, dann Speicherplatz nicht vorhanden -> return 0
    			ret = 0;
    	}
    	pp_string[count] = (char *)malloc(1 + strlen(string));	// erstellt Speicherplatz fuer den uebergebenen String + /0
    	strcpy(pp_string[count], string);	// kopiert uebergebenen String in Speicherplatz
    	pp_string[++count] = NULL;	// setzt Zeiger auf nächsten/letzten Speicherplatz, also NULL
    
    	return ret;
    }
    

    Hier überprüfst du zwar auf NULL, springst aber im Falle von NULL nicht direkt raus (sondern setzt nur ret) und würdest im Zweifelsfall eben jene NULL dereferenzieren. Das ist albern 😉

    Hier wird aber nicht auf NULL geprüft, sondern NULL zugewiesen.
    Deshalb hat das Ganze wahrscheinlich auch nicht funktioniert:)

    }-Tux-{



  • }-Tux-{ schrieb:

    Hier wird aber nicht auf NULL geprüft, sondern NULL zugewiesen.
    Deshalb hat das Ganze wahrscheinlich auch nicht funktioniert:)

    Ha, total übersehen 🙂


Anmelden zum Antworten