Untypischer Laufzeitfehler durch malloc()



  • @Swordfish sagte in Untypischer Laufzeitfehler durch malloc():

    @EL-europ sagte in Untypischer Laufzeitfehler durch malloc():

    alloziiere ich doch ein Feld von Zeigern das auf int-typen zeigt?

    Ja, damit bekommst Du ein "Array" von Zeigern auf int.
    feld zeigt dann auf einen zusammenhängenden Speicherbereich für diese Zeiger.

    Dann alloziierst Du für jeden dieser Zeiger ein "Array" von ints. Diese einzelnen Bereiche sind auch jeweils zusammenhängend, alle Werte direkt hintereinander im Speicher.

    ABER:
    Das "Array" auf das feld[1] zeigt kann ganz wo anders sein als das "Array" auf das feld[0] zeigt. Diese einzelnen "Arrays" können im Speicher überall verstreut sein.

    Deshalb kannst Du nicht einfach den ersten Zeiger feld[0] nehmen und von dem ausgehend bis feld[width * height - 1] durchgehen wie Du es zB in initalFeld() machst.

    Eben hab ich dich vielleicht verstanden und was dazu gelernt?
    In beiden Fällen sind es Zeiger auf int-typen, in erster Version sind die int-arrays nicht hintereinanader im Speicher und mit

    int **feld=malloc(size * sizeof(int *));
    

    werden auch die int-arrays hintereinander im Speicher abgelegt?



  • @EL-europ sagte in Untypischer Laufzeitfehler durch malloc():

    werden auch die int-arrays hintereinander im Speicher abgelegt?

    Nein.

    Ein Doppelzeiger **feld ist kein 2D-Array - es sieht nur so aus.



  • @DirkB
    ja stimmt. Durch den wiederholten Aufruf von malloc() in der Schleife für jedes einzelne array kann nicht gewährleisten sein das sie hintereinander liegen. oder?



  • @SeppJ
    es ist tatsächlich so das ich ein c-Grundlagen und ein c++ umfassendes Handbuch von J.W. habe die beide, zumindest Didaktisch, nicht an andere Autoren heranreichen. Seine Beispielcodes werfen oft Fragen auf die nicht beantwortet werden. Frag jetzt bitte nicht nach einem Beispiel, hab die Bücher grade hinter mir und mag nicht grundlos darin lesen und schlechte Beispiele suchen



  • Ich weiß nicht, wie man es Dir erzählen muss damit der Groschen fällt.

    int *foo;
    foo = malloc(42 * sizeof(int));
    

    Da ist foo ein Zeiger auf einen Integer dem das Ergebnis von malloc() zugewiesen wird. Diese von malloc() zurückgegebene Adresse steht nun in foo.

    Oben sagte ich "Zeiger auf einen" Integer. Du weißt aber, daß malloc() einen zusammenhängenden Speicherbereich besorgt hat, in dem 42 Integer alle direkt hintereinander liegen. Also kannst Du *(foo + 0), *(foo + 1), *(foo + 2), *(foo + 3), ... bis *(foo + 42 - 1) machen um auf die einzelnen Elemente dieses Speicherbereichs zuzugreifen. (Oder, dasselbe, nur hübscher: foo[0], foo[1], foo[2], ... bis foo[42 - 1].)

    Zu Deinem 2d-Dings:

    int **bar;  // ein Zeiger auf einen Zeiger auf Integer
    bar = malloc(42 * sizeof(int*));
    

    Da ist foo ein Zeiger auf einen [Zeiger auf Integer] dem das Ergebnis von malloc() zugewiesen wird. Diese von malloc() zurückgegebene Adresse steht nun in bar.

    Wieder dasselbe wie oben: in bar steht nun die von malloc() zurückgegebene Adresse und wir wissen, daß malloc() einen zusammenhängenden Speicherbereich besorgt hat in dem 42 [Zeiger auf Integer] alle direkt hintereinander liegen. Also können wir *(bar + 0), *(bar + 1), *(bar + 2), *(bar + 3), ... bis *(bar + 42 - 1) machen um auf die einzelnen Elemente dieses Speicherbereichs zuzugreifen. (Oder, dasselbe, nur hübscher: bar[0], bar[1], bar[2], ... bis bar[42 - 1].)

    Schön. Nun besorgen wir uns die 2. Dimension:

    int **bar;                           // dasselbe wie
    bar = malloc(42 * sizeof(int*));    // schon im letzten codeschnippsel
    
    for (size_t i = 0; i < 42; ++i)
        bar[i] = malloc(13 * sizeof(int));  // DIESE ZEILE
    

    besorgt nun jeweils mittels malloc() einen zusammenhängenden Speicherbereich für 13 Integer. Das Ergebnis von malloc() (=die Adresse wo dieser Speicherbereich beginnt) speichern wir jeweils in bar[0], bar[1], bar[2], ... bar[42 - 1].

    Das schaut nun im Speicher so aus:

    
    
     Irgendwo am Stack           Irgendwo am Heap                           Irgendwo am Heap
      |                           |                                           |
    +-------+    zeigt auf    +-------------------------+   zeigt auf      +-----------+
    | bar   |---------------> |  einen Zeiger auf int   |----------------->| einen int |
    +-------+                 |-------------------------|                  | einen int |
                              | malloc garantiert uns   |                  | einen int |
                  bar +  1 -->| daß einen Zeiger weiter |-----------+      | ...       |
                              | noch ein Zeiger ist der |           |      | einen int |
                              | uns gehört              |           |      +-----------+
                              |-------------------------|           |                                    Irgendwo am Heap
                  bar +  2 -->| und noch einer          |----+      |                                       |
                              |-------------------------|    |      |                                    +-----------+
                  bar +  3 -->| und noch einer          |    |      +----- *(*(bar + 1) +  0) ---------->| einen int |
                              |-------------------------|    |             *(*(bar + 1) +  1) ---------->| einen int |
                  ...               wird langweilig          |             *(*(bar + 1) +  2) ---------->| einen int |
                              |-------------------------|    |                   ...                     | ...       |
                  bar + 40 -->| und noch einer          |    |             *(*(bar + 1) + 12) ---------->| einen int |
                              |-------------------------|    |                                           +-----------+
                  bar + 41 -->| und der letzte          |    |
                              +-------------------------+    |                                           IRGENDWO am Heap
                                                             |                                            +-----------+
                                                             +-------------*(*(bar + 2) +  0) ----------->| einen int |
                                                                           *(*(bar + 2) +  1) ----------->| einen int |
                                                                           *(*(bar + 2) +  2) ----------->| einen int |
                                                                                 ...                      | ...       |
                                                                           *(*(bar + 2) + 12) ----------->| einen int |
                                                                                                          +-----------+
    

    Du kannst die Pointer bar[0], bar[1], bar[2], ... bar[42 - 1] nehmen und die dereferenzieren um zu den jeweiligen Anfängen der 2. Dimension zu kommen. bar[y] ist bloß eine hübsche Schreibweise für *(bar + y). Also ist bar[y][x] nur eine hübsche Schreibweise für *(*(bar + y) + x).

    Du addierst zu bar aber einfach immer weiter hinzu bis du irgendwann bei bar + y * x bist. Das funktioniert so nicht weil die Dingstis der "2. Dimension" überall im Speicher verstreut sein können und nicht hintereinander liegen.



  • @Th69 sagte in Untypischer Laufzeitfehler durch malloc():

    @hustbaer sagte in Untypischer Laufzeitfehler durch malloc():

    So wie die Schleife da steht läuft die bis inklusive width * height, sollte aber bis exklusive width * height laufen weil ja bei 0 angefangen wird.
    Also bei beispielsweise width = height = 4 würde die Schleife von 0 bis inklusive 4 laufen, also 5 mal. Sollte aber nur 4 mal laufen.

    Du meinst "würde die Schleife von 0 bis inklusive 16 laufen, also 17 mal. Sollte aber nur 16 mal laufen."!?!

    Fast. Ich wollte width = height = 2 und 4/5 schreiben, und hab dann fälschlicherweise 4/4/5 statt 2/4/5 geschrieben. Läuft aber auf's gleiche raus 🙂



  • Danke der Mühe @Swordfish 🙏🏻
    vor allem die Zeichnung hat mir geholfen zu verstehen. Eins hab ich nun auch noch gelernt: Der Zufall lässt auch Programme laufen die falsch geschrieben sind



  • Danke nochmal allen für ihre Beiträge, das Thema "Zeiger" verstehe ich dank @Swordfish nun besser.
    Jetzt beschäftige ich mich mit Threads in c um die Schlange alleine laufen zu lassen wenn keine Taste gedrückt wird.



  • Dazu brauchst Du keine Threads sondern nur etwas das Tastatureingaben ohne zu blocken erkennt. Schau nach ncurses, der funktion getch() und nodelay.



  • @Swordfish
    Danke für den Hinweis, werd jetzt ncurses Wiki studieren damit ich da rein komme. Hast du vielleicht noch ein paar Tips, oder zusammenfassende Worte für mich bezüglich der ncurses? So wie ich das jetzt verstehe muss neben dem einbinden der ncurses.h beim compilen dem Compiler über "-Incurses" mitgeteilt werden das er die ncurses "benutzt"
    Ist der Umgang anderes als mit den üblichen stdlib.h und stdio.h



  • @EL-europ Die Headerdateien .h sind nicht die Library
    Dort stehen (nur) die Informationen über die Funktionen, aber kein Code.
    Der Code dazu steht (meist) in .lib-Dateien und werden vom Linker dazu gebunden.
    Bei der Standardbibliothek ist das klar, bei Erweiterungen müssen die mit angegeben werden.

    In der Standardbibliothek sind eigentlich alle Funktionen der Header enthalten, die du mit den <> beim #include angibst.
    (wenn man da nicht selber rumgepfuscht hat)

    Eine Ausnahme ist <math.h>. Wenn man die Fließkommafunktionen nutzen möchte, muss man auf manchen Systemen die math-Libraray mit -lm dazu binden.
    (Das gilt nicht für + - * /, sondern für Funktionen wie sin(), sqrt(), ... )



  • @EL-europ
    ncurses ist kein C-Sprachstandard, ein standardkonformer Compiler muss diese Bibliothek nicht anbieten.



  • @Wutz Danke für die Info



  • Danke @DirkB für die ausführliche antwort. Aber mir kommen weitere Fragen dazu auf. Wenn du schon Antworten hast würde mir das einen Haufen "Forschungsarbeit" abnehmen.
    Library bedeuted: Das der Quellcode nicht verfügbar sondern nur ein Binary auf dem Entwicklungsrechner ist?
    Musss die Library auch auf dem Zielsystem vorhanden sein?
    Wenn ja, und ich den Quellcode habe und mit Einbinde muss dann trotzdem die Library auf Zielsystem vorhanden sein?
    Wenn ich cross-compile, brauche ich dann die Library im "cross-Format"?



  • @Wutz sagte in Untypischer Laufzeitfehler durch malloc():

    @EL-europ
    ncurses ist kein C-Sprachstandard, ein standardkonformer Compiler muss diese Bibliothek nicht anbieten.

    Das heisst es kann auch compiler geben bei denen "-lncurses" nicht funtioniert obgleich ich die Library habe?



  • @Swordfish sagte in Untypischer Laufzeitfehler durch malloc():

    Dazu brauchst Du keine Threads sondern nur etwas das Tastatureingaben ohne zu blocken erkennt. Schau nach ncurses, der funktion getch() und nodelay.

    Der "Automove" macht erst mit der curses richtig Sinn. Ansonsten ist Geflacker durch "clearscreen" zu stark.
    Aber Ich glaube die curses kommt mit schnellen Tastenanschlägen nicht so klar. wenn ich im "Automove-modus" eine Zeit (ca. 3-5min) lang spiele, stürzt das Programm einfach ab. Kannst du mir nochmal Helfen? Du hast doch den Speicher analysieren können. Vielleicht findest du wieder einen Programmfehler. Das wäre toll

    /* Klassikspiel snake v1.4
     * Eine Schlange zum Essen steuern 
     * ohne das diese sich nach dem zeiter Mahlzeit in den Schwanz beisst
     * 
     * unter Mithilfe von https://www.c-plusplus.net/forum/
     * nach einer Vorlage von https://www.c-howto.de/
     * 
     * @author: El Europ alias momefilo
     * Lizenz: GPL
     */
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <curses.h>
    #include <math.h>
    #include <time.h>
    #include <string.h>
    #include <unistd.h>
    
    /*Tasten zur Steuerung */
    #define MYKEY_UP	'w'
    #define MYKEY_DOWN	's'
    #define MYKEY_LEFT	'd'
    #define MYKEY_RIGHT	'a'
    
    /* Figuren auf dem Spielfeld */
    #define BLANK		0 /* Leeres Feld */
    #define HEAD		1 /* Kopf der Schlange */
    #define TAIL		2 /* Schwanz der Schlange */
    #define FOOD		3 /* Essen fuer die Schlange damit der Schwanz waechst */
    
    /* Spielevariablen */
    int autoMove	= 0; /* Beweggung ohne Tastendruck*/
    int xoffset		= 0; /* Zur Spielfeldzentrierung */
    int yoffset		= 0; /* Dito */
    int tailcount	= 0; /* Laenge des Schwanzes */
    int points		= 0; /* Erreichte Punkte */
    int width; 			 /* Spielfelddimension */
    int height; 		 /* Dito */
    char richtung; 		 /* Die aktuelle Richtung der Schlange */
    
    /* Position des HEAD */
    struct position{
    	int x;
    	int y;
    } pos; /* Position des HEAD */
    
    /* Initialisiert das Spielfeldarray 
     * Dank an @swordfish */
    void initalFeld(int **feld, int wert){
    	int x;
    	int y;
    	for(x=0; x<width; x++){
    		for(y=0; y<height; y++){
    			*(*(feld + x) + y) = wert;
    		}
    	}
    }
    
    /* Initialisiert das Schwanzarray */
    void initalTail(struct position *tail){
    	int cnt=0;
    	struct position myPos;
    	myPos.x=-1;
    	myPos.y=-1;
    	for(cnt=0; cnt <= width * height; cnt++){
    		*(tail + cnt) = myPos;
    	}
    }
    
    /* Setzt pos.x und pos.y Abhängig von der richtung */
    void myMove(){
    	switch(richtung){
    		case MYKEY_DOWN:
    			if(pos.y >= height -1) pos.y = 0;
    			else ++pos.y;
    			break;
    		case MYKEY_UP:
    			if(pos.y <= 0) pos.y = height -1;
    			else --pos.y;
    			break;
    		case MYKEY_LEFT:
    			if(pos.x >= width -1) pos.x = 0;
    			else ++pos.x;
    			break;
    		case MYKEY_RIGHT:
    			if(pos.x <= 0) pos.x = width -1;
    			else --pos.x;
    	}
    }
    
    /* Zeichnet den Spielfeldrand und Ueberschrift*/
    void printFeld(){
    	int x; /* Schleifenzaehler */
    	
    	/* Schriftzug mittig ueber Spielfeld */
    	int xoff = (width - 10) / 2;
    	if(xoff < 0) xoff = 0;
    	
    	/* Schriftstil fett */
    	attrset(A_BOLD);
    	
    	/* Ueberschrift zeichnen */
    	mvprintw(0+yoffset, xoff+xoffset, "Snake v%d.%d", 1, 4);
    	mvprintw(1+yoffset, xoff+xoffset, "(%d x %d)", width, height);
    	
    	/* Ecken Zeichnen */
    	mvaddch(yoffset + 3, xoffset, ACS_ULCORNER);
    	mvaddch(yoffset + 3, xoffset + width+1, ACS_URCORNER);
    	mvaddch(yoffset+height + 4, xoffset, ACS_LLCORNER);
    	mvaddch(yoffset+height + 4, xoffset+width + 1, ACS_LRCORNER);
    	
    	/* Linke und rechte Kante zeichnen */
    	for(x=4; x<=height +3; x++){
    		mvaddch(yoffset+x, xoffset, ACS_VLINE);
    		mvaddch(yoffset+x, xoffset+width + 1, ACS_VLINE);
    	}
    	
    	/* Obere und untere Kante zeichnen */
    	for(x=1; x<=width; x++){
    		mvaddch(yoffset+3, xoffset+x, ACS_HLINE);
    		mvaddch(yoffset+height + 4, xoffset+x, ACS_HLINE);
    	}
    }
    
    /* Setzt FOOD zufaellig aufs Spielfeld */
    void setFood(int **feld){
    	int x;
    	int y;
    	do{
    		x=rand() % width;
    		y=rand() % height;
    	}while(*(*(feld + x) + y) != BLANK);
    	feld[x][y] = FOOD; 									/* Spielfeld aktualisieren */
    	attrset(A_BOLD|COLOR_PAIR(2));						/* Farbe blau fuer FOOD */
    	mvaddch(yoffset+y + 4, xoffset+x + 1, ACS_DIAMOND); /*Figur FOOD zeichnen */
    	attrset(A_BOLD|COLOR_PAIR(1));						/* Farbe wieder gelb */
    }
    
    /* Zum Start des Spiels. Zeichnet spielfeld neu und setzt HEAD/FOOD/points */
    void resetGame(int **feld, struct position *tail){
    	
    	clear(); 											/* Bildschirm leeren */
    	printFeld(); 										/*Ueberschrift und Rand zeichnen */
    	initalFeld(feld, BLANK); 							/* Spielfeldarray initialisieren */
    	initalTail(tail); 									/* Schwanz initialisieren */
    	
    	/* HEAD platzieren */
    	pos.x	= width / 2;
    	pos.y	= height / 2;
    	feld[pos.x][pos.y] = HEAD; 							/* Feldarray aktualisieren */
    	mvaddch(yoffset+pos.y + 4, xoffset+pos.x + 1, '@'); /* Figur zeichnen */
    	
    	/* FOOD Platzieren */
    	setFood(feld);
    	
    	/* Spielvariablen ruecksetzten */
    	tailcount = 0;
    	points = 0;
    	
    	/* Punkte anzeigen */
    	mvprintw(yoffset+height+5,xoffset,"Punkte %d",points);
    	
    	/* Wenn Option Automove aktiv */
    	if(autoMove)nodelay(stdscr, TRUE);
    }
    
    /* Fuehrt Spielzug auf feldarray aus aktualisiert das tailarray
     * und zeichnet die Figuren und Punktzahl
     * Beisst sich die Schlange in den Schwanz return 0 (Game over) sonst 1*/
    int setFeld(int **feld, struct position *tail, int bevor){
    	
    	int ret = 1;				/* Wenn die Schlange in den Schwanz beisst return 0 */
    	int figur;					/* Die Figur auf der neuen Position im Feld (BLANK,TAIL,FOOD) */
    	static int hasFood	= 0;	/* Wenn die Schlange grad was zu Essen fand */
    	int cnt;
    	struct position tailPos;	/* Position für tail-Elemente */
    	
    	/* Vor dem Zug. Der HEAD verlaesst die Position pos
    	 * Den Schwanz verschieben und zeichnen */
    	if(bevor){
    		
    		/* Die von HEAD verlassende position pos leeren */
    		feld[pos.x][pos.y] = BLANK;
    		mvaddch(yoffset+pos.y+4, xoffset+pos.x + 1, ' ');
    		
    		/* Hat die Schlange ueberhaupt einen Schwanz */
    		if(tailcount > 0){
    			
    			/* Hat die Schlange zuvor kein FOOD gefunden verschiebe Schwanz */
    			if(! hasFood){
    				
    				/*Schwanzende loeschen */
    				tailPos = tail[0];
    				feld[ tailPos.x ][ tailPos.y ] = BLANK;
    				mvaddch(yoffset+tailPos.y+4, xoffset+tailPos.x + 1, ' ');
    			
    				/* Wenn Schwanzlaenge > 1 verschieben */
    				if(tailcount > 1){
    					for(cnt=0; cnt<tailcount-1; cnt++)
    						tail[cnt] = tail[cnt +1];
    					tail[tailcount - 1] = pos; /* Neue Position vor dem HEAD */
    				}
    				
    				/* Sonst einfach neuen Anfang setzten */
    				else tail[0] = pos;
    				
    			/* oder FOOD wurde zuvor gefunden und wird jetzt verdaut */
    			}else hasFood = 0;
    			
    			/* Schwanzanfang im Spielfeld setzen und zeichnen */
    			feld[pos.x][pos.y] = TAIL;
    			mvaddch(yoffset+pos.y + 4, xoffset+pos.x + 1, '*');
    		}
    		
    	/* Oder nach dem Zug. Der HEAD besetzt die Position pos 
    	 * Figuren auswerten und neu Zeichnen*/	
    	}else{
    			figur = feld[pos.x][pos.y];	/* was ist aktuell auf der neuen Position */
    			if(figur==TAIL) ret = 0;	/* TAIL: In den Schwanz gebissen - Gameover */
    			else if(figur==FOOD){ 		/* FOOD: Was zu Essen gefunden */
    				tail[tailcount] = pos;	/* Neues tail-Element einfügen */
    				setFood(feld);			/* Frischen Essen servieren :) */
    				hasFood = 1;			/* Fuer nachsten Zug vormerken */
    				++tailcount;
    				points += 10;
    			}
    			/* HEAD zeichnen und im Spielfeldarray setzten */
    			feld[pos.x][pos.y] = HEAD;
    			mvaddch(yoffset+pos.y + 4,xoffset+pos.x+1, '@');
    			
    			/* Punke anzeigen */
    			mvprintw(yoffset+height+5,xoffset,"Punkte %d",points);
    	}
    	return ret;
    }
    
    /* Beendet curses */
    void quit(){endwin();}
    
    
    int main(int argc, char *argv[]){
    	
    	int **feld;							/* Spielfeld */
    	struct position *tail; 				/* Schwanz */
    	int cnt;							/* Schleifenvariable */
    	int myx; 							/* Zur Spielfeldzentrierung */
    	int myy; 							/* Dito */
    	srand( (unsigned int) time(NULL) ); /* Zufall initialisieren */
    	
    	/* Bei unkorrekten Komandozeilenargumenten erfolgt Abbruch */
    	if(argc > 2){
    		width=atoi(argv[1]);
    		height=atoi(argv[2]);
    		if(width > 1 && height > 1){
    			feld = malloc(width * sizeof(int *));
    			for(cnt=0; cnt<width; cnt++)feld[cnt]=malloc(height * sizeof(int));
    			tail = (struct position *)malloc((width * height +1) *(sizeof(struct position)));
    		}else{
    			printf("Aufruf mit 'snake breite hoehe [option a=Automove]' min: 'snake 2 2'\n");
    			printf("Steuerung mit 'w' 'a' 's' 'd' Ende 'x'\n");
    			return 0;
    		}
    	}else{
    		printf("Aufruf mit 'snake breite hoehe [option a=Automove]' min: 'snake 2 2'\n");
    		printf("Steuerung mit 'w' 'a' 's' 'd' Ende 'x'\n");
    		return 0;
    	}
    	
    	/* Ist Automove aktiviert ?*/
    	if(argc>3)autoMove = 1;
    	
    	/* curses initialisieren */
    	initscr();
    	atexit(quit);
    	curs_set(0);
    	noecho();
    	start_color();
    	init_pair(1, COLOR_YELLOW, COLOR_BLACK);
    	init_pair(2, COLOR_CYAN, COLOR_BLACK);
    	bkgd(COLOR_PAIR(1));
    	cbreak();
    	keypad(stdscr, TRUE);
    
    	/*Spielfeld zentrieren */
    	getmaxyx(stdscr ,myy, myx);
    	if(width>myx-4 || height>myy-16){ /* Spielfeld zu gross fuer Screen */
    		attrset(A_BOLD);
    		mvprintw(LINES/2,0,"Das Spielfeld ist zu gross max:%d x %d",myx-4,myy-16);
    		mvprintw(LINES/2+1,0,"mit taste beenden und mit max neu aufrufen");
    		getch();
    		return 0;
    	}
    	xoffset = myx/2 - width/2 -1;
    	yoffset = myy/2 - height/2;
    	
    	/* Spiel starten */
    	resetGame(feld, tail);
    	while(richtung != 'x'){
    	
    	/* Wenn Automove aktiv sleep() aktivieren*/
    	if(autoMove){
    		if(richtung == 'a' || richtung == 'd')usleep(100000);
    		else if(richtung == 'w' || richtung == 's')usleep(150000);
    	}
    	
    	/* Neue Richtung einlesen */			
    	char key = getch();
    	if(key=='w' || key=='a' || key=='s' || key=='d' || key=='x')
    		richtung = key;
    		
    	/* Spielfeld vor dem Zug setzten. HEAD verlaesst die pos */
    	setFeld(feld, tail, 1);
    	
    	/* Zug Ausführen */
    	myMove();
    	
    	/* Spielfeld nach dem Zug setzten 
    	 * gewonnen und verloren auswerten */
    	if(! setFeld(feld, tail, 0) || points > width*height*10 -30){
    		
    		/* damit auf getch() gewartet wird */
    		nodelay(stdscr, FALSE); 
    		
    		/* Schriftfarbe aendern */
    		attrset(A_BOLD|COLOR_PAIR(2));
    		
    		/* Gewonnen ?*/
    		if(points > width*height*10 -30)
    			mvprintw(yoffset+height/2,xoffset+2,"Sie haben gewonnen! Nochmal j");
    			
    		/* oder verloren */
    		else
    			mvprintw(yoffset+height/2,xoffset+2,"Sie haben verloren! Nochmal j");
    		attrset(A_BOLD|COLOR_PAIR(1));
    		key = getch();
    		if(key != 'j') break; /*Spiel verlassen */
    		else resetGame(feld,tail); /*Spiel neu starten */
    	}
    	
    	/* Naechster/neuer zug beginnt */
    	}
    	quit(); /* curses beenden */
    }
    


  • @EL-europ sagte in Untypischer Laufzeitfehler durch malloc():

    Library bedeuted: Das der Quellcode nicht verfügbar sondern nur ein Binary auf dem Entwicklungsrechner ist?

    Jain.
    Die Library ist compiliert, du kannst dennoch den Quellcode dafür haben.

    Musss die Library auch auf dem Zielsystem vorhanden sein?

    Das kommt auf das Format an.
    Es gibt statische Librarys - die werden mit deinem Code zu einer Exe gelinkt und sind somit Teil des Programms.
    Und es gibt dynamischel Librarays (DLL "Dynamic Linked Library") - die werden erst zur Laufzeit eingebunden und sind extra Dateien.
    Da DLL extra Dateien sind, kann man sie leicht durch neuere ersetzen, bzw können sich mehrere Programme eine DLL teilen.
    (In C gehört zu einer DLL noch eine lib, die die Aufrufe in die DLL kapselt)

    Wenn ja, und ich den Quellcode habe und mit Einbinde muss dann trotzdem die Library auf Zielsystem vorhanden sein?

    s.o.

    Wenn ich cross-compile, brauche ich dann die Library im "cross-Format"?

    Die Library muss - wie auch alle anderen Codebestandteile - für das Zielsystem geeignet sein.
    Wenn du den Quellcode hast, kannst du die selber erstellen, wenn nicht downloaden oder kaufen oder fluchen.



  • @EL-europ sagte in Untypischer Laufzeitfehler durch malloc():

    Das heisst es kann auch compiler geben bei denen "-lncurses" nicht funtioniert obgleich ich die Library habe?

    -lncurses ist eine Linkeroption (der wird vom Compiler aufgerufen). Du musst dann noch mit einer anderen Option weitere Pfade angeben, wo er nach Librarys suchen soll.
    Du kannst auch angeben, wo der Compiler bei #include "keinsystemheader.h" suchen soll.



  • @DirkB sagte in Untypischer Laufzeitfehler durch malloc():

    Es gibt statische Librarys - die werden mit deinem Code zu einer Exe gelinkt und sind somit Teil des Programms.
    Und es gibt dynamischel Librarays (DLL "Dynamic Linked Library") - die werden erst zur Laufzeit eingebunden und sind extra Dateien.
    Da DLL extra Dateien sind, kann man sie leicht durch neuere ersetzen, bzw können sich mehrere Programme eine DLL teilen.
    (In C gehört zu einer DLL noch eine lib, die die Aufrufe in die DLL kapselt)

    Da er ein Ubuntu nutzt, gibt es dort natürlich keinerlei DLLs. Unter UNIX/Linux wird das Thema Libraries etwas anders gehandhabt als unter Windows.

    Bei Systemen mit dem Programmformat ELF (es gibt auch noch andere wie XCOFF, Mach-O, …) verhält es sich wie folgt.

    • Es gibt Archives mit der Endung .a, das ist nichts anderes als eine Sammlung an übersetzten Dateien, die in einer Datei archiviert werden. Sie werden als statische Libraries genutzt.
    • Es gibt Shared Libraries mit der Endung .so. Diese werden erst beim Programmstart geladen, und das System nutzt sie um die Symbole in Programm aufzulösen. Danach kann das Programm genutzt werden.
    • *.so Dateien können auch während der Laufzeit über dlopen in den Andressraum des Programms geladen werden.

    Alle *.so Libraries müssen auf dem Zielsystem vorhanden sein. Das kann man bei Ubuntu entweder mit Hilfe eines *.deb Packets erreichen, dann installiert das System ggf. die notwendigen Library Pakete nach, oder erstelle ein Flatpak, Snap, … und lieferte die Libraries mit aus.



  • @DirkB sagte in Untypischer Laufzeitfehler durch malloc():

    -lncurses ist eine Linkeroption (der wird vom Compiler aufgerufen). Du musst dann noch mit einer anderen Option weitere Pfade angeben, wo er nach Librarys suchen soll.

    Das braucht man bei Ubuntu nicht, wenn die Library in einem der üblichen Standardverzeichnisse des Systems liegt.