problem about using a dynamically allocated 2d array in a c program - c

I'm having a problem on making a move on my 9 x 9 tic tac toe program.
When I enter a coordinate such as (5,5), The x is displayed correctly on the grid.
MY PROBLEM IS THAT when I enter a coordinate which has the number 7 in it such as (4,7), TWO X's ARE DISPLAYED ON THE GRID.
I previously did the program declaring my array as a global variable. All was working fine. The issue started when I switched to a dynamically allocated array and passed the array using a double-pointer.
So I'm guessing that my problem is because of my array.
Can someone tell me where does this issue occur and how to fix it please.
I have declared the array in my main
//previously the array was declared here
//char grid[ROW][COLUMN];
int main()
{
//dynamically create an array of pointers os size ROW
char **grid = (char **)malloc(ROW * sizeof(char *));
// dynamically allocate memory of size ROW*COLUMN and let *grid point to it
*grid = (char *)malloc(sizeof(char) * ROW * COLUMN);
make move method
int make_move(char **grid, int x, int y,int row, int col, char letter)
{
if (x < 0 || x >= row || y < 0 || y >= col || grid[x][y] != ' ' )
{
// checks to see if the input is valid
return 1;
}
if( grid[x][y] == ' ')
grid[x][y] = letter;
// sets the coordinates in the grid to the letter
return 0;
}
update grid method
// Updates the grid accordingly every time a move is made
void update_grid(char **grid,int x, int y, int row, int col)
{
// int counter = 1;
//checks the input
while (x < 0 || x >= row || y < 0 || y >= col || grid[x][y] != ' ')
{
fputs("Error, Move not valid! Please reenter: ", stderr);
scanf("%d,%d", &x, &y);
}
++counter;
{
//Acts as an increment for the turns of the players
if(counter % 2 == 0)
{
//checks to see if it is player X's turn
grid[x][y] = 'X';
}
if(counter % 2 != 0)
{
//checks to see if it is player O's turn
grid[x][y] = 'O';
}
//prints grid
printf(" ");
for (int c = 0; c < col; c++)
{
printf(" ");
printf(" %d", c);
}
printf("\n");
for (int r = 0; r < row; ++r)
{
printf("%d", r);
printf("|");
for (int dot = 0; dot < (col*row); ++dot)
{
printf("|");
printf("%c", grid[r][dot]);
printf(" ");
if (dot == col - 1)
{
// stops j from over printing
printf("|| \n");
break;
}
}
}
}
}

As B. Go said your malloc is wrong, here's how it should look.
//dynamically create an array of pointers os size ROW
char **grid = malloc(ROW * sizeof(char *));
for(size_t i = 0; i < ROW; i++){
grid[i] = malloc(COLUMN);
}
you allocated ROW pointers but you only filled the first one, you need to give them each COLUMN bytes of data.

Related

C, 2D Array, How to find specific number in all 8 directions

You are allowed to enter only 0 and 1 as values in the arrays. Then in place of all elements having a value of 0, enter the number of elements with a value of 1 around that element in all eight directions. And on the end print the 2d array and the values with 1 change to *.
Here is an example how it's supposed to look like:
Here is my code
#include <stdio.h>
#include <stdlib.h>
int main()
{
int n,m;
scanf("%d%d", &n, &m);
int a[n][m];
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
scanf("%d", &a[i][j]);
if(a[i][j]==1){
a[i][j]=9;
}
}
}
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
int counter=0;
if(a[i][j]==9){
printf("*\t");
}else if(a[i][j]==0){
if(a[i+1][j+1]==9 && i!=n && j!=m) counter++;
if(a[i-1][j-1]==9 && i!=0 && j!=0) counter++;
if(a[i+1][j-1]==9 && i!=n && j!=0) counter++;
if(a[i-1][j+1]==9 && i!=0 && j!=m) counter++;
if(a[i][j+1]==9 && j!=m) counter++;
if(a[i][j-1]==9 && j!=0) counter++;
if(a[i+1][j]==9 && i!=n) counter++;
if(a[i-1][j]==9 && i!=0) counter++;
a[i][j]=counter;
counter=0;
printf("%d\t", a[i][j]);
}
}
printf("\n");
}
return 0;
}
You have UB (undefined behavior).
With (e.g.):
if (a[i + 1][j + 1] == 9 && i != n && j != m)
Then, a is always fetched, even if i or j is out of range.
To fix this, reorder the terms:
if (i != n && j != m && a[i + 1][j + 1] == 9)
Now, if either i or j is out of range, then the if will be "short circuited": (i.e. _short circuit evaluation) and the a value will not be fetched.
But, your program output is incorrect. You're coding everything out longhand. It makes it hard to debug (i.e. which lines have a bug).
What wasn't explicitly described was that you are summing the non-zero values in a 3x3 kernal around a given zero point.
The hardcoding doesn't scale too well. Suppose the kernal had to be 100x100. Would we code up 10,000 lines of code?
It's much easier to debug if we refactor to use for loops. And, to use more descriptive names instead of i/j/m/n:
n hgt
m wid
i y*
j x*
Here is the code:
#include <stdio.h>
#include <stdlib.h>
int
main(int argc,char **argv)
{
int hgt, wid;
int counter;
FILE *xf;
--argc;
++argv;
if (argc > 0)
xf = fopen(*argv,"r");
else
xf = stdin;
if (xf == NULL) {
perror(*argv);
exit(1);
}
fscanf(xf,"%d%d", &hgt, &wid);
int a[hgt][wid];
for (int ycur = 0; ycur < hgt; ycur++) {
for (int xcur = 0; xcur < wid; xcur++) {
int val;
fscanf(xf,"%d", &val);
if (val == 1)
val = 9;
a[ycur][xcur] = val;
}
}
for (int yctr = 0; yctr < hgt; yctr++) {
for (int xctr = 0; xctr < wid; xctr++) {
if (a[yctr][xctr] == 9) {
printf("*\t");
continue;
}
counter = 0;
for (int yoff = -1; yoff <= 1; yoff++) {
int ycur = yctr + yoff;
if (ycur < 0)
continue;
if (ycur >= hgt)
continue;
for (int xoff = -1; xoff <= 1; xoff++) {
int xcur = xctr + xoff;
if (xcur < 0)
continue;
if (xcur >= wid)
continue;
counter += (a[ycur][xcur] == 9);
}
}
printf("%d\t",counter);
}
printf("\n");
}
return 0;
}
Here is the program output for your sample input:
* 1 1 2 *
2 2 2 * 3
* 1 2 * 2
Not sure what the question is, but there are bugs in the code -
you are accessing out of array boundaries by doing, for example, this:
if(a[i-1][j-1]==9 && i!=0 && j!=0)
When i and j are zeros you are reading the value of a[-1][-1]. Changing the order of conditions and checking i and j first would guard against such an access.
Same happens when you access the "borders" of the matrix.
And, the "i!=n && j!=m" condition is always true within the loops - you iterate as long as i<n and j<m.
But aside of that, some of these accesses in fact read from within the array, but from a wrong location.
Here is an example that shows that:
Given the matrix of 2x2
0 1
1 0
This is the result your code produced:
2 *
* 3
Where obviously, '3' is wrong.
Why it happened?
The 2D array is in fact stored as a 1D array in memory, like this:
0 1 1 0 // this is your data
0 1 2 3 // this is the index in the array (offset from the array start)
And each element is located at an offset of row*columns+column from the array start (i.e. this is the formula to find the index in 1D array given i and j).
When you count the '1'-neighbours for the last element (a[1][1] in this example), you count the two obvious results (at a[1][0] and a[0][1]), but then you hit this condition:
if(a[i-1][j+1]==9 && i!=0 && j!=m)
For this last cell, i is 1 and j is 1, so the second part of the condition is true.
But what about a[i-1][j+1]==9 ?
This references a memory at row*columns+column, right? I.e. (i-1)*2+(j+1), because that's what you tried to access. Substituting i and j with 1 and 1, and you get offset 2 in the 1D array above.
Which is 1 in the input matrix (or actually 9 since you've replaced it).
So you count it twice.
Guarding better against "stepping out" of the matrix (but not necessarily out of the actual array) will solve this bug.

How to access elements of a Matrix using loops

I have two 4x4 multidimensional arrays, and the rows and columns are marked as being A, B, C and D. When the user inputs the co-ordinates, the value of known_location_info selected is changed to the value of bomb_location_info. So for example, if AA was input then the value of [1][1] on known_location_info is changed to the value of [1][1] on bomb_location_info. At the moment I am only getting the first element to change regardless of what co-ordinates are entered. What is incorrect in my loop?
char inputRow;
char inputColumn;
char letterA = 'A';
void display(int known_location_info[][DIM], int size) {
printf(" A B C D\n");
for (int row = 0; row < DIM; row++) {
printf("%c", letterA);
letterA++;
for (int column = 0; column < DIM; column++) {
printf("%d ", known_location_info[row][column]);
}
printf("\n");
}
printf("Please select a row and column: ");
scanf("%c, %c", &inputRow, &inputColumn);
}
void update_known_info(int row, int col, int bomb_location_info[][DIM],
int known_location_info[][DIM]) {
for (inputRow = letterA; inputRow < DIM; inputRow++) {
for (inputColumn = letterA; inputColumn < DIM; inputColumn++) {
row++;
col++;
}
}
known_location_info[row][col] = bomb_location_info[row][col];
}
#include <stdio.h>
#include <assert.h>
#define DIM 4
void display(int known_location_info[][DIM]) {
printf(" A B C D\n");
for (int row = 0; row < DIM; ++row) {
printf("%c ", 'A' + row);
for (int column = 0; column < DIM; ++column)
printf("%2d ", known_location_info[row][column]);
putchar('\n');
}
printf("Please select a row and column: ");
char inputRow; char inputColumn;
if (scanf(" %c, %c", &inputRow, &inputColumn) != 2 ||
inputRow < 'A' || 'A' + DIM < inputRow ||
inputColumn < 'A' || 'A' + DIM < inputRow)
{
// handle input error
}
}
void update_known_info(char row, char col, int bomb_location_info[][DIM],
int known_location_info[][DIM])
{
row -= 'A';
col -= 'A';
assert(0 <= row && row < DIM && 0 <= col && col < DIM);
known_location_info[row][col] = bomb_location_info[row][col];
}
Access matrix using chars that scanned from the user is not a good idea. because every char is represented by an ASCII code. hence you will have an implicit offset of the ascii value of the letter (for example ASCII fo A = 64. in the other hand matrixes are like arrays. they are indexed starting from 0. you may retrieve the ascii offset before starting your loops..

How do I print an "x" shape?

I needed some help with my homework. I've spent about 2 hours on this but I can't get my head around it (c programming). I have to print an x like so:
* *
* *
* *
* *
*
* *
* *
* *
* *
The steps of the program should work like this.
1. User inputs a single number which is the size (this single number is basically the width and height). Also we can assume the user always puts an odd number (so we don't need conditions for that).
2. It draws the X in respect to that size.
However, I can only use while loops, and if statements, scanf and printf. Nothing else.
This is what I can get so far (just a diagonal)
row = 0;
while (row < size) {
column = 0;
while (column < size) {
if (row == column) {
printf("*");
} else {
printf(" ");
}
column++;;
}
printf("\n");
row++;
}
this should work
#include <stdio.h>
int main()
{
int size, row, column;
scanf("%d", &size);
row = 0;
while (row < size)
{
column = 0;
while (column < size)
{
if (column == row || column == size - row - 1)
{
printf("x");
}
else
{
printf(" ");
}
column++;
}
printf("\n");
row++;
}
return 0;
}
#include <stdio.h>
int main(void) {
int size = 11; //this should be the size given by user.
char line[size + 1];
int i;
for(i = 0; i < size; i++) line[i] = ' ';
line[size] = '\0';
int se = 0;
int sw = size - 1;
while(se < size && sw >= 0){
line[se] = line[sw] = 'x';
printf("%s\n", line);
line[se++] = line[sw--] = ' ';
}
return 0;
}
Tested on Ideone and worked.
You are checking only one diagonal.To get the required pattern ,change the if condition as follows...
if ((row == column)||(row==(size-column-1)))

C Chomp questions?

I'm trying to create the game Chomp. I am halfway through but pretty stuck.
The game will have 5 different functions. Pointers and structs are not allowed.
This is how far I have come and I have been struggeling with a few problems for a while, but I can't figure out how to solve them by myself so I thought I could get some help here.
BUGS
a) If you first input 2 2 and then input 2 1 it will say that the position already has been eaten, even though it's a perfectly valid position to eat. Instead of checking if the position is != 'O' I should check if it is == 'O', but that won't work either because in the check_move() loop the row and col will not always be an O...
b) If you input a position that is not inside the matrix (i.e. 20 20) you will get two lines of errors. I don't understand why. Of course I only want to display one error, not two.
c) If you input a position that has already been eaten you will get the error "Already been eaten!" several times due to the loop that is looping through the print several times.
QUESTION
a) What is the best way to alternate between Player 1 and Player 2? I thought about an int that will increase by +1 every time a player makes a valid move. Then I will check if the value of the int is odd or even. Odd = Player 1 and even = Player 2 or vice verca. But that won't work because I'm not allowed to have any more global variables than I currently has. And I'm only allowed to return one value from one function (check_move()).
#include <stdio.h>
int height = 4;
int width = 10;
char matrix[4][10];
void initialize()
{
for(int row = 0; row < height; row++)
for(int col = 0; col < width; col++)
matrix[row][col] = 'O';
}
void print_board()
{
printf("\n\n");
for(int row = 0; row < height; row++)
{
for(int col = 0; col < width; col++)
{
printf("%c", matrix[row][col]);
}
printf("\n");
}
printf("\n\n");
}
void get_move(int player, int input[])
{
printf("Player %d, make your move: ", player);
scanf("%d %d", &input[0], &input[1]);
}
int check_move(int position[])
{
int row = position[0];
int col = position[1];
int status = 1;
if(row <= height && col <= width)
{
for(row; row <= height; row++)
{
for(col; col <= width; col++)
{
// Checks if position already has been eaten
if(matrix[row-1][col-1] != 'O')
{
printf("Already eaten!\n");
status = 0;
}
}
}
}
else if(row >= height || col >= width)
{
printf("Your move must be inside the matrix!\n");
status = 0;
}
return status;
}
void update_board(int x, int y)
{
for(int xi = x; xi <= 10; ++xi)
{
for(int yi = y; yi <= 10; ++yi)
matrix[xi-1][yi-1] = ' ';
}
}
int main(void)
{
int player = 1;
int position[2];
initialize();
print_board();
while(1){
get_move(player, position);
check_move(position);
while(check_move(position) != 1)
{
printf("Try again!\n\n");
get_move(player, position);
}
update_board(position[0], position[1]);
print_board();
}
getchar();
getchar();
getchar();
return 0;
}
Bug a and c:
Your check_move function is wrong, you should only test if the position played is eaten or not, the status of the other positions are not relevant:
int check_move(int pos[])
{
if(pos[0] < 1 || pos[0] > height || pos[1] < 1 || pos[1] > width)
{
printf("Your move must be inside the matrix!\n");
return 0;
}
if(matrix[ pos[0] - 1 ][ pos[1] - 1 ] != 'O' ) {
printf("Already eaten!\n");
return 0;
}
return 1;
}
Bug b:
You get the error message twice because you're calling check_move twice in your main:
check_move(position);
while(check_move(position) != 1)
Just remove the useless first call to check_move().
Question a:
You can switch between players by updating the variable player inside your main :
player = (player + 1) % maxNumberOfPlayer;
This will go from 0 to maxNumberOfPlayer - 1, so you may use printf("Player %d, make your move: ", player + 1); for a more user-friendly output. Also, if maxNumberOfPlayer = 2, player = (player + 1) % 2; is equivalent to player = !player.
In main, inside your while loop just add:
player = !player;
Which will toggle player between 0 and 1.

