People, I have a matrix that moves from left to right and only the characters of the array that are inside the circle appear (distance = sqrt(pow((x - CENTER_X) / ASPECT_RATIO, 2) + pow(y - CENTER_Y, 2)) ;
), when the 'mapWorld' matrix reaches the end, the frame starts again, but with two blank columns, and some characters that I can't understand.
I thought that when the offset reaches the end of the map, the value of x
was negative in the mapWorld[y][x - offset]
expression. causing an invalid index in the mapWorld array to be accessed, resulting in blank characters.
Then I then added a check to ensure that x - offset
is a non-negative value.
if (mapWorld[y][(x - offset + MAP_WIDTH) % MAP_WIDTH] == '-') {
// ...
} else if (mapWorld[y][(x - offset + MAP_WIDTH) % MAP_WIDTH] == '+') {
// ...
}
It has improved a lot but there is still a blank column.
I would like to better clarify the words but I don't really know what could be happening. Please see the GIF.
#include <stdio.h>
#include <math.h>
#include <curses.h>
#define MAP_HEIGHT 34
#define MAP_WIDTH 141
#define ASPECT_RATIO 2
#define RADIUS 20
#define CENTER_X (MAP_WIDTH / 2.0)
#define CENTER_Y (MAP_HEIGHT / 2.0)
const char *mapWorld [MAP_HEIGHT] = {
// Map omitted for brevity
};
int clip(int v, int max) {
return v < max ? v : max - 1;
}
int main() {
initscr();
start_color();
cbreak();
noecho();
curs_set(0);
init_pair(1, COLOR_BLUE, COLOR_BLACK);
init_pair(2, COLOR_GREEN, COLOR_BLACK);
while (1) {
//Right to left shift loop
for (int offset = 0; offset < MAP_WIDTH; offset++) {
erase();
//Loop through all array coordinates
for (int y = 0; y < MAP_HEIGHT; y++) {
for (int x = 0; x < MAP_WIDTH; x++) {
float distance = sqrt(pow((x - CENTER_X) / ASPECT_RATIO, 2) + pow(y - CENTER_Y, 2));
//Checks if the point is inside the circle
if (distance <= RADIUS) {
//Defines the color for the characters '-' and '+'
if (mapWorld[y][x - offset] == '-') {
attron(COLOR_PAIR(1));
} else if (mapWorld[y][x - offset] == '+') {
attron(COLOR_PAIR(2));
}
//Print the corresponding character
mvprintw(y, x, "%c", mapWorld[y][x - offset]);
//Disable color
attroff(COLOR_PAIR(1));
attroff(COLOR_PAIR(2));
}
}
}
refresh();
napms(50);
}
}
endwin();
return 0;
}
Map
const char * mapWorld[MAP_HEIGHT] = {
"--------------------------------------------------------------------------------------------------------------------------------------------",
"--------------------------------------------------------------------------------------------------------------------------------------------",
"----------------------------------+++++++--+++++++++++++++++++------------------------------------------------------------------------------",
"----------------------+-+++++--+-+-+++++--------++++++++++++++-----------------------------+----------++++++++++++++--+-----++--------------",
"------++++++++++++++++++++++++++++++++--++++-----++++++++++-----------------++++++++-----+++++++++++++++++++++++++++++++++++++++++++++++++++",
"------+++++++++++++++++++++++++++++-----++++------++++-------------------++++-+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-",
"--------++-------+++++++++++++++++------++++++----------------------+----++++--++++++++++++++++++++++++++++++++++++++++++++++------++-------",
"--------------------++++++++++++++++++-+++++++++--------------------++--++++++++++++++++++++++++++++++++++++++++++++++++++++-------+--------",
"----------------------+++++++++++++++++++++++------------------------+++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------",
"----------------------+++++++++++++++++++++------------------------++++---+-+++++----++++-+++++++++++++++++++++++++++++++-------------------",
"----------------------+++++++++++++++++++--------------------------+++--------+--++++++++--+++++++++++++++++++++++++---+----+---------------",
"-------------------------++++++++++++++----------------------------+++++++++--+----++++++++++++++++++++++++++++++++++-----------------------",
"--------------------------++++++------+--------------------------++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------",
"-----------------------------+++--------------------------------++++++++++++++++++++-++++++++----+++++++++++++++++--------------------------",
"-------------------------------++-++----------------------------+++++++++++++++++++++-+++++-------++++-----+++++----------------------------",
"------------------------------------++--------------------------+++++++++++++++++++++++++----------++-------+-++----------------------------",
"----------------------------------------+++++++------------------++++++++++++++++++++++++---------------------------------------------------",
"---------------------------------------+++++++++++------------------------++++++++++++++---------------------+---+++------------------------",
"---------------------------------------++++++++++++++++-------------------++++++++++++-----------------------++--++--------++---------------",
"---------------------------------------+++++++++++++++++-------------------++++++++++---------------------------------------++--------------",
"----------------------------------------+++++++++++++++--------------------+++++++++++----------------------------------+++--+--------------",
"------------------------------------------+++++++++++++--------------------+++++++++---++----------------------------++++++++++-------------",
"-------------------------------------------+++++++++------------------------++++++++---+--------------------------+++++++++++++++-----------",
"------------------------------------------+++++++++-------------------------++++++--------------------------------+++++++++++++++-----------",
"------------------------------------------+++++++----------------------------+++-----------------------------------+++----+++++++-----------",
"------------------------------------------++++--------------------------------------------------------------------------------+-------------",
"-----------------------------------------++++-----------------------------------------------------------------------------------------------",
"-----------------------------------------+++------------------------------------------------------------------------------------------------",
"--------------------------------------------------------------------------------------------------------------------------------------------",
"--------------------------------------------------------------------------------------------------------------------------------------------",
"--------------------------------------------------------------------------------------------------------------------------------------------",
"--------------------------------------------++-------------------------------------+-++++++++++++--+++++++++++++++++++++++++++++++++--------",
"--------------------+++++++---++++++++++++++++-----------------+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------",
"----------+++++++++++++++++++++++++++++++----------+----+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------"
};
Adding a little bit of debug to this
if (distance <= RADIUS) {
if (x - offset < 0)
fprintf(stderr, "d%f o%d y%d x%d c%d\n", distance, offset, y, x, x - offset);
/* ... */
and compiling (clang) with -fsanitize=address
produces the following diagnostics:
d19.976549 o32 y14 x31 c-1
=================================================================
==951==ERROR: AddressSanitizer: global-buffer-overflow on address 0x0001083e123f at pc 0x0001083e0382 bp 0x7ffee7821950 sp 0x7ffee7821948
READ of size 1 at 0x0001083e123f thread T0
#0 0x1083e0381 in main+0x2a1 (a.out:x86_64+0x100002381)
#1 0x7fff73177cc8 in start+0x0 (libdyld.dylib:x86_64+0x1acc8)
0x0001083e123f is located 1 bytes to the left of global variable '<string literal>' defined in 'vis.c:27:9' (0x1083e1240) of size 141
'<string literal>' is ascii string '-------------------------------++-++----------------------------+++++++++++++++++++++-+++++-------++++-----+++++----------------------------'
0x0001083e123f is located 50 bytes to the right of global variable '<string literal>' defined in 'vis.c:26:9' (0x1083e1180) of size 141
'<string literal>' is ascii string '-----------------------------+++--------------------------------++++++++++++++++++++-++++++++----+++++++++++++++++--------------------------'
SUMMARY: AddressSanitizer: global-buffer-overflow (a.out:x86_64+0x100002381) in main+0x2a1
Shadow bytes around the buggy address:
0x10002107c1f0: 00 00 00 00 00 00 00 00 00 05 f9 f9 f9 f9 f9 f9
0x10002107c200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10002107c210: 00 05 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00
0x10002107c220: 00 00 00 00 00 00 00 00 00 05 f9 f9 f9 f9 f9 f9
0x10002107c230: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10002107c240: 00 05 f9 f9 f9 f9 f9[f9]00 00 00 00 00 00 00 00
0x10002107c250: 00 00 00 00 00 00 00 00 00 05 f9 f9 f9 f9 f9 f9
0x10002107c260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x10002107c270: 00 05 f9 f9 f9 f9 f9 f9 00 00 00 00 00 00 00 00
0x10002107c280: 00 00 00 00 00 00 00 00 00 05 f9 f9 f9 f9 f9 f9
0x10002107c290: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==951==ABORTING
From this we can see that as distance
approaches RADIUS
, a negative index is produced by x - offset
, resulting in mapWorld[14][-1]
, and subsequently Undefined Behaviour occurs.
As you have seen, you must avoid creating a negative index, and your solution of
mapWorld[y][(x - offset + MAP_WIDTH) % MAP_WIDTH]
seemingly works well.
The last thing to note is your strings have a size of 141
, but a length of 140
. You index the null-terminating byte creating a blank column. Change
#define MAP_WIDTH 141
to
#define MAP_WIDTH 140