Search code examples
cgccsegmentation-faultnested-for-loop

Segfault in C (during middle of for loops)


I'm trying to practice C by writing a memory-type card game. The game is compiled by gcc on ARMv8. The user enters a number "users_N" in the argument line and a board of cards is created size: 2N x 2N.

The program runs just fine when the number is 1 or 2. But if it's 3 or bigger, I get a segmentation fault when trying to initialize the board. I thought this meant it was a stack overflow, but I increased the stack size to unlimited on my SSH and the problem was not resolved. I don't think it's a problem with pointers or trying to access an array out-of-bounds either, as it runs just fine until after 10 cards are added to the array.

The print statements are just to determine exactly when the segfault occurs.See image of for loop segfault

EDIT: to add more context... I know it's a bit messy, sorry!

int main(int argc, char *argv[]) {
    if (argc < 3){          //Checking user's command line input.
        printf("Missing argument. Exiting...    \n");
            return 0;
    }   
    users_N = atoi(argv[2]);
    srand(time(NULL));   //Initialize random number generator.
    int ***board = (int ***)malloc(2 * users_N * sizeof(int));  //Dynamic array to store the board values
    for (int i = 0; i < 2 * users_N; i++){
        board[i] = (int **)malloc(2 * users_N * sizeof(int)); /*Array of pointers (rows) filled with
                                                              an array (columns). */
        for (int j = 0; j < 2 * users_N; j++){
            board[i][j] = (int *)malloc(2 * sizeof(int)); //3rd dimension to show/hide cards.
        }
    }
    initialize(board);  
}

 /*
 * Function initialize sets up the board. It takes the 3D  board array. A card deck is created the
 * size of 2N^2, then shuffled and added to the board. The 3rd dimension is initialized
 * completely to 1, so all cards are shown. There is no return. 
 */
void initialize(int*** board){
    int* cards = (int *)malloc(2 * users_N * users_N * sizeof(int)); //Create an array of cards.
    printf("Cards created\n");

    for (int c = 0; c < (2 * users_N * users_N); c++){
        printf("card: %d\n",c);
        cards[c]=c;
    }
    int half = 0;
    
    while (half < 2){   //Divide up into 2 halves of the board, to repeat shuffle and card placement.
        shuffle(cards);
        int cardsNum = 0;
        for (int j = 0; j < users_N; j++){  //For each row in the current half:
            printf("\n row = %d ", j);
            for (int k = 0; k < (users_N * 2); k++){    //For each column:
                printf("col = %d ",k);


                board[j + (half * users_N)][k][0] = cards[cardsNum];  /* Assign appropriate
                                              card to each board 
                                              position. */
                printf("set to: %d ", board[j + (half * users_N)][k][0]);
                board[j + (half * users_N)][k][1] = 1;
                cardsNum++;
                printf("Card num: %d \n", cardsNum);
            }
        }
        half++;     //Moves to next half to repeat.
    }
}
/*
 * Function shuffle takes the array of cards as a parameter. It will then randomly mix array.
 * Numbers are not repeated and will not exceed 2N*N-1. No return values.
 */
void shuffle(int *cards){
    int j;
    for (int k = 0; k < (2 * users_N * users_N) - 2; k++){
        j = randomNum(k, (2 * users_N * users_N) - 1); //Assign a random number between k and 2N*N-1.
        swap(cards, k, j);
        printf("cards swapped: %d,%d\n",k,j);
    }   
}

/*
 * Function swap takes the array of cards, two index integers. The index integers indicate the positions of
 * the elements (cards) to switch. No return values.
 */
void swap(int *cards, int i, int j){
    int temp = cards[i];    //Value of position i stored in temp.
    cards[i] = cards[j];    //value of card j assigned to card i.
    cards[j] = temp;        //Value of temp assigned to card j.
}

Solution

  • Allocation of your board is wrong:

    int ***board = (int ***)malloc(2 * users_N * sizeof(int));
                                                 ^^^^^^^^^^^
                                                 wrong size
    
    
    for (int i = 0; i < 2 * users_N; i++){
        board[i] = (int **)malloc(2 * users_N * sizeof(int));
                                                 ^^^^^^^^^^^
                                                 wrong size
        ...
    
    }
    

    When you have board as int *** you don't want size of int during first allocation. You want size of int **. Like

    int ***board = malloc(2 * users_N * sizeof(int**));
    

    A better approach is to use the variable name - like:

    int ***board = malloc(2 * users_N * sizeof *board);
                                               ^^^^^^
                                              Better approach
                                              to get correct size
    

    The same applies to the next malloc