I have some code performing relatively simple operations
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <curses.h>
char map[3600] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
};
int getblock(int x,int y)
{
return(map[x + 80 * y]);
}
int colread(char chr)
{
switch(chr)
{
case 'k':
return(COLOR_BLACK);
break;
case 'r':
return(COLOR_RED);
break;
case 'g':
return(COLOR_GREEN);
break;
case 'y':
return(COLOR_YELLOW);
break;
case 'b':
return(COLOR_BLUE);
break;
case 'm':
return(COLOR_MAGENTA);
break;
case 'c':
return(COLOR_MAGENTA);
break;
case 'w':
return(COLOR_WHITE);
break;
}
}
void colinit()
{
init_pair(0,COLOR_BLACK, COLOR_BLACK);
init_pair(1,COLOR_BLACK,COLOR_WHITE);
init_pair(3,COLOR_BLACK,COLOR_YELLOW);
init_pair(26,COLOR_BLUE,COLOR_BLUE);
}
void colman(char bg,char fg)
{
int bgint = colread(bg);
int fgint = colread(fg);
if(bgint == 0 && fgint == 1)
{
attrset(0);
attron(A_BOLD);
}
else
{
attron(COLOR_PAIR(bgint*8+fgint));
}
}
void pixrender(int x,int y){/*oh god please no*/
addstr("rendered pixel");refresh();
char coord[3];
sprintf(coord,"%d",x);
addstr("(");
addstr(coord);
addstr(",");
sprintf(coord,"%d",y);
addstr(coord);
addstr(")");
/*
b blue
r red
w white
k black
blue for blocks, white for spikes
*/
char fku = 'f';
char spritesheet[144] = {
// 0 1 2 3 4 5 6 7 8 9 0 1
/*empty */' ','x','n','v','d','b',' ',' ','-','_','[',']',
/*block */'*','X',fku,'V','d','b',' ',' ',fku,fku,'[',']',
/*spup */'^','A','M','N','&','&',' ',' ','A',fku,'P','9',
/*spdwn */'Y',fku,'<','<','<','Z',' ',' ',fku,fku,fku,fku,
/*splft */'9','9','<','<','<','Z',' ',' ','<','<','<',fku,
/*sprht */'P','P','>','>','Z','>',' ',' ','>','>',fku,'>',
/*lava */' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
/*ice */' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
/*owup */'~','~',fku,'T','Z','Z',' ',' ','~',fku,'[',']',
/*owdown*/'-','x','7','v','z','z',' ',' ','-','=','[',']',
/*owleft*/'[','[','9','Y','<','<',' ',' ','[','L','[','|',
/*owrht */']','h','R','j','>','>',' ',' ','[',']','|',']'
};
char bgsheet[144] = {
// 0 1 2 3 4 5 6 7 8 9 0 1
/*empty */'k','b','k','k','k','k','k','k','k','k','k','k',
/*block */'b','b',fku,'k','k','k','k','k',fku,fku,'k','k',
/*spup */'k','k','k','k','k','k','k','k','k','k','k','k',
/*spdwn */'k',fku,'k','k','k','k','k','k',fku,fku,fku,fku,
/*splft */'k','k','k','k','k','k','k','k','k','k','k',fku,
/*sprht */'k','k','k','k','k','k','k','k','k','k',fku,'k',
/*lava */'k','k','k','k','k','k','k','k','k','k','k','k',
/*ice */'k','k','k','k','k','k','k','k','k','k','k','k',
/*owup */'k','k',fku,'k','k','k','k','k','k',fku,'k','k',
/*owdown*/'k','k','k','k','k','k','k','k','k','k','k','k',
/*owleft*/'k','k','k','k','k','k','k','k','k','k','k','k',
/*owrht */'k','k','k','k','k','k','k','k','k','k','k','k',
};
char fgsheet[144] = {
// 0 1 2 3 4 5 6 7 8 9 0 1
/*empty */'k','b','w','w','w','w',' ',' ','y','y','y','y',
/*block */'b','b',fku,'w','w','w',' ',' ',fku,fku,'y','y',
/*spup */'w','w','w','w','w','w',' ',' ','y',fku,'y','y',
/*spdwn */'w',fku,'w','w','w','w',' ',' ',fku,fku,fku,fku,
/*splft */'w','w','w','w','w','w',' ',' ','y','y','y',fku,
/*sprht */'w','w','w','w','w','w',' ',' ','y','y',fku,'y',
/*lava */' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
/*ice */' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
/*owup */'y','y',fku,'y','y','y',' ',' ','y',fku,'y','y',
/*owdown*/'y','y','y','y','y','y',' ',' ','-','y','y','y',
/*owleft*/'y','[','y','Y','y','y',' ',' ','y','y','y','y',
/*owrht */'y','h','y','y','y','y',' ',' ','y','y','y','y'
};
//segfault before here
int pos = getblock(x,2*y) + 12 * getblock(x,2*y+1);
colman(bgsheet[pos],fgsheet[pos]);
char cstr[2] = "";
cstr[0] = spritesheet[pos];
attron(A_BOLD);//why does this have to be here
addstr(cstr);
}
void render()
{
int y = 24;
int x;
while (y >= 0)
{
x = 0;
while(x < 80)
{
pixrender(x,y);
x++;
}
if (y > 0)
{
addstr("n");
}
y-=1;
}
clear();
refresh();
}
void game()
{
colinit();
while (true)
{
render();
}
}
int main()
{
initscr();
start_color();
attron(A_BOLD);
game();
endwin();
return(0);
}
and it works…but only in gdb, when running the same a.out outside of gdb, it crashes due to a segfault, does anyone know what sort of interaction could cause this (or if its some specific code related issue), the most relevant thing I could find was https://www.reddit.com/r/cprogramming/comments/18k3o01/issue_with_segfault_when_running_code_outside_of/ but that it doesnt seem like there would be any latent memory issues, there also isnt any database stuff so there shouldnt be anything with fread, could it be an undefined behaviour of some sort?
15
-
Your program segfaults in
getblock (x=48, y=49)
onreturn(map[x + 80 * y]);
akareturn map[3968];
as you definedchar map[3600] = {...}
. It’s undefined behavior to access an array out of bounds. I don’t have any intuition as why it happens to work when your program is running under the control of gdb.It’s called from
pixrender(x=48, y=24)
which doesint pos = getblock(x,2*y) + 12 * getblock(x,2*y+1)
. I don’t know what your program is supposed to do in order to propose a fix.valgrind is angry (there are also a few leaks):
==1804063== Invalid read of size 1 ==1804063== at 0x109210: getblock (1.c:35) ==1804063== by 0x10A019: pixrender (1.c:138) ==1804063== by 0x10A0D5: render (1.c:151) ==1804063== by 0x10A141: game (1.c:165) ==1804063== by 0x10A174: main (1.c:172) ==1804063== Address 0x10e000 is not stack'd, malloc'd or (recently) free'd
-
char map[3600]
only stores 3600 bits so you could easily pack that into auint8_t[3600/8]
as you only access it viagetblock()
. 2 calls tomemset()
would be easier on the eyes. You also could run-length encode it. Or as it’s read-only get rid of entirely:int getblock(int x, int y) { assert(x >= 0 && x < 80); assert(y >= 0 && y < 45); return x + 80 * y >= 1600; }
People hate asserts here as you have the option of turning them off. I don’t turn them off and use them liberally for pre- and post-conditions. Use error checks if you have issues with assert. With the asserts you code now fails with:
rendered pixela.out: 1.c:9: getblock: Assertion `y >= 0 && y < 45' failed. Aborted
-
Prefer symbolic constant instead of magic values (3600, 80, 24, 144).
3600
appears to be80 * (40 + 5)
or perhaps80 * (2 * 24 + 1)
but I don’t know why. -
Prefer to initialize arrays instead of separate assignment.
char cstr[] = {spritesheet[pos], 0};
-
Prefer to mark read-only variables
const
. It allows to more easily refactor code like I showed withmap
above. -
Prefer letting the compiler deduce the size of arrays.
char spritesheet[] = { // ... };
-
Avoid global variables. It makes testing harder than necessary.
-
Consider a
struct xy { int x, int y }
as you use or pass them as arguments. -
Consider an
enum
for thechr
so the compiler can check you have a case for every value used. -
Prefer
for
towhile
loop for iteration. They are purpose built for it. Inrender()
:for(int y = 24; y >= 0; y--) { for(int x = 0; x < 80; x++) pixrender(x, y); // ... }
-
Minimize scope of variables. See previous.
0