Connect-N Board Game, crashing when Width is >> Height - c

I'm in the process of coding a Connect-N board game, and I'm almost finished and have gone through troubleshooting. My problem is now after changing some stuff my game crashes when the computer plays its move if the Width is too much greater than the height. There are two functions involved here, so I will paste them both.
Board
*AllocateBoard(int columns, int rows)
{
int **array= malloc(sizeof(int *) *columns);
int r = 0;
for ( r = 0; r < columns; ++r)
{
array[r] = malloc(sizeof(int) * rows);
}
int j = columns - 1;
int k = rows - 1;
int m = 0;
int n = 0;
for ( m = 0; m < j; ++m)
{
for ( n = 0; n < k; ++n)
{
array[m][n] = 0;
}
}
Board *board = malloc(sizeof(Board));
board->columns = columns;
board->rows = rows;
board->spaces = array;
return board;
}
This first function allocates the board to be a matrix Width * Height that the user passes in via the command line. It then initializes every space on the board to be zero, and then stores the columns, rows, and spaces into a Board structure that I've created. It then returns the board.
int
computerMakeMove(Board *board)
{ int RandIndex = 0;
int **spaces = board->spaces;
int columns = board->columns;
int *arrayoflegalmoves = malloc(sizeof(int) * (columns));
int columncheck = 0;
int legalmoveindex = 0;
while (columncheck <= columns - 1)
{
if (spaces[columncheck][0] == 0)
{
arrayoflegalmoves[legalmoveindex] = columncheck;
++legalmoveindex;
++columncheck;
}
else
{
++columncheck;
}
arrayoflegalmoves = realloc(arrayoflegalmoves, (legalmoveindex) * sizeof(int));
}
if (legalmoveindex == 1)
{
return arrayoflegalmoves[0];
}
else
{
RandIndex = rand() % (legalmoveindex);
return arrayoflegalmoves[RandIndex];
}
}
This second function is designed to make the computer randomly pick a column on the board. It does this by checking the value of the top row in each column. If there is a zero there, it will store this value in an array of legal moves, and then it increments the legalmoveindex. If there isn't, it skips the column and checks the next. It ends when it gets finished checking the final column. If there is only one legal move, it will play it. If there are more, it will select a random index from the array of legal moves (I run srand in the main) and then return that value. It will only ever attempt to play on a legal board, so that's not the problem. I am pretty confident the problem occurs in this function, however, as I call the functions as follows
printf("Taking the computers move.\n");
{printf("Taking computer's move.");
computermove = computerMakeMove(playerboard);
printf("Computer's move successfully taken.\n");
playerboard = MakeMove(playerboard, computermove, player);
printf("Computer's board piece successfully played.\n");
system("clear");
displayBoard(playerboard);
...;
}
and it prints
Aborted (core dumped)
immediately after it prints
"Taking computer's move."
Once again, my question is: why is my program crashing if the width is larger than the height when the computer plays?
Thanks.
Edit: I found the solution and I am stupid.
I realloc'd during the while loop.
The realloc should be the first thing outside of the while loop.

The answer for any future programmers who may have this problem:
Notice the
while (columncheck <= columns - 1)
{
if (spaces[columncheck][0] == 0)
{
arrayoflegalmoves[legalmoveindex] = columncheck;
++legalmoveindex;
++columncheck;
}
else
{
++columncheck;
}
arrayoflegalmoves = realloc(arrayoflegalmoves, (legalmoveindex) * sizeof(int));
}
has a realloc inside of it. The realloc should be moved to immediately outside of it, like so
while (columncheck <= columns - 1)
{
if (spaces[columncheck][0] == 0)
{
arrayoflegalmoves[legalmoveindex] = columncheck;
++legalmoveindex;
++columncheck;
}
else
{
++columncheck;
}
}
arrayoflegalmoves = realloc(arrayoflegalmoves, (legalmoveindex) * sizeof(int));

