Schnellere Alternative zu printf, write und setchar



  • Hallo Ihr lieben,
    ich beschäftige mich seit kurzem mit C; ich komme von Python, weshalb mein Wissen sehr eingeschränkt ist. Da ich mich noch nicht an die GUI Programmierung herangewagt habe, versuche ich ein kleines, simples Spiel über die Benutzung des Terminals zu erstellen, bei welchem der Spieler mit Hilfe der WASD Tasten ein X steuern kann. Alles tut auch das was ich möchte, allerdings geschieht das ausgeben der Zeichen in das Terminal viel zu langsam, da ich so viele Zeichen sehr schnell hintereinander ausgeben lassen möchte. Ich habe schon Alternativen zu printf(), wie zum Beispiel write() oder setchar() ausprobiert, wobei in der Geschwindigkeit keine auffallenden Unterschiede zu verzeichnen waren. Deshalb wollte ich nach einer schnelleren Alternative zu diesen Funktionen fragen. Falls ihr Anmerkungen zum Programmierstil oder der Herangehensweise habt, würde es mich freuen, da ich gerne mehr Erfahrung sammeln würde. Die Funktion, die von Wichtigkeit ist, ist die print() Funktion in Zeile 40 .Der Quellcode lautet:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #define XSIZE 168
    #define YSIZE 43
    
    int xcor = 0;
    int ycor = 0;
    int running = 1;
    int i, j;
    char feld[YSIZE][XSIZE];
    char player_shp = 'x';
    char void_shp = ' ';
    char input;
    
    main() {
        update();
        while(running == 1){
            update();
            print();
            events();
        }
    }
    
    update(){
        for(i=0; i<YSIZE; i++){
            for(j=0; j<XSIZE; j++){
                if((i == 0) || (i == (YSIZE - 1)))
                    feld[i][j] = '-';
                else if((j == 0) || (j == (XSIZE - 1)))
                    feld[i][j] = '|';
                else
                    feld[i][j] = void_shp;
            }
        feld[ycor][xcor] = player_shp;
        }
    }
    
    print(){
        system("cls");
        for(i=0; i<YSIZE; i++){
            for(j=0; j<XSIZE; j++){
                write(STDOUT_FILENO, &feld[i][j], 1);
            }
            printf("\n");
        }
    }
    
    events(){
        switch(input = getch()){
            case 'w':
                if(ycor == 0)
                    running = 0;
                ycor--;
                break;
            case 'a':
                if(xcor == 0)
                    running = 0;
                xcor--;
                break;
            case 's':
                if(ycor == (YSIZE - 1))
                    running = 0;
                ycor++;
                break;
            case 'd':
                if(xcor == (XSIZE - 1))
                    running = 0;
                xcor++;
        }
    }
    
    

    Ich bedanke mich für jegliche Hilfe.

    Gruß Daniel



  • @daniel verzichte auf das system

    Lerne modernes C, also das ab 1989 (C89)



  • @daniel sagte in Schnellere Alternative zu printf, write und setchar:

    system("cls");
    

    ... ist Sau-lahm. system() started eine neue Shell um den Befehl auszuführen. Schau dir lieber die Console Functions der WinAPI an. Auch solltest Du nicht immer wieder das gesamte Spielfeld schreiben, sondern bloß die Änderungen.

    Ich sehe grad

    @daniel sagte in Schnellere Alternative zu printf, write und setchar:

    #include <unistd.h>
    

    system("cls") ließ mich auf Windows schließen. Für Linux und sonstige Unixoide schau nach der ncurses library.

    Und bitte, lerne Funktionsparameter zu benutzen. Für jede globale Variable stirbt irgendwo ein Kätzchen 😞 😢



  • Der Flaschenhals wird immer der output in die Konsole sein. Etwas schneller geht es, wenn man die WinApi-Funktionen nutzt. mE geht es am schnellsten, wenn man seinen eigenen Buffer hat, und den dann in die Konsole schreibt.

    void Console::writeBuffer()
    {
        const std::vector<CHAR_INFO> outbuffer = convertToCHAR_INFO();
        const CHAR_INFO* output = outbuffer.data();
        SMALL_RECT rect = { 0, 0,
                            static_cast<SHORT>( columns -1 ),
                            static_cast<SHORT>( rows    -1 )
                          };
        WriteConsoleOutput( wHnd, output,
                            COORD { static_cast<SHORT>( columns ), static_cast<SHORT>( rows ) },
                            COORD { 0, 0 },
                            &rect );
    }
    


  • @Swordfish sagte in Schnellere Alternative zu printf, write und setchar:

    system("cls") ließ mich auf Windows schließen.

    Ups, mich auch.



  • @lemon03 sagte in Schnellere Alternative zu printf, write und setchar:

    Der Flaschenhals wird immer der output in die Konsole sein.

    Mhm. Und einen neuen Prozess starten um die Ausgabe zu "leeren" ist noch lahmer.

    @lemon03 sagte in Schnellere Alternative zu printf, write und setchar:

    Ups, mich auch.

    Und Du hast Dich im Forum geirrt. Hier ist C, nicht C++. 😛



  • @Swordfish sagte in Schnellere Alternative zu printf, write und setchar:

    @lemon03 sagte in Schnellere Alternative zu printf, write und setchar:

    Der Flaschenhals wird immer der output in die Konsole sein.

    Mhm. Und einen neuen Prozess starten um die Ausgabe zu "leeren" ist noch lahmer.

    @lemon03 sagte in Schnellere Alternative zu printf, write und setchar:

    Ups, mich auch.

    Und Du hast Dich im Forum geirrt. Hier ist C, nicht C++. 😛

    Und? Die WinAPI ist eine C API und daher Windows = C++ anzunehmen ist da doch etwas weit hergeholt



  • @firefly sagte in Schnellere Alternative zu printf, write und setchar:

    Und? Die WinAPI ist eine C API und daher Windows = C++ anzunehmen ist da doch etwas weit hergeholt

    @firefly sagte in Schnellere Alternative zu printf, write und setchar:

    Hier ist C, nicht C++.

    bezog sich auf

    @lemon03 sagte in Schnellere Alternative zu printf, write und setchar:

    void Console::writeBuffer()
    {
        const std::vector<CHAR_INFO> outbuffer = convertToCHAR_INFO();
        // ...
    

    Vielleicht erstmal Kaffee, fly?



  • Vielen Dank für all die schnellen Antworten, ich werde sie mir mal genauer ansehen. Warum soll ich keine Globalen Variablen benutzen? Ich habe ursprünglich nur auf lokale gesetzt, allerdings hat das nur zu mehr Code und weniger Übersichtlichkeit geführt.

    Danke!

    Daniel



  • @daniel Das einzige vernünftige an deinem Code ist die Formatierung/Einrückung.

    Der Rest ist Schrott.

    Wenn du in C programmieren willst, dann programmiere C und nicht Python.

    Python ist schließlich nicht Fortran.





  • Geschmacksmuster mit ncurses (Windows: pdcurses):

    #include <stdlib.h>  // EXIT_FAILURE
    #include <stdio.h>   // fputs()
    
    #ifdef __linux__
    #	include <unistd.h>
    #	define delay(micro_seconds) usleep((micro_seconds))
    #elif _WIN32
    #	define _WIN32_LEAN_AND_MEAN
    #	include <windows.h>
    #	undef MOUSE_MOVED // conflicts with curses.h
    #	define delay(micro_seconds) Sleep((micro_seconds))
    #endif
    
    #include "curses.h"   // initscr(), resize_term(), refresh()
    
    
    typedef enum error_tag {
    	ERROR_NONE, ERROR_WINDOW_RESIZE, ERROR_NOECHO, ERROR_SET_CURSOR, ERROR_SET_NODELAY,
    	ERROR_SET_CBREAK, ERROR_DRAW_BORDER, ERROR_WINDOW_REFRESH, ERROR_PLAYER_WINDOW,
    } error_t;
    
    char const * const error_message[] = {
    	"No error.",
    	"Couldn't resize the console window.",
    	"Couldn't set no echo mode."
    	"Couldn't set cursor size.",
    	"Couldn't set no delay mode.",
    	"Couldn't set cbreak-mode.",
    	"Couldn't draw border.",
    	"Couldn't refresh window.",
    	"Couldn't create player window.",
    };
    
    void handle_error(error_t error)
    {
    	endwin();
    	fputs(error_message[error], stderr);
    	fputs("\n\n", stderr);
    }
    
    
    enum { PLAYFIELD_WIDTH = 168, PLAYFIELD_HEIGHT = 43, DELAY = 100, PLAYER_GLYPH = 'X' };
    enum { KEY_MOVE_UP = 'w', KEY_MOVE_DOWN = 's', KEY_MOVE_RIGHT = 'd', KEY_MOVE_LEFT = 'a', KEY_QUIT = 0x1b };  // 0x1b == ESC
    
    
    typedef struct position_tag {
    	int x, y;
    } position_t;
    
    typedef enum direction_tag {
    	DIRECTION_NONE, DIRECTION_UP, DIRECTION_DOWN, DIRECTION_LEFT, DIRECTION_RIGHT
    } direction_t;
    
    typedef struct player_tag {
    	position_t   position;
    	direction_t  direction;
    	WINDOW      *window;
    } player_t;
    
    error_t player_create(player_t *player)
    {
    	player_t new_player = { { PLAYFIELD_WIDTH / 2, PLAYFIELD_HEIGHT / 2 }, DIRECTION_NONE };
    
    	new_player.window = newwin(1, 1, new_player.position.y, new_player.position.x);
    	if (!new_player.window)
    		return ERROR_PLAYER_WINDOW;
    
    	waddch(new_player.window, PLAYER_GLYPH);
    
    	*player = new_player;
    	return ERROR_NONE;
    }
    
    bool player_move(player_t *player)
    {
    	switch (player->direction) {
    	case DIRECTION_UP:
    		if (--player->position.y == 0)
    			return FALSE;
    		break;
    	case DIRECTION_DOWN:
    		if (++player->position.y == PLAYFIELD_HEIGHT - 1)
    			return FALSE;
    		break;
    	case DIRECTION_LEFT:
    		if (--player->position.x == 0)
    			return FALSE;
    		break;
    	case DIRECTION_RIGHT:
    		if (++player->position.x == PLAYFIELD_WIDTH - 1)
    			return FALSE;
    		break;
    	}
    
    	wclear(player->window);
    	wrefresh(player->window);
    	mvwin(player->window, player->position.y, player->position.x);
    	waddch(player->window, PLAYER_GLYPH);
    	wrefresh(player->window);
    
    	return TRUE;
    }
    
    void player_destroy(player_t *player)
    {
    	delwin(player->window);
    }
    
    
    error_t draw_border(WINDOW *window)
    {
    	if (box(window, 0, 0) == ERR)
    		return ERROR_DRAW_BORDER;
    
    	if (refresh() == ERR)
    		return ERROR_WINDOW_REFRESH;
    
    	return ERROR_NONE;
    }
    
    error_t init_ncurses(WINDOW *window)
    {
    	if (resize_term(PLAYFIELD_HEIGHT, PLAYFIELD_WIDTH) == ERR)
    		return ERROR_WINDOW_RESIZE;
    
    	if (noecho() == ERR)
    		return ERROR_NOECHO;
    
    	if (cbreak() == ERR)
    		return ERROR_SET_CBREAK;
    
    	if (curs_set(0) == ERR)
    		return ERROR_SET_CURSOR;
    
    	if (nodelay(window, TRUE) == ERR)
    		return ERROR_SET_NODELAY;
    
    	return ERROR_NONE;
    }
    
    bool handle_input(WINDOW *window, player_t *player)
    {
    	int ch;
    	if ((ch = getch()) == ERR)
    		return FALSE;
    
    	BOOL result = FALSE;
    
    	switch(ch) {
    	case KEY_MOVE_UP:
    		player->direction = DIRECTION_UP;
    		break;
    	case KEY_MOVE_DOWN:
    		player->direction = DIRECTION_DOWN;
    		break;
    	case KEY_MOVE_RIGHT:
    		player->direction = DIRECTION_RIGHT;
    		break;
    	case KEY_MOVE_LEFT:
    		player->direction = DIRECTION_LEFT;
    		break;
    	case KEY_QUIT:
    		result = TRUE;
    	}
    
    	while (getch() != ERR);
    
    	return result;
    }
    
    
    int main(void)
    {
    	WINDOW *window = initscr();
    	error_t error = init_ncurses(window);
    
    	if (error != ERROR_NONE) {
    		handle_error(error);
    		return EXIT_FAILURE;
    	}
    
    	error = draw_border(window);
    	if (error != ERROR_NONE) {
    		handle_error(error);
    		return EXIT_FAILURE;
    	}
    
    	player_t player;
    	error = player_create(&player);
    	if (error != ERROR_NONE) {
    		handle_error(error);
    		return EXIT_FAILURE;
    	}
    
    	bool alive = TRUE;
    	bool quit = FALSE;
    	do {
    		quit = handle_input(window, &player);
    		alive = player_move(&player);
    		delay(DELAY);
    	} while (alive && !quit);
    
    	player_destroy(&player);
    	endwin();
    }
    

    Noch 'nen Schwanz wachsen lassen und Snake ist (halb-) fertig.



  • Aufgeblasen zu Snake:

    #include <stddef.h>  // size_t
    #include <stdlib.h>  // EXIT_FAILURE, srand(), rand(), malloc(), realloc(), free()
    #include <stdio.h>   // fputs()
    #include <time.h>    // time()
    
    #ifdef __linux__
    #	include <unistd.h>
    #	define delay(micro_seconds) usleep((micro_seconds))
    #elif _WIN32
    #	define _WIN32_LEAN_AND_MEAN
    #	include <windows.h>
    #	undef MOUSE_MOVED // conflicts with curses.h
    #	define delay(micro_seconds) Sleep((micro_seconds))
    #endif
    
    #include "curses.h"   // WINDOW, initscr(), resize_term(), refresh(), wrefresh(), newwin(), delwin(), mvwin(),
                          // waddch(), wclear(), endwin(), box(), getch(), ...
    
    
    typedef enum error_tag {
    	ERROR_NONE, ERROR_WINDOW_RESIZE, ERROR_NOECHO, ERROR_SET_CURSOR, ERROR_SET_NODELAY,
    	ERROR_SET_CBREAK, ERROR_DRAW_BORDER, ERROR_WINDOW_REFRESH, ERROR_PLAYER_WINDOW,
    	ERROR_FRUIT_WINDOW, ERROR_MEMORY,
    } error_t;
    
    char const *error_message[] = {
    	"No error.",
    	"Couldn't resize the console window.",
    	"Couldn't set no echo mode."
    	"Couldn't set cursor size.",
    	"Couldn't set no delay mode.",
    	"Couldn't set cbreak-mode.",
    	"Couldn't draw border.",
    	"Couldn't refresh window.",
    	"Couldn't create player window.",
    	"Couldn't create fruit window.",
    	"Out of memory."
    };
    
    void handle_error(error_t error)
    {
    	endwin();
    	fputs(error_message[error], stderr);
    	fputs("\n\n", stderr);
    }
    
    
    enum { PLAYFIELD_WIDTH = 168, PLAYFIELD_HEIGHT = 43, HDELAY = 50, VDELAY = 100, PLAYER_GLYPH = 'X', FRUIT_GLYPH = 'O' };
    enum { KEY_MOVE_UP = 'w', KEY_MOVE_DOWN = 's', KEY_MOVE_RIGHT = 'd', KEY_MOVE_LEFT = 'a', KEY_QUIT = 0x1b };
    
    
    typedef struct position_tag {
    	int x, y;
    } position_t;
    
    typedef enum direction_tag {
    	DIRECTION_NONE, DIRECTION_UP, DIRECTION_DOWN, DIRECTION_LEFT, DIRECTION_RIGHT
    } direction_t;
    
    
    typedef struct player_tag {
    	position_t   *position;
    	direction_t   old_direction;
    	direction_t   direction;
    	WINDOW       *head;
    	WINDOW       *tail;
    	size_t        size;
    	size_t        length;
    	size_t        growing;
    	bool          alive;
    } player_t;
    
    error_t player_create(player_t *player)
    {
    	player_t new_player = { 0 };
    
    	new_player.position = malloc(sizeof(*new_player.position));
    	if (!new_player.position)
    		return ERROR_MEMORY;
    
    	new_player.position[0].x = PLAYFIELD_WIDTH / 2;
    	new_player.position[0].y = PLAYFIELD_HEIGHT / 2;
    
    	new_player.head = newwin(1, 1, new_player.position[0].y, new_player.position[0].x);
    	if (!new_player.head) {
    		free(new_player.position);
    		return ERROR_PLAYER_WINDOW;
    	}
    
    	new_player.tail = newwin(1, 1, new_player.position[0].y, new_player.position[0].x);
    	if (!new_player.tail) {
    		free(new_player.position);
    		delwin(player->head);
    		return ERROR_PLAYER_WINDOW;
    	}
    
    	waddch(new_player.head, PLAYER_GLYPH);
    
    	new_player.size = 1;
    	new_player.length = 1;
    	new_player.growing = 0;
    	new_player.alive = TRUE;
    
    	*player = new_player;
    	return ERROR_NONE;
    }
    
    bool player_is_within_body(player_t const *player, position_t const *position)
    {
    	for (size_t i = 1; i < player->length; ++i)
    		if (position->x == player->position[i].x && position->y == player->position[i].y)
    			return TRUE;
    	return FALSE;
    }
    
    bool player_is_cannibal(player_t const *player)
    {
    	return
    		player->length > 1 &&
    		( player->direction == DIRECTION_UP && player->old_direction == DIRECTION_DOWN ||
    		  player->direction == DIRECTION_DOWN && player->old_direction == DIRECTION_UP ||
    		  player->direction == DIRECTION_LEFT && player->old_direction == DIRECTION_RIGHT ||
    		  player->direction == DIRECTION_RIGHT && player->old_direction == DIRECTION_LEFT
    		) || player_is_within_body(player, &player->position[0]);
    }
    
    bool player_is_alive(player_t const *player)
    {
    	return player->alive;
    }
    
    error_t player_move(player_t *player)
    {
    	position_t new_head = player->position[0];
    
    	if (player_is_cannibal(player)) {
    		player->alive = FALSE;
    	}
    	else {
    		switch (player->direction) {
    		case DIRECTION_UP:
    			if (--new_head.y == 0)
    				player->alive = FALSE;
    			break;
    		case DIRECTION_DOWN:
    			if (++new_head.y == PLAYFIELD_HEIGHT - 1)
    				player->alive = FALSE;
    			break;
    		case DIRECTION_LEFT:
    			if (--new_head.x == 0)
    				player->alive = FALSE;
    			break;
    		case DIRECTION_RIGHT:
    			if (++new_head.x == PLAYFIELD_WIDTH - 1)
    				player->alive = FALSE;
    			break;
    		}
    	}
    
    	if (!player->alive)
    		return ERROR_NONE;
    
    	if (player->growing && player->length == player->size) {
    		position_t *tmp = realloc(player->position, (player->size + 5) * sizeof(*tmp));
    		if (!tmp)
    			return ERROR_MEMORY;
    		player->position = tmp;
    		player->size += 5;
    	}
    
    
    	for (size_t i = player->length - !(player->growing); i; --i)
    		player->position[i] = player->position[i - 1];
    	player->position[0] = new_head;
    
    	if (!player->growing) {
    		wclear(player->tail);
    		wrefresh(player->tail);
    		mvwin(player->tail, player->position[player->length - 1].y, player->position[player->length - 1].x);
    	}
    	else {
    		--player->growing;
    		++player->length;
    	}
    
    	mvwin(player->head, player->position[0].y, player->position[0].x);
    	waddch(player->head, PLAYER_GLYPH);
    	wrefresh(player->head);
    
    	return ERROR_NONE;
    }
    
    bool player_is_moving_horizontally(player_t const *player)
    {
    	return player->direction == DIRECTION_RIGHT || player->direction == DIRECTION_LEFT;
    }
    
    void player_destroy(player_t *player)
    {
    	delwin(player->head);
    	delwin(player->tail);
    	free(player->position);
    }
    
    
    typedef struct fruit_tag {
    	position_t  position;
    	WINDOW     *window;
    } fruit_t;
    
    error_t fruit_create(fruit_t *fruit, player_t const *player)
    {
    	fruit_t new_fruit;
    
    	do {
    		new_fruit.position.x = rand() % (PLAYFIELD_WIDTH - 2) + 1;
    		new_fruit.position.y = rand() % (PLAYFIELD_HEIGHT - 2) + 1;
    	} while (new_fruit.position.x == player->position[0].x &&
    	         new_fruit.position.y == player->position[0].y ||
    	         player_is_within_body(player, &new_fruit.position));
    
    
    	new_fruit.window = newwin(1, 1, new_fruit.position.y, new_fruit.position.x);
    	if (!new_fruit.window)
    		return ERROR_FRUIT_WINDOW;
    
    	waddch(new_fruit.window, FRUIT_GLYPH);
    
    	*fruit = new_fruit;
    	return ERROR_NONE;
    }
    
    error_t fruit_update(fruit_t *fruit)
    {
    	wrefresh(fruit->window);
    	return ERROR_NONE;
    }
    
    void fruit_destroy(fruit_t *fruit)
    {
    	delwin(fruit->window);
    }
    
    
    bool player_eat(player_t *player, fruit_t *fruit)
    {
    	if (player->position[0].x == fruit->position.x &&
    	    player->position[0].y == fruit->position.y)
    	{
    		fruit_destroy(fruit);
    		fruit_create(fruit, player);
    		fruit_update(fruit);
    		return TRUE;
    	}
    
    	return FALSE;
    }
    
    
    error_t draw_border(WINDOW *window)
    {
    	if (box(window, 0, 0) == ERR)
    		return ERROR_DRAW_BORDER;
    
    	if (refresh() == ERR)
    		return ERROR_WINDOW_REFRESH;
    
    	return ERROR_NONE;
    }
    
    error_t init_ncurses(WINDOW *window)
    {
    	if (resize_term(PLAYFIELD_HEIGHT, PLAYFIELD_WIDTH) == ERR)
    		return ERROR_WINDOW_RESIZE;
    
    	if (noecho() == ERR)
    		return ERROR_NOECHO;
    
    	if (cbreak() == ERR)
    		return ERROR_SET_CBREAK;
    
    	if (curs_set(0) == ERR)
    		return ERROR_SET_CURSOR;
    
    	if (nodelay(window, TRUE) == ERR)
    		return ERROR_SET_NODELAY;
    
    	return ERROR_NONE;
    }
    
    bool handle_input(WINDOW *window, player_t *player)
    {
    	int ch;
    	if ((ch = getch()) == ERR)
    		return FALSE;
    
    	bool result = FALSE;
    
    	switch (ch) {
    	case KEY_MOVE_UP:
    		player->old_direction = player->direction;
    		player->direction = DIRECTION_UP;
    		break;
    	case KEY_MOVE_DOWN:
    		player->old_direction = player->direction;
    		player->direction = DIRECTION_DOWN;
    		break;
    	case KEY_MOVE_RIGHT:
    		player->old_direction = player->direction;
    		player->direction = DIRECTION_RIGHT;
    		break;
    	case KEY_MOVE_LEFT:
    		player->old_direction = player->direction;
    		player->direction = DIRECTION_LEFT;
    		break;
    	case KEY_QUIT:
    		result = TRUE;
    	}
    
    	while (getch() != ERR);
    
    	return result;
    }
    
    
    int main(void)
    {
    	WINDOW *window = initscr();
    	error_t error = init_ncurses(window);
    
    	if (error != ERROR_NONE) {
    		handle_error(error);
    		return EXIT_FAILURE;
    	}
    
    	error = draw_border(window);
    	if (error != ERROR_NONE) {
    		handle_error(error);
    		return EXIT_FAILURE;
    	}
    
    	player_t player;
    	error = player_create(&player);
    	if (error != ERROR_NONE) {
    		handle_error(error);
    		return EXIT_FAILURE;
    	}
    
    	srand((unsigned)time(NULL));
    	fruit_t fruit;
    	error = fruit_create(&fruit, &player);
    	if (error != ERROR_NONE) {
    		handle_error(error);
    		return EXIT_FAILURE;
    	}
    
    	fruit_update(&fruit);
    
    	bool quit = FALSE;
    	do {
    		quit = handle_input(window, &player);
    		error = player_move(&player);
    		if (error != ERROR_NONE) {
    			fruit_destroy(&fruit);
    			player_destroy(&player);
    			handle_error(error);
    			return EXIT_FAILURE;
    		}
    
    		if (player_eat(&player, &fruit)) {
    			player.growing = 10;
    			// todo: increase score and display
    		}
    
    		delay(player_is_moving_horizontally(&player) ? HDELAY : VDELAY);
    	} while (player_is_alive(&player) && !quit);
    
    	fruit_destroy(&fruit);
    	player_destroy(&player);
    	endwin();
    }
    


  • @DirkB Okay, also was genau ist Schrott?



  • @Swordfish Wow, wirklich vielen Dank! Ich verstehe allerdings nur wenig von der Syntax. Wo kann ich mehr darüber erfahren?



    • Mischen von deutschen und englischen Variablenamen
    • #defines für Konstanten (wenn es keinen Grund dafür gibt, sie als Präprozessorsymbole haben zu wollen).
    • Variablen nicht dort definiert, wo sie verwendet werden.
    • Falsche Signatur für main(). Laut Standard gibt es int main(void) und int main(int argc, char **argv)
    • int statt bool (siehe <stdbool.h> ab C99)
    • Alles Zeugs in ein Array schreiben anstatt die jeweiligen Änderungen auf den Bildschirm.
    • system("cls")
    • Einerseits write() und dann ein printf() nur um ein newline auszugeben.
    • Woher kommt getch() (In den eingebundenen Headern sollte es eigentlich nicht enthalten sein.)
    • Keine deiner Funktionen hat einen Rückgabetyp und nimmt eine unbestimmte Zahl an Parametern. (Ersteres ist seit ich glaube C90 nicht mehr erlaubt.)


  • @Swordfish Ah, Danke. Welcher Teil deines Codes ist dafür zuständig, das Array in das Terminal zu schreiben? Und warum brauchen Funktionen zwingend einen Rückgabetyp?



  • @daniel sagte in Schnellere Alternative zu printf, write und setchar:

    Welcher Teil deines Codes ist dafür zuständig, das Array in das Terminal zu schreiben?

    Ich habe kein solches Array wie Du in meinem Code.

    @daniel sagte in Schnellere Alternative zu printf, write und setchar:

    Und warum brauchen Funktionen zwingend einen Rückgabetyp?

    Weil es seit spätestens C89 so geschrieben steht.

    Function definitions (§3.7.1):

    [...] The return type of a function shall be void or an object type other than array.

    Davor wurde für Funktionen ohne Rückgabetyp int als Rückgabetyp angenommen.

    @daniel sagte in Schnellere Alternative zu printf, write und setchar:

    Ich verstehe allerdings nur wenig von der Syntax. Wo kann ich mehr darüber erfahren?

    Am besten währe wahrscheinlich, wenn Du Dir ein gutes Lehrbuch besorgst.



  • @Swordfish Habe ich schon. "C Programmieren von Anfang an" von Helmut Erlenkötter. Kannst du mir ein besseres empfehlen? Und wie speicherst du dann das Feld bzw wie gibst du den Spieler auf dem Terminal aus?



  • Ich habe ein "Fenster" an der Position des "Spielers":

    @Swordfish sagte in Schnellere Alternative zu printf, write und setchar:

    wclear(player->window);    // Fenster noch an der alten Position -> löschen
    wrefresh(player->window);  // ncurses mitteilen, daß das Fenster gezeichnet
                               // werden soll
    // Fenster an die aktuelle Position verschieben (mv ... move):
    mvwin(player->window, player->position.y, player->position.x);
    waddch(player->window, PLAYER_GLYPH);  // ein 'X' reinschreiben
    wrefresh(player->window);              // Auf den Bildschirm damit.
    

    Merken muss ich mir nur die Position. Ich muss auch nicht bei jeder Bewegung den ganzen Bildschirm löschen sondern nur die vorige Position des Spielers.

    @daniel sagte in Schnellere Alternative zu printf, write und setchar:

    Habe ich schon. "C Programmieren von Anfang an" von Helmut Erlenkötter. Kannst du mir ein besseres empfehlen?

    Der Erlenkötter ist auch eins der ersten gewesen, die mir eingefallen sind. Und da steht ernsthaft nicht drinnen, daß Funktionen einen Rückgabetyp haben und eine Parameterliste und eine Funktion die nichts zurückgibt und keine Parameter nimmt so ausschaut: void foo(void); ?