Initialize 2D array in C using array of pointers - arrays

I have a static array that I want to use to initialize a dynamic array using pointers.
Right now I have this:
boardinit[BOARD_HEIGHT][BOARD_LENGTH] = {
{-4, -2, -3, -5, -6, -3, -2, -4},
{-1, -1, -1, -1, -1, -1, -1, -1},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 1, 1, 1, 1, 1, 1},
{4, 2, 3, 5, 6, 3, 2, 4},
};
int main()
{
int board[BOARD_HEIGHT][BOARD_LENGTH];
initboard(board);
for (int j = 0; j < BOARD_HEIGHT; j++)
{
for (int i = 0; i < BOARD_LENGTH; i++)
printf("%d ", board[j][i]);
printf("\n");
}
return 0;
}
void initboard(int (*pboard)[BOARD_HEIGHT])
{
for(int i = 0;i<BOARD_HEIGHT;i++)
pboard[i] = boardinit + i;
}
I want board[BOARD_HEIGHT][BOARD_LENGTH] to initialize as boardinit[BOARD_HEIGHT][BOARD_LENGTH] by passing board to initboard() using pointers, but can't seem to get it to go.

To copy the contents boardinit to the value of board, just use this:
memcpy(board, boardinit, sizeof(board));
If that does not work, try this:
void initboard(int pboard[BOARD_HEIGHT][BOARD_LENGTH]) {
for (int i = 0; i < BOARD_HEIGHT; i++)
for (int j = 0; j < BOARD_LENGTH; j++)
pboard[i][j] = boardinit[i][j];
}

