1

I am still new to programming and this site please be nice to me an unknowing fool. I am currently working on an assignment. We need to make a Binoxxo puzzle in C and when entering a value check if it's correct according to the rules. The rules are:

  1. There can't be more than two following 'x' or 'o'.
  2. Every row and column needs to have an equal amount of 'x' and 'o'.
  3. All rows and columns are unique.

The Binoxxo field is an array[10][10] filled with 'x', 'o' and ' '. I have a working solution for the second rule. However, I can't really figure out the other two. I'm currently getting more used to array's but here I guess I still don't really understand it.

This was my kind of approach to rule 1:

//There can't be more than two following 'x' or 'o'
for (i = j = 0; i < 10; i++) {
    for (j = 0; j < 10; j++) {
        if ((puzzle[i][j + 1] == val) && (puzzle[i][j - 1] == val)) x++;
        if ((puzzle[i][j + 1] == val) && (puzzle[i][j + 2] == val)) x++;
        if ((puzzle[i][j - 1] == val) && (puzzle[i][j - 2] == val)) x++;
        if ((puzzle[i + 1][j] == val) && (puzzle[i - 1][j] == val)) x++;
        if ((puzzle[i + 1][j] == val) && (puzzle[i + 2][j] == val)) x++;
        if ((puzzle[i - 1][j] == val) && (puzzle[i - 2][j] == val)) x++;

        if (x > 0)
            return false;
    }
}

This is a picture of the array for better understanding.

enter image description here

I was trying to cover the areas around one point to make sure that there would not be more than two x or o in a row. Val is entered in another function through the console and can be x or o. When I try to run this it first starts correctly and wenn I try to enter something I get the error 0xC0000005 Access Violation.

I read that this error can occur when there is an issue with a pointer. I noticed that I have a warning C6011 dereferencing NULL-Pointer, which leads me to this:

char** board() 
{
    int i, j;
    char** puzzle;
    char arrpuzzle[10][10] = {' ', ' ', 'o', 'x', ' ', ' ', ' ', ' ', ' ', 'o',
                            'x', ' ', ' ', 'x', ' ', ' ', ' ', ' ', ' ', ' ',
                            ' ', ' ', 'o', ' ', ' ', 'x', ' ', ' ', ' ', 'o',
                            ' ', ' ', ' ', ' ', 'o', ' ', ' ', ' ', 'o', ' ',
                            'o', ' ', ' ', 'x', ' ', ' ', ' ', 'x', ' ', ' ',
                            'o', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'o', ' ',
                            ' ', ' ', ' ', 'x', ' ', 'x', ' ', ' ', ' ', ' ',
                            ' ', 'o', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
                            ' ', 'o', ' ', 'o', ' ', 'x', 'x', ' ', ' ', ' ',
                            ' ', ' ', 'x', ' ', ' ', ' ', 'o', ' ', 'x', 'o' };

    puzzle = (char**)malloc(sizeof(char*) * 10);

    for (i = 0; i < 10; i++) {
        puzzle[i] = (char*)malloc(sizeof(char) * 10); // Warning here...
        for (j = 0; j < 10; j++) {
            puzzle[i][j] = arrpuzzle[i][j];           // And here
        }
    }
    return puzzle;
}

What did I do wrong? Is the issue due to malloc? What can I do to fix this? Can someone give me a few tips?

  • Your board function is fine. Although in C you probably shouldn't cast malloc, let the compiler infer the type. – Irelia Jan 19 '22 at 18:41
  • Please provide a [mre] which demonstrates your observation, or at least the situation in which you sometimes observe it. Make sure to provide the input which provokes it. – Yunnosch Jan 19 '22 at 18:46
  • 1
    You have some problems with the array indexing, like first time in the loop, when `i == 0` and `j == 0`, what does `puzzle[i][j - 1]` refer to? Likewise when i or j is at the upper end of the range, any +1 or +2 will make it fall off the cliff. – BoP Jan 19 '22 at 19:18

1 Answers1

1

In your code for the test for rule 1, neighboring cells are checked unconditionally, even if the cell being tested is on the edge (or corner).

In memory, what puzzle points to would look something like this:

...
      puzzle
------[X]------------------------------------------------------
--------\------------------------------------------------------
---------[A][B][C][D][E][F][G][H][I][J]------------------------
----------/--/--| ...                 \------------------------
---------/--/---[][][][][][][][][][]---\-----------------------
--------/--[][][][][][][][][][]---------[][][][][][][][][][]---
-------[][][][][][][][][][]------------------------------------
---------------------------------------------------------------
...

When puzzle[i][j+1] is accessed, if i==2 and j==3, then the 5th char after address C is accessed (C+4*sizeof(char)). But if j==9, then an undefined value will be accessed (the "11th" one - the char cell after the last one that was allocated). This would probably not cause an access violation, since it would probably be within the memory bounds for the process, but could cause a subtle and difficult to find error.

When puzzle[i+1][j] is accessed, however, and i==9, there is a different problem: The address cell after address J will be treated as an address (a char *), and dereferenced.

The value stored there could be:

  • Some value that happens to be an address within the memory bounds for the process, causing a subtle error.
  • 0x0, causing a NULL dereference.
  • Some value outside of the memory bounds for the process, causing an access violation.

The problems are similar for the other edges ([i-1] and [j-1]).

mrbrobro
  • 26
  • 3
  • Oh yeah, that makes a lot of sense. I didn't really consider that... Thanks to your insight I tried around a bit again and it seems I found a working solution. But now I'm wondering why is this working. if (puzzle[row][column + 1] == val) x++; I'm not iterating it anymore. I'm only giving it the position in the array and the value. But if it's like you said for example 1,9 there is no error. I mean shouldn't there be an error again? Or is it now just like a random value that's luckily not interfering? – YukiKinimoto Jan 19 '22 at 21:00
  • 1
    Right: if a *column* past either edge is accessed, then it is likely to still be in accessible memory for the process, but the value stored there has not been controlled by the program. This will likely mostly "work", but is a subtle bug. The value stored there could happen to be equal to `val`, causing unexpected behavior. – mrbrobro Jan 20 '22 at 18:37