how to store a masked array

i have been asked to code a memory game, with some specifics, where the reveled letter shows the first time then, if the user in the 2nd prompt guesses the corresponding matching spot, the board should stay like that until the user finishes the game (by guessing all of the correct matching spots), heres an example with a 2x2 grid
Your program:
* *
* *
Enter a pair of integers in the range [1, 2]
Player: 1 1
Your program:
A *
* *
(then it clears the screen and displays)
* *
* *
Enter another pair of integers in the range [1, 2]
Player: 2 1
Your program:
* *
C *
(then it clears screen and displays)
* *
* *
Enter a pair of integers in the range [1, 2]
Player: 1 2
Your program:
* C
* *
(then it clears screen and displays)
* *
* *
Enter another pair of integers in the range [1, 2]
Player: 2 1
Your program:
* *
C *
(then it clears the screen and displays)
* C
C *
Enter a pair of integers in the range [1, 2]
Player: 1 1
Your program:
A C
C *
(then it clears the screen and displays)
* C
C *
Enter another pair of integers in the range [1, 2]
Player: 1 1
Your program:
A C
C *
(then it clears the screen and displays)
* C
C *
Enter a pair of integers in the range [1, 2]
Player: 1 1
Your program:
A C
C *3
(then it clears the screen and displays)
* C
C *
Enter another pair of integers in the range [1, 2]
Player: 2 2
Your program:
A C
C A
CONGRATULATIONS. YOU SUCCEEDED
i need a 4x4, i understand how to show the correct matches but i cannot seem to store the new board, so the user sees the most current board, i cant wrap my head around it....
char board[4][4] = { {'A','B','A','D'},{'C','E','H','G'},{'B','D','G','C'},{'F','H','F','E'} };
int i, j, row, column, row2, column2;
char boardmatch[4][4];
int tempX,tempY;
for(tempX = 0; tempX < 4; tempX++){
for(tempY = 0; tempY < 4; tempY++){
boardmatch[tempX][tempY] = 0;
}
}
for (i=0; i < 4 ; i++){
for (j=0; j<4; j++){
printf("* ");
}
printf("\n");
}
do {
printf("\nEnter a pair of integers in the range [1, 4]: ");
scanf("%d %d", &row, &column);
row--;
column--;
printf("\n");
for (i=0; i < 4 ; i++){
for (j=0; j < 4 ; j++){
if ( i == row && j == column){
printf("%c ", board[row][column]);
}else{
printf("* ");
}
}
printf("\n");
}
printf("\n");
system("pause");
system("cls");
for (i=0; i < 4 ; i++){
for (j=0; j<4; j++){
printf("* ");
}
printf("\n");
}
printf("\nEnter another pair of integers in the range [1, 4]: ");
scanf("%d %d", &row2, &column2);
row2--;
column2--;
printf("\n");
for (i=0; i < 4 ; i++){
for (j=0; j < 4 ; j++){
if (i == row2 && j == column2){
printf("%c ", board[row2][column2]);
}else{
printf("* ");
}
}
printf("\n");
}
system("pause");
system("cls");
if(board[row][column]==board[row2][column2]){
boardmatch[row][column] = 1;
boardmatch[row2][column2] = 1;
}
for (i=0; i < 4 ; i++){
for (j=0; j<4; j++){
if (boardmatch[i][j] == 1){
printf("%c ", board[row2][column2]);
}else{
printf("* ");
}
}
printf("\n");
}
printf("\n");
system("pause");
system("cls");
}while(1);
system("PAUSE");
return 0;
}
You need another array for the board.
It just holds a bit for each cell, meaning 'found' or 'turned'.
Use that (and the original board) to display the board.
Only show the cells that have been found/turned.
For the players turns, when some cells might be turned back, just remember which cell was turned so you can flip it back to unfound/unturned. This array starts out as all unturned and the game finishes when they are all turned.
(You can use a struct to put this all in one array as well.)
The problem is in these lines (fix already applied).
if (boardmatch[i][j] == 1)
{
printf("%c ", board[i][j]);
}
It should show the correct value if it has been matched before. Not the ones under row2, column2
Also, here's an alternative on what you're doing, storing the previous values of row and column as row_old and column_old.
#include <stdio.h>
// Prints the matrix
void board_print(char board[4][4], char boardmatch[4][4], int revealRow, int revealColumn, int revealRow2, int revealColumn2)
{
int row, col;
printf(" 0 1 2 3\n");
// Printing code
for (row=0; row < 4 ; row++)
{
printf ("%d ", row);
for (col=0; col<4; col++)
{
// Print the value if there's a board match
// or there's a revealRow/revealColumn
if (boardmatch[col][row] == 1
|| (row == revealRow && col == revealColumn)
|| (row == revealRow2 && col == revealColumn2))
{
printf("%c ", board[col][row]);
}
else
{
printf("* ");
}
}
printf("\n");
}
}
// Clears board
void board_clear(char board[4][4])
{
int i,j;
for(i = 0; i < 4; i++)
{
for(j = 0; j < 4; j++)
{
board[i][j] = 0;
}
}
}
// Main game loop
void game_loop()
{
char board[4][4] = { {'A','B','A','D'},{'C','E','H','G'},{'B','D','G','C'},{'F','H','F','E'} };
int row, column, row_old=-1, column_old=-1;
char boardmatch[4][4];
board_clear(boardmatch);
// Reveal the matrix
board_print(board, boardmatch, -1, -1, -1, -1);
do
{
// Ask for input
printf("\n[column row]: ");
fflush(stdin);
scanf("%d %d", &column, &row);
// Adjust the values
// Check the previous value
if (row_old == -1 || column_old == -1)
{
// There was nothing stored
// Store the previous values
row_old = row;
column_old = column;
// Print only the selected value
board_print(board, boardmatch, row, column, -1, -1);
}
else
{
// There was something stored
// Check if he did it
if (board[column][row] == board[column_old][row_old])
{
// You did it! Store as matched
boardmatch[column][row] = 1;
boardmatch[column_old][row_old] = 1;
// Present the result to the user
board_print(board, boardmatch, row, column, -1, -1);
printf("Match!\n");
}
else
{
// Nope, you didn't
// Present the two items marked (old and selected)
board_print(board, boardmatch, row, column, row_old, column_old);
printf("YOU SUCK!\n");
}
// Now print the matrix with the selected values
// Finally, kill the previous values
row_old = -1;
column_old = -1;
}
// (Check the boardmatch if every value is 1, and break if it does)
} while (1);
}
int main(int argc, const char * argv[])
{
game_loop();
return 0;
}
The key here, is that the row_old and column_old acts as the check for the items, as much as it acts for a flag for the game.
Whenever it's -1, it means that the previous match has not been made, and when it stores a value, it represents the previous match.
I also suggest as an improvement and/or lesson, modify the code using the structs:
#import <stdbool.h>
typedef struct
{
char value;
bool matched;
}tile;
typedef struct
{
int row, col;
}coordinate;

Resources