it is unusual to have the columns be the first index in an array.
having the first index of an array be columns leads to confusion
// suggest using camel case for all variable names, for readability
Board *AllocateBoard(int columns, int rows)
{
int **array= malloc(sizeof(int *) *columns); // add check that malloc successful
int r = 0;
for ( r = 0; r < columns; ++r)
{
array[r] = malloc(sizeof(int) * rows); // <-- add: check that malloc successful
}
int j = columns - 1; // this results in last column not initialized
int k = rows - 1; // this results in last row of each column not initialized
int m = 0; // column loop counter
int n = 0; // row loop counter
for ( m = 0; m < j; ++m)
{
for ( n = 0; n < k; ++n)
{
array[m][n] = 0;
}
}
Board *board = malloc(sizeof(Board)); // <-- add: check if malloc successful
board->columns = columns;
board->rows = rows;
board->spaces = array;
return board;
} // end function: AllocateBoard
// why is this only looking at the first row of each column?
int computerMakeMove(Board *board)
{
int RandIndex = 0;
int **spaces = board->spaces;
int columns = board->columns;
int *arrayoflegalmoves = malloc(sizeof(int) * (columns)); // <-- add check that malloc successful
int columncheck = 0;
int legalmoveindex = 0;
while (columncheck <= columns - 1)// should be: for(; columncheck < columns; columncheck++ )
{
if (spaces[columncheck][0] == 0)
{ // then first row of column is zero
arrayoflegalmoves[legalmoveindex] = columncheck;
++legalmoveindex;
++columncheck; // <-- remove this line
}
else // remove this 'else' code block
{
++columncheck;
} // end if
arrayoflegalmoves = realloc(arrayoflegalmoves, (legalmoveindex) * sizeof(int));
// <-- 1) use temp int*, in case realloc fails
// <-- 2) if realloc successful, update arrayoflegalmoves
// <-- 3) the code is not checking each row of each column,
// so the original malloc is more than plenty
// so why bother to realloc
// <-- 4) if legalmoveindex is 0 then realloc returns NULL
} // end while
// in following, what about when zero moves found? probably should return NULL
if (legalmoveindex == 1)
{ // only one column[row0] found to contain 0
return arrayoflegalmoves[0];
}
else
{
RandIndex = rand() % (legalmoveindex);
return arrayoflegalmoves[RandIndex]; // if zero moves found, this returns a
// de-reference to address 0
// which would result in a seg fault event
} // end if
} // end function: computerMakeMove

Related

Cunit test invalid read/write of size8

Invalid read and write of size 8 happening in modify_tab_size().
what am I doing wrong? Ive tried almost everything, I dont understand it.
// Function being tested.
int erase_repeated(int *nb_words, char **words) {
for (int i = 0; i < *nb_words; ++i) {
if (words[i] != 0) {
for (int b = 0; b < *nb_words; ++b) {
if (strcmp(words[i], words[b]) == 0 && b != i)
modify_tab_size(&b, nb_words, words);
}
}
}
return *nb_mots;
}
void modify_tab_size(int *b, int *nb_words_update, char **words) {
free(words[*b]);
for (int k = *b; k < *nb_words_update; k++) {
words[k] = words[k + 1]; <--------------------------read error
words[*nb_words_update + 1] = 0; <--------------------------write error
}
(*nb_words_update)--;
(*b)--;
}
The problem is k+1 and *nb_words_update + 1 can walk off the array, and it is. Add printf("k:%d, k+1:%d, *nb_words_update + 1: %d\n", k, k+1, *nb_words_update + 1); into the loop to see.
k:1, k+1:2, *nb_words_update + 1: 4
k:2, k+1:3, *nb_words_update + 1: 4
You've only allocated three slots, 3 and 4 walk off the end of the array.
Since nb_words_update starts as the length of the array, words[*nb_words_update + 1] = 0; is always going to be too large. words[*nb_words_update] = 0; is also too large.
What you seem to be trying to do is deleting an element from an array by shifting everything after it to the left.
void delete_element(char **words, int *b, int *size) {
// Free the string to be deleted.
free(words[*b]);
// Only go up to the second to last element to avoid walking off the array.
for (int i = *b; i < *size-1; i++) {
// Shift everything to the left.
words[i] = words[i+1];
}
// Null out the last element.
// Don't use 0 for NULL, it's confusing.
words[*size-1] = NULL;
// Decrement the size of the array.
(*size)--;
// Redo the check with the newly shifted element.
(*b)--;
}
This sort of thing is better done with a linked list.
Note that your code has a bug. The result is an array of two elements, but one of them is blank. In addition to the return value of erase_repeated, also test its side effect which is to modify words. Test that words contains what you think it does.