"I have a static array that i want to use to initialize a dynamic array using pointers."
The problem with arrays of pointers is that each call to [m][c]alloc() is not guaranteed (in fact is not likely) to provide a single contiguous block of memory. i.e., this is a common approach that provide many little areas of memory:
int **array = malloc(sizeof(width * sizeof(int *));
{
for(int i=0; i<width; i++)
{
array[i] = malloc(height*sizeof(int));
}
}
Thus, the initializer would need to be broken into several memory block locations.
A simpler and more efficient way to do this is with a single dynamic memory allocation call, guaranteeing a single contiguous block of memory, then a single memcpy() is possible using the initializer into the pointer location returned from [m][c]alloc(). The only problem then is how to access the memory area with array notation. The example below illustrates how this can be done using *(ptr + index) notation...
//assuming your other code above
int main(void)
{
int elements = BOARD_HEIGHT*BOARD_LENGTH;
int *pArray = calloc(elements, sizeof(int));
if(pArray)
{
memcpy(pArray, boardinit, sizeof boardinit);
for(int i=0; i<BOARD_HEIGHT;i++)
for(int j = 0;j<BOARD_LENGTH;j++)
printf("%d\n", *(pArray + (i + j)));
free(pArray);
}
return 0;
}

Related

Undefined functions in header file

I am trying to create a sudoku solver and want to divide my project into different files.
I want my board.c file to handle the creation and printing of the board while the solver.c file will have the solver functions and such.
I currently have three three files. sudokuSolver.c, board.c, board.h
Have I defined the header files incorrectly or am I missing something else?
sudokuSolver.c:
#include <stdio.h>
#include <stdlib.h>
#include "board.h"
int main()
{
int** board;
board = createBoard();
printBoard(board);
free(board);
return 0;
}
board.h:
#ifndef BOARD_H_
#define BOARD_H_
int ** createBoard();
void printBoard(int**);
#endif
board.c:
#include <stdio.h>
#include <stdlib.h>
#include "board.h"
int** createBoard(){
int array[9][9] = {
{3, 0, 0, 6, 0, 2, 0, 0, 4},
{0, 0, 0, 0, 7, 9, 8, 0, 3},
{0, 1, 0, 0, 0, 0, 7, 0, 0},
{0, 0, 0, 0, 6, 0, 0, 0, 2},
{0, 4, 1, 7, 0, 8, 0, 0, 0},
{7, 0, 6, 0, 0, 0, 4, 0, 0},
{9, 0, 7, 2, 8, 5, 3, 4, 0},
{0, 8, 0, 0, 0, 0, 2, 9, 0},
{1, 2, 3, 0, 4, 7, 5, 6, 0}
};
int k, **board;
board = malloc(9*sizeof(int *));
for(k = 0 ; k < 9 ; k++)
board[k] = malloc(9*sizeof(int) );
for (size_t i = 0; i < 9; i++)
{
for (size_t j = 0; j < 9; j++)
{
board[i][j] = array[i][j];
}
}
return board;
}
void printBoard(int** board){
for (size_t i = 0; i < 9; i++)
{
for (size_t j = 0; j < 9; j++)
{
printf("%d ", board[i][j]);
}
printf("\n");
}
return;
}
EDIT: When I try to compile the code with gcc sudokuSolver.c board.h board.c in the terminal.
After compiling I now have an executable a.exe file that runs the program correctly.
Now I run into a new problem. After the code is compiled I try to run the code directly from Visual Studio Code (Ctrl+Alt+N) But still receive this error:
C:\Users\x\AppData\Local\Temp\ccbnvRga.o:sudokuSolver.c:(.text+0xf): undefined reference to `createBoard'
C:\Users\x\AppData\Local\Temp\ccbnvRga.o:sudokuSolver.c:(.text+0x1f): undefined reference to `printBoard'
collect2.exe: error: ld returned 1 exit status
As Some programmer dude pointed out. I had to configure VSCode to be able to compile multiple source files.
I solved this by adding
,
"code-runner.executorMap": {
"c": "cd $dir && gcc *.c -o $fileNameWithoutExt && $dir$fileNameWithoutExt"
}
in settings of the code Runner extension

Incorrect results when printing out a submatrix of a 2D array in C

I'm new to C and learning about arrays. I've made a function, print2d, to print out a two dimensional array. I've created a 9x9 array, array2d. First, I printed out array2d using print2d, which worked perfectly. Then, I tried to print out a 3x3 submatrix of array2d that consists of elements in the first three rows and first three columns. The 3x3 submatrix is printed out incorrectly.
In main:
int array2d[9][9] = {
{0, 1, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 1, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0},
{0, 0, 0, 0, 0, 0, 0, 0, 0}
};
print2d(rows,cols,array2d);
print2d(3,3,array2d); // print 3x3 submatrix
void print2d(int rows, int cols, int array[][cols])
{
printf("{");
for (int r = 0; r < rows; r++)
{
printf("{%i",array[r][0]);
for (int c = 1; c < cols; c++)
{
printf(", %i",array[r][c]);
}
printf("}\n");
}
printf("}\n");
}
Output:
The 9x9 matrix array2d is printed out properly, but the 3x3 submatrix is printed out as:
{{0, 1, 0}
{0, 0, 0}
{0, 0, 0}
}
instead of
{{0, 1, 0}
{0, 0, 0}
{1, 1, 0}
}
The first row of the submatrix is correct, but the third row is not. My guess is that by calling print2d(3,3,array2d), the function print2d is expecting a 2d array with 3 columns (int array[][3]), rather than a 9x9 array. I'm not sure what kind of problem that is causing, and why the first row of the output is correct but not the third. Thank you for your help!
You can use double pointer instead of 2D array
void print2d(int rows, int cols, int **array);
Or define the sub array as #Weather_Vane comment above:
void print2d(int rows, int cols, int array[rows][cols], int sub_row, int sub_col) {
for (int r = 0; r < sub_row; r++)
{
...
for (int c = 1; c < sub_col; c++)
{
...
}
...
}
printf("}\n");
}
main function for array with sub array arguments
print2d(9,9,array2d, 9, 9);
print2d(9,9,array2d, 3, 3);
main function for double pointer:
int main() {
int rows, cols, i;
int **array2d;
/* obtain values for rows & cols*/
// allocate the array
array2d = malloc(rows * sizeof(int));
if (!array2d)
return -1;
for (i=0; i<rows; i++) {
array2d[i] = malloc(cols * sizeof *array2d[i]);
if(!array2d[i])
return -1;
}
/*init the values of array here */
print2d(rows,cols,array2d);
for (i=0; i<rows; i++)
free(array2d[rows];
free(array2d);
}

How to fix ' Error: invalid read of size 4'

I'm trying to learn C and am completing different challenges in order to learn faster. The code seems logical to me and should progress. However, I'm getting an invalid read of size four on line 29
I've tried to change the data type that gets parsed through, but it didn't seem to work.
#include <unistd.h>
typedef struct s_grid
{
int x;
int y;
} t_grid;
void set_point(t_grid *coord, int i, int j)
{
coord->x = i;
coord->y = j;
}
//check loccation of next zero
int where_is_zero(int **sudoku)
{
int x;
int y;
t_grid coord;
x = 0;
y = 0;
while (x < 9)
{
y = 0;
while (y < 9)
{
if (sudoku[x][y] == 0) //Here I'm getting the error.
{
set_point(&coord, x, y);
return (0);
}
x++;
}
y++;
}
return (1);
}
int solve_sudoku(int **grid)
{
int row;
int col;
int num;
t_grid coord;
if (where_is_zero(grid) == 1)
return (1);
row = coord.x;
col = coord.y;
//where_is_zero(grid);
num = 1;
while (num <= 9)
{
if (check_number(grid, row, col, num) == 1)
{
grid[row][col] = num;
if (solve_sudoku(grid) == 1)
return (1);
grid[row][col] = 0;
}
num++;
}
return (0);
}
void ft_putchar(char c)
{
write(1, &c, 1);
}
void ft_putstr(char *str)
{
while (*str != '\0')
{
ft_putchar(*str);
str++;
}
}
//my main function
int main(int argc, char **argv)
{
int board[9][9] ={ { 0, 9, 0, 0, 0, 0, 8, 5, 3 },
{ 0, 0, 0, 8, 0, 0, 0, 0, 4 },
{ 0, 0, 8, 2, 0, 3, 0, 6, 9 },
{ 5, 7, 4, 0, 0, 2, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 9, 0, 0, 6, 3, 7 },
{ 9, 4, 0, 1, 0, 8, 5, 0, 0 },
{ 7, 0, 0, 0, 0, 6, 0, 0, 0 },
{ 6, 8, 2, 0, 0, 0, 0, 9, 0 } };
solve_sudoku(board);
return (0);
}
I removed some code just to highlight where the problem is. It should find the next 0 in the table and set the coordinations to my structure.
The problem lies in how you have the loop set up. See my comments below:
while (x < 9)
{
y = 0;
while (y < 9)
{
if (sudoku[x][y] == 0) //Here I'm getting the error.
{
set_point(&coord, x, y);
return (0);
}
x++; // This increments the x index while you're inside the y loop
}
y++; // This increments the y index when you meant to increment the x
}
If you swap both lines, that should work fine and will resolve your out-of-bounds error.
What would also help you write this better is instead of using a while loop, use a for loop. If you haven't covered that topic yet, it's really straightforward:
for(int x = 0; x < 9 ; ++x)
{
for (int y = 0; y < 9; ++y)
{
if (sudoku[x][y] == 0) //Here you won't get the error anymore!
{
set_point(&coord, x, y);
return (0);
}
}
}
What the for loop line means there is this: Start the loop by setting it to 0, at the end of an iteration, increment it. On the next iteration, check if x is still less than 9. If so, proceed with the next iteration.
Your problem is due to mixing types. In main() you declare:
int board[9][9] = { ....
You then pass:
solve_sudoku(board);
board has the type int (*)[9] (a pointer to array of int [9]). See C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3). Your solve_soduku expects a parameter of type int** (pointer to pointer to int).
int solve_sudoku(int **grid) { ...
The type are NOT compatible. (and your compiler should be screaming warnings at you)
board is a pointer to array of int [9], while grid is a pointer to pointer to int. You must make the types compatible. The easiest way is to change solve_sudoku to
int solve_sudoku(int (*grid)[9]) { ...
Otherwise you will need to declare board as int** and allocate and fill in main().

C Programming - Integer value within struct becomes "random" after assignment [duplicate]

This question already has an answer here:
How do I get a function to modify any of the parameters?
(1 answer)
Closed 4 years ago.
I've searched for a fix to this issue but haven't been able to find an explanation. I have a two dimensional struct which has an integer variable within it.
typedef struct
{
int example;
} Example;
typedef struct
{
Example two_dimensional_array[5][5];
} Example_Outer;
I then set this variable to 0 for all fields using the following function and print the current values.
void initialise(Example_Outer example)
{
for(int i = 0; i < 5; i++){
for(int j = 0; j < 5; j++){
example.two_dimensional_array[i][j].example = 0;
}
}
print_example(example);
}
During this print, the values all appear as 0's like they should.
Output:
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
I then run a new function that utilises the exact same print code, and receive the following output:
0, 0, 0, 0, 9,
0, -394918304, 32551, -2138948520, 32764,
1, 0, 1, 0, 1775692253,
21904, -394860128, 32551, 0, 0,
1775692176, 21904, 1775691312, 21904, -2138948320,
print method:
void print_example(Example_Outer example)
{
for(int i = 0; i < 5; i++){
for(int j = 0; j < 5; j++){
printf("%d, ", example.two_dimensional_array[i][j].example);
}
printf("\n");
}
}
main method:
int main( int argc, const char* argv[] )
{
Example_Outer example;
initialise(example);
printf("---------------\n");
print_example(example);
}
Why do the variables not remain set to 0? What is causing this and how can I fix it? Thank you!
First, you can initialize your struct like bellow in a simple way :
Example_Outer example = { 0 };
Or in second way :
typedef struct
{
Example two_dimensional_array[5][5] = { 0 };
} Example_Outer;
Now in your code , you forgot about * in your void initialise(Example_Outer example) function, and in this case you just passing a copy of struct in function.
So you should use of struct's address as parameter to the function with pointer (*) :
void initialise(Example_Outer *example)
{
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
example->two_dimensional_array[i][j].example = 0;
}
}
print_example(*example);
}
Finally you can pass your struct's address as following : ( Test it online ) :
int main(int argc, const char* argv[])
{
Example_Outer example;
initialise(&example);
printf("---------------\n");
print_example(example);
}

Changing of elements of array when passed as an index of another array

I am a rookie, and I hope this question is not a naive one!
I have the following function, where I use elements of one array as indices of another. However, despite my making no changes to the former, I see that the elements are being modified. The code is as follows:
void convert_to_bitmap(int n_shapes, int sizex, int sizey,
int ll_x[n_shapes], int ll_y[n_shapes],
int ur_x[n_shapes], int ur_y[n_shapes],
int shapes_ll_bitmap[sizex][sizey],
int shapes_ur_bitmap[sizex][sizey] )
{
int i;
for (i = 0; i < n_shapes; i++)
{
printf("%d, %d, %d, %d check1\n", ll_x[i], ll_y[i], ur_x[i], ur_y[i]);
}
for (i = 0; i < n_shapes; i++)
{
shapes_ll_bitmap[ll_x[i]][ll_y[i]] = 1;
shapes_ur_bitmap[ur_x[i]][ur_y[i]] = 1;
printf("%d, %d, %d, %d check2\n", ll_x[i], ll_y[i], ur_x[i], ur_y[i]);
}
}
And, the output shows that the first array has changed when I do so. Is there some way to keep it immutable?
Output:
0, 0, 0, 7 check1
0, 9, 0, 15 check1
1, 0, 1, 7 check1
1, 9, 1, 15 check1
2, 13, 2, 15 check1
2, 17, 2, 24 check1
2, 26, 2, 32 check1
0, 0, 0, 7 check2
0, 9, 0, 15 check2
1, 0, 1, 7 check2
1, 9, 1, 15 check2
1, 13, 2, 15 check2
2, 1, 2, 1 check2
1, 26, 2, 32 check2
This is how I invoke the function in main():
convert_to_bitmap(n_shapes, sizex, sizey, ll_x, ll_y, ur_x, ur_y, shapes_ll_bitmap, shapes_ur_bitmap);
And the declaration and initialization of the matrices in int main() is as follows:
int ll_x[n_shapes];
int ll_y[n_shapes];
int ur_x[n_shapes];
int ur_y[n_shapes];
int sizex;
int sizey;
int shapes_ll_bitmap[sizex][sizey];
int shapes_ur_bitmap[sizex][sizey];
for (i=0; i < sizex; i++)
{
for (j = 0; j < sizey; j++)
{
shapes_ll_bitmap[i][j] = 0;
shapes_ur_bitmap[i][j] = 0;
}
printf("\n");
}
Thank you!
Edit:
Here's some self-contained code:
int main(void)
{
enum { MAX_SHAPES = 100000 };
struct Rectangle rect_array[MAX_SHAPES];
int n_shapes = read_shapes_rpt("shapes.rpt", MAX_SHAPES, rect_array);
int i, j;
float pitch_x = 0.044;
float pitch_y = 0.042;
float ll_x_flt[n_shapes];
float ll_y_flt[n_shapes];
float ur_x_flt[n_shapes];
float ur_y_flt[n_shapes];
int ll_x[n_shapes];
int ll_y[n_shapes];
int ur_x[n_shapes];
int ur_y[n_shapes];
int sizex;
int sizey;
int shapes_ll_bitmap[sizex][sizey];
int shapes_ur_bitmap[sizex][sizey];
for (i=0; i < sizex; i++)
{
for (j = 0; j < sizey; j++)
{
shapes_ll_bitmap[i][j] = 0;
shapes_ur_bitmap[i][j] = 0;
}
printf("\n");
}
if (n_shapes > 0)
{
transform_to_shape_bit_locations(n_shapes, rect_array, ll_x_flt, ll_y_flt, ur_x_flt, ur_y_flt, ll_x, ll_y, ur_x, ur_y, &pitch_x, &pitch_y, &sizex, &sizey);
convert_to_bitmap(n_shapes, sizex, sizey, ll_x, ll_y, ur_x, ur_y, shapes_ll_bitmap, shapes_ur_bitmap);
printf("%d\n%d\n%d\n", n_shapes, sizex, sizey);
/* Use the shapes that were read */
}
return 0;
}
My shapes.rpt file contained the following csv values:
1.408,529.237,1.43,529.523
1.408,529.597,1.43,529.883
1.452,529.237,1.474,529.523
1.452,529.597,1.474,529.883
1.496,529.777,1.518,529.883
1.496,529.957,1.518,530.243
1.496,530.317,1.518,530.564
Your variables sizex and sizey are left uninitialized. Which means that your matrices shapes_ll_bitmap and shapes_ur_bitmap have unpredictable size (the behavior is actually undefined).
Note that when you actually assign meaningful values to your your sizex and sizey later, it is already too late. The matrices are already declared with indeterminate sizes and that's final. Once the matrices are declared, any changes to the values of sizex and sizey will have no effect on the matrices.
Your matrices end up with some indeterminate size, which results in out-of-bounds access inside convert_to_bitmap function and destruction of unrelated memory values.

Resources