TicTacToe classic in C
malloc

I start with one of the most common ones. Instead of char *board = malloc(sizeof(char) * BOARD_SIZE) write char *board = malloc(sizeof(*board) * BOARD_SIZE). If you decide to change the type in the future, you don't have to change at more than one place. And besides, sizeof(char) is ALWAYS 1.

But the biggest problem is that you're not checking the return value. It should look like this:

void *init_board()
{
    char *board = malloc(sizeof(char) * BOARD_SIZE);
    if(!board) { 
        /* Handle error */ 
    } else {     
        for(int i = 0; i &lt; BOARD_SIZE; i++) {
            board[i] = ' ';
        }
    }
    return board;
}


Or like this:

void *init_board()
{
    char *board = malloc(sizeof(char) * BOARD_SIZE);
    if(board) {
        for(int i = 0; i &lt; BOARD_SIZE; i++) {
            board[i] = ' ';
        }
    }
    return board;
}


But if you choose the latter one, then you need to check the return value of init_board().

Another thing about the board variable. Why not make it into a 3x3 array instead? It's overkill to call malloc for a 9 byte array. I would do like this instead:

const int dim=3;

void init_board(char board[dim][dim]) 
{
    for(int i=0; i&lt;dim; i++)
        for(int j=0; j&lt;dim, j++)
            board[i][j]=' ';
}


And then in main()

char board[3][3];
init_board(board);


scanf

You're also not checking the return value of scanf. That should also always be done.

scanf(" %d %d", &amp;x, &amp;y);


should be

if(scanf(" %d %d", &amp;x, &amp;y) != 2) {
    /* Handle error */
} else {


But if you ask me, the best method, even though it takes a few more lines, is this:

const size_t buffer_size = 100;
char buffer[buffer_size];
if(!fgets(buffer, buffer_size, stdin)) {
    /* Handle error */
} else {
    if(sscanf(buffer, "%d %d", &amp;x, &amp;y) != 2) {
        /* Handle error */
    }
}


bool

No reason to define bool, true and false on your own. Just include stdbool.h.

const

A minor thing is that you should declare playerOneChar and playerTwoChar as const.

style

This is my personal preference, but I think you waste a lot of space with unnecessary braces. I would at least move the opening brace to then end of previous line, except for functions. Like this:

bool is_draw(char *board)
{
    for(int i = 0; i &lt; BOARD_SIZE; i++) {
        if(board[i] == ' ') {
            return false;
        }
    }
    return true;
}


or even

bool is_draw(char *board)
{
    for(int i = 0; i &lt; BOARD_SIZE; i++) 
        if(board[i] == ' ') 
            return false;
    return true;
}


Remember that readability also includes not having to scroll more than necessary. Putting the opening brace on the line before or sometimes even removing them completely barely makes it harder to read at all. If you ask me it's even easier. But it can save you a ton of lines, making more code visible at the same time. In the above example I would probably remove the braces for the if statement, but keep the braces for the for loop.

I usually go by the coding style guide for the Linux kernel, except that I prefer a tab size of 4 instead of 8.

Apart from these things, I think it looks pretty good. Nice work.