How to find the minimum number of coins needed for a given target amount(different from existing ones)

This is a classic question, where a list of coin amounts are given in coins[], len = length of coins[] array, and we try to find minimum amount of coins needed to get the target.
The coins array is sorted in ascending order
NOTE: I am trying to optimize the efficiency. Obviously I can run a for loop through the coins array and add the target%coins[i] together, but this will be erroneous when I have for example coins[] = {1,3,4} and target = 6, the for loop method would give 3, which is 1,1,4, but the optimal solution is 2, which is 3,3.
I haven't learned matrices and multi-dimensional array yet, are there ways to do this problem without them? I wrote a function, but it seems to be running in an infinity loop.
int find_min(const int coins[], int len, int target) {
int i;
int min = target;
int curr;
for (i = 0; i < len; i++) {
if (target == 0) {
return 0;
}
if (coins[i] <= target) {
curr = 1 + find_min(coins, len, target - coins[i]);
if (curr < min) {
min = curr;
}
}
}
return min;
}
I can suggest you this reading,
https://www.geeksforgeeks.org/generate-a-combination-of-minimum-coins-that-results-to-a-given-value/
the only thing is that there is no C version of the code, but if really need it you can do the porting by yourself.
Since no one gives a good answer, and that I figured it out myself. I might as well post an answer.
I add an array called lp, which is initialized in main,
int lp[4096];
int i;
for (i = 0; i <= COINS_MAX_TARGET; i++) {
lp[i] = -1;
}
every index of lp is equal to -1.
int find_min(int tar, const int coins[], int len, int lp[])
{
// Base case
if (tar == 0) {
lp[0] = 0;
return 0;
}
if (lp[tar] != -1) {
return lp[tar];
}
// Initialize result
int result = COINS_MAX_TARGET;
// Try every coin that is smaller than tar
for (int i = 0; i < len; i++) {
if (coins[i] <= tar) {
int x = find_min(tar - coins[i], coins, len, lp);
if (x != COINS_MAX_TARGET)
result = ((result > (1 + x)) ? (1+x) : result);
}
}
lp[tar] = result;
return result;
}

Conway's game of life with C. Command terminated when calling function to generate new generation and update "board"

I'm writing Conway's game of life in C. I understand that the rules of the game are:
Any live cell with 2 or 3 live neighbours survives.
Any dead cell with 3 live neighbours becomes a live cell.
All other live cells die in the next generation.
'#' symbolises a live cell and '.' symbolises a dead one
The code to my function to generate and update the universe "board" for every generation is written below. It takes in the universe (A 2d array which I dynamically allocated memory for in the main function), the no of rows and no of columns of the 2d array. All other functions (such as alive_neighbour) are correct and the program runs smoothly to the point this function is called. Afterwhich the terminal just prints "command terminated". I can't seem to figure out which part of the function causes the program to crash. Help will be greatly appreciated. Thank you!
void next_generation(char **universe, long row, long column)
{
for (long i = 1; i <= (row - 1); i += 1) {
for (long j = 1; j <= (column - 1); j += 1) {
//a = no of alive neighbours surrounding universe[i][j]
long a = alive_neighbour(universe, i, j);
if (universe[i][j] == '#') {
if (a == 2 || a == 3) {
universe[i][j] = '#';
}
}
else if (universe[i][j] == '.') {
if (a == 3) {
universe[i][j] = '#';
}
}
else {
universe[i][j] = '.';
}
}
}
}
long alive_neighbour(char **universe, long row, long column)
{
long count = 0;
for (long i = -1; i <= 1; i += 1) {
for (long j = -1; j <= 1; j += 1) {
if (universe[row + i][column + j] == '#') {
count += 1;
}
}
}
if (universe[row][column] == '#') {
count -= 1;
}
return count;
}
How I declared universe in the main function:
universe = (char **)malloc((size_t) row * sizeof(char *));
for (long i = 0; i < row; i += 1) {
universe[i] = (char *)malloc((size_t) column * sizeof(char));
}

