Search code examples
cfunctionpointerswhile-looppass-by-reference

"While loop" (contains pointer to array passed into a function) works only once


I am writing some code in C. Inside the main function there is a while loop with a function call to printboard taking a pointer to array board. Inside the function I have got a printf, that prints 3 characters stored inside the board" array. HoWever inside the function, I have got just a pointer, so I am doing pointer arithmetics. When the while loop first executes, it works just fine. However, when it executes again, it does not work. It does not print the letters. Why?

#include <stdio.h>
#include <stdbool.h>

void printboard(char *boardp) {
    printf("  %c |  %c |  %c ", *(boardp), *(boardp + 1), *(boardp + 2));
}

int main() {

    char board[3];
    board[0] = 'a';
    board[1] = 'b';
    board[2] = 'c';

    bool playgame = true;

    while (playgame == true) {
        printboard(board);
        board[0] = 'a';
        board[1] = 'b';
        board[2] = 'c';
        scanf("%d", &playgame);
    }
    return 0;
}

Solution

  • You pass the address of a bool to scanf() for conversion specifier %d which expects a pointer to int. This has undefined behavior. A likely explanation is scanf() overwrites the contents of the array board when writing an int to the destination address, causing memory corruption.

    Define playgame as an int.

    Here is a modified version:

    #include <stdio.h>
    
    void printboard(const char *board) {
        printf("  %c |  %c |  %c \n", board[0], board[1], board[2]);
    }
    
    int main(void) {
        char board[3] = { 'a', 'b', 'c' };
    
        for (;;) {
            int playgame;
    
            printboard(board);
            board[0] = 'a';
            board[1] = 'b';
            board[2] = 'c';
            // read an int from the user, check for conversion success
            // break from the loop if conversion failure or value entered is 0
            if (scanf("%d", &playgame) != 1 || !playgame)
                break;
        }
        return 0;
    }