C Array check row and column. Issue with pointer(dereferencing NULL-Pointer warning)

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?


Solution 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]).