i'm getting unexpected behavior using realloc

for some reason, every 2-3 times that i run the program i get unexpected values, such as -842150451 -842150451, and every other time i get the correct result: 7 9.
i'm a student, so sorry if the code is a little academic.
please see code:
int mat[ROW][COL] = {
{2,-3,5,1,2},
{2,4,7,7,1},
{1,9,7,3,0}
};
int row, col, tempRow = 0, tempCol = 0, indexCol, indexRow = 0, loopTempRow, flag = 0, cnt = 1, loopTempCol = 0;
int* arr;
int* ptrArr;
arr = (int*)malloc(cnt * sizeof(int)); // mallocating an array with size 1 * int
ptrArr = arr;
if (arr == NULL) // checking allocation done succefully
{
printf("Error Allocating Memory\n");
exit(1);
}
for (row = 0; row < ROW; row++) // starting from row 0 we will wheck col 0,1,2,3,4 for the highest val.
{
flag = 1;
tempCol = 0;
for (col = 0; col < COL; col++)
{
if (mat[row][col] > tempCol)
{
tempCol = mat[row][col];
indexCol = col;
}
}
for (loopTempRow = 0; loopTempRow < ROW; loopTempRow++) // then we will check the row of the col index
{
if (mat[loopTempRow][indexCol] > tempCol)
{
flag = 0;
break;
}
}
if (flag == 1)
{
cnt++; // this is a counter for realloctaing.
arr = realloc(arr, (cnt - 1) * sizeof(int)); // every iteration the arr is increasing by 1
printf("mat[%d][%d] = %d\n", row, indexCol, mat[row][indexCol]);
*ptrArr = mat[row][indexCol]; // inserting the element into the arr
ptrArr++;
}
}
if (cnt == 1) // if the cnt = 1, it means that flag didn't became 1. which meant no value inserted to the arr
arr = NULL;
for (ptrArr = arr; ptrArr - arr < cnt - 1; ptrArr++) // print arr
printf("%d\t", *ptrArr);
free(arr);
}
i suspect that the problem is with the realloc block:
if (flag == 1)
{
cnt++; // this is a counter for realloctaing.
arr = realloc(arr, (cnt - 1) * sizeof(int)); // every iteration the arr is increasing by 1
printf("mat[%d][%d] = %d\n", row, indexCol, mat[row][indexCol]);
*ptrArr = mat[row][indexCol]; // inserting the element into the arr
ptrArr++;
}
}
You initially allocate an array with room for one integer, but you never set that integer value. I guess it is because allocating a block of 0 bytes returned NULL which you assume is an error.
Another confusing code fragment is
cnt++; // this is a counter for realloctaing.
arr = realloc(arr, (cnt - 1) * sizeof(int)); // every iteration the arr is increasing by 1
Why initializing cnt to 1 if you want that the size of the allocated array is the number of times we had flag == 1 ?
Beside, you never write any value in this array. Assigning a value to *ptrArr would at best overwrite the first value of the array.
Another problem it that you initially copy arr to ptrArr. Later, if flag == 1 you reallocate arr. A reallocation implies that the input array may be deallocated (free) and a new bigger block is allocated. In this case, when you later assign a value to *ptrArr you won’t write in arr. You will write in deallocated space where you should not write. Worse, if that space is reallocated in the mean time, you may override valid data by mistake, which is a very nasty problem to debug.
I have the impression that you assume that reallocation creates space in front of the block. That is not correct. ralloc, extends the block. So room is added at the end of the block when its size grows.
This implies that you have to append mat[row][indexCol] to the array arr when flag == 1.
Here is how you should handle your array.
// initialize the array as empty
int cnt = 0;
int *arr = NULL;
Note that allocating a block of 0 bytes is implementation dependent. It may or may not return NULL. Here we decide that an empty array is NULL and has cnt == 0.
The following code appends the value mat[row][indexCol] to the array:
// append mat[row][indexCol] to the array arr
arr = realloc(arr, (cnt+1)*sizeof(int));
arr[cnt++] = mat[row][indexCol];
This works when arr is NULL because realloc will allocate a new block.
To print all values in the array:
for(int i = 0; i < cnt; i++)
printf("%d\t", arr[i]);
It doesn’t matter if arr == NULL when cnt == 0 because arr is never accessed when cnt == 0.
There is also a mistake in the code that locates the biggest value in a row.
You initialize tempCol with 0, and compare values with it. If the row contains only negative values that are all smaller than 0, your algorithm will fail to find the biggest value in the row.
In order to find the biggest value in a row, you have two options.
Initialize tempCol with the smallest possible value : INT_MIN (#include <limits.h>).
Use the following code that removes the need of tempCol.
indexCol = 0;
for (col = 1; col < COL; col++)
if (mat[row][col] > mat[row][indexCol])
indexCol = col;
// here, indexCol is the index of biggest value in the row
Your problem is mostly likely due to using ptrAtr. You initialise it to the start of arr, but later on you realloc arr and there is no guarantee that arr will remain at the same memory location which means that ptrArr will no longer point into it.
You'd be better off with using an index into arr like this..
int cnt = 0;
arr = (int*)malloc(cnt * sizeof(int));
// stuff happens
if (flag == 1)
{
arr = realloc(arr, (cnt + 1) * sizeof(int));
printf("mat[%d][%d] = %d\n", row, indexCol, mat[row][indexCol]);
arr[cnt++] = mat[row][indexCol];
}
}

Creating a matrix in C

I´m trying to create a dynamic matrix with an user introduzed number of lines and 6 columns.
I only want to create the matrix so I can get its values when I want to.
I have tried this but the program crashes when it gets here.
matriz = (int **)malloc(n_lines * 6 * sizeof(int *));
for (i = 0; i < n_lines; ++i)
{
for (j = 0; j < 6; ++j)
{
current_year = starting_year + i;
if (current_year % 400 == 0)
{
february = 29;
days = 366;
hours = 8784;
minutes = 527040;
seconds = 31622400;
}
else
{
february = 28;
days = 365;
hours = 8760;
minutes = 525600;
seconds = 31536000;
}
matriz[i][0] = { current_year };
matriz[i][1] = { february };
matriz[i][2] = { days };
matriz[i][3] = { hours };
matriz[i][4] = { minutes };
matriz[i][5] = { seconds };
}
}
Program crashed because you were accessing chunk of memory as if you have jagged allocated array which is not, resulting in invalid memory access in turn making your program crash.
Well from what I see - you messed up type. Two ways to go about this.
int **matriz;
matriz = malloc(sizeof *matriz*nlines);
// error check
for(size_t i=0; i<nlines; i++){
matriz[i]= malloc(sizeof *matriz[i] * 6);
// error check
}
int *matriz = malloc(6*nlines*sizeof *matriz);
// error check
matriz[r*6+c] = ... // accessing r-th row c-th column.
And based on case-1 it will be
matriz[i][j] = current_year ;
And in case-2 similarly
matriz[i*6+j] = current_year;
General code structure would be
if (current_year % 400 == 0)
{
...
seconds = 31622400;
}
else
{
...
seconds = 31536000;
}
for (j = 0; j < 6; ++j)
{
matriz[i][j] = current_year ;
...
}
To explain a bit - the first case is allocating a jagged array. First an array of pointers and then each of them are pointing to an array of 6 elements.
Second case is basically allocating a chunk of memory which has 6*nlines int and matriz is pointing to beginning of it. Now that's why you will have to access the elements first calculating the right index for it.

Resources