Passing 2D array to a Function: zero-value and print issue - c

I want to pass 2D array to a function. I've written 3 functions:
make all the values == 0;
implement it with desired values;
print matrix;
My output looks wrong. I checked in debug mod that mapZero works right (it implements zeros by all rows and columns but). The first matrix must consist of only zero values, the second one with implemented (btw, why my commented code in mapInit can't be built? It seems I did it right). and the third matrix is a new matrix implemented with my algorithm (I'm writin wave-algorithm to find the shortest way to a final point).
I can't get how and where I should use pointers (maybe the problem is in it?) and how to pass WIDTH and HEIGHT with a right way.
int mapZero(int * map[WIDTH][WIDTH])
{
for (int i = 0; i < WIDTH; ++i)
{
for (int j = 0; j < HEIGHT; ++j)
{
map[i][j] = 0;
}
}
}
int mapPrint(int map[WIDTH][HEIGHT])
{
for (int i = 0; i < WIDTH; ++i)
{
for (int j = 0; j < HEIGHT; ++j)
{
printf("%2d ", map[i][j]);
}
printf("\n\n");
}
printf("\n");
return 0;
}
int mapInit(int * map[WIDTH][WIDTH])
{
/*
map[WIDTH][WIDTH] =
{
{ 127,1,1,1,1,1,1, 1 },
{ 0, 1,0,0,0,1,1, 1 },
{ 1, 1,1,1,0,0,0, 1 },
{ 1, 0,0,1,0,0,0, 1 },
{ 1, 0,1,1,0,0,1, 1 },
{ 1, 1,1,1,1,1,1, 1 },
{ 0, 1,0,0,1,0,1, 1 },
{ 1, 1,1,1,1,1,1,255 },
};
*/
for (int i = 0; i < WIDTH; ++i)
{
for (int j = 0; j < HEIGHT; ++j)
{
map[i][j] = 0;
}
}
for (int j = 0; j < WIDTH; ++j)
{
map[0][j] = 1;
map[7][j] = 1;
map[j][7] = 1;
map[5][j] = 1;
}
for (int j = 2; j < 5; ++j)
{
map[j][0] = 1;
}
map[1][1] = 1; map[1][5] = 1; map[1][6] = 1;
map[2][1] = 1; map[2][2] = 1; map[2][3] = 1;
map[3][3] = 1;
map[4][2] = 1; map[4][3] = 1; map[4][6] = 1;
map[6][1] = 1; map[6][4] = 1; map[6][6] = 1; map[6][7] = 1;
map[0][0] = 22;
map[7][7] = 99;
return 0;
}
My main.c:
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#define WIDTH 8
#define HEIGHT 8
int mapZero(int * map[WIDTH][WIDTH]);
int mapPrint(int map[WIDTH][HEIGHT]);
int mapInit(int * map[WIDTH][WIDTH]);
int main(int argc, char * argv[])
{
short int map[WIDTH][HEIGHT];
short int visited[WIDTH][HEIGHT];
mapZero(visited);
mapZero(map);
mapInit(map, WIDTH, HEIGHT);
printf("Matrix of zeroed-visited cells:\n\n");
mapPrint(visited, WIDTH, HEIGHT);
printf("Matrix of the map:\n\n");
mapPrint(map, WIDTH, HEIGHT);
return 0;
}

The argument declaration int * map[WIDTH][WIDTH] is equal to int * (*map)[WIDTH]. That's an array of array of pointers to int. You pass an array of array of short int.
Drop the asterisk, use the correct type in the arguments, and the correct symbolic constant: short int map[WIDTH][HEIGHT].
You also call mapInit and mapPrint with two extra arguments that are not in the declared functions.
The compiler should have complained about all of this.

int * map[WIDTH][WIDTH] is an array of pointers. It is not compatible with the array in the caller so the code should not compile. Change this to int map[WIDTH][WIDTH].
Similarly, an array of short is not necessarily compatible with an array of int. Use the same type everywhere.
If your code compiled without errors/warnings there's something very wrong with your compiler.
By the rule of array parameter adjustment ("decay"), the above array declaration, when part of a parameter list, will get adjusted by the compiler to the pointer to the first element. The first element of the 2D array is a 1D array, so it gets adjusted to an array pointer to a 1D array, int (*)[WIDTH].

Related

passing a char 2d array into a void function in c

I'm new to c but I have been trying for ages to try and get this to work even though it seems so simple.
So below is what I am aiming to do which is working but I want to make 2 functions: fillseats() and printseatingplan()[for now I just want them all blank];
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main()
{
char seatingplan[15][15];
memset(seatingplan,'.',sizeof seatingplan);
for (int k = 0; k < 15; ++k)
{
for(int j = 0; j < 15; ++j)
{
printf("%c",seatingplan[k][j]);
}
printf("\n");
}
}
So whenever I try to run these functions without pointers it gives me these �`:�ij:�
i�d:�iH#=�i
�B��ik:�
how can i use pointers to fix this
can I pass this array into the functions where printseatingplan()
void printseatingplan(char array[15][15])
{
for (int k = 0; k < 15; ++k)
{
for(int j = 0; j < 15; ++j)
{
printf("%c",array[k][j]);
}
printf("\n");
}
}
and then fillseats() does:
void fillseats(char array[15][15])
{
memset(array,'.',sizeof array);
}
sizeof will give you only the size of the pointer, not the whole array.
You need to pass the sizes to the function. I would use pointer to array:
void fillseats(size_t rows, size_t cols, char (*array)[cols])
{
memset(array,'.',rows * sizeof(*array));
}
void printseatingplan(size_t rows, size_t cols, char (*array)[cols])
{
for (size_t row = 0; row < rows; row++)
{
for(size_t col = 0; col < cols; col++)
{
printf("%c",array[row][col]);
}
printf("\n");
}
}
char array[15][15] when used as parameter to a function "decays" into a pointer to the first element, in this case equivalent to char (*array)[15]). If you do sizeof array instead the function, you get the size of a pointer (4 or 8 etc). If you do sizeof *array you just get the size of one dimension, 15.
A simple way to fix it:
#include <stdio.h>
#include <string.h>
void fillseats (size_t x, size_t y, char array[x][y])
{
memset(array, '.', sizeof(char[x][y]));
}
void printseatingplan (size_t x, size_t y, char array[x][y])
{
for (size_t i = 0; i < x; i++)
{
for(size_t j = 0; j < y; j++)
{
printf("%c",array[i][j]);
}
printf("\n");
}
}
int main (void)
{
char seatingplan[15][15];
fillseats(15, 15, seatingplan);
printseatingplan(15, 15, seatingplan);
}
The size of array is bound to its type. The problem is that the parameters of array type decay to pointers. To prevent it, you can pass a pointer to an array. The pointer don't decay thus the essential part of the array type prevails.
void printseatingplan(char (*array)[15][15])
{
for (int k = 0; k < 15; ++k)
{
for(int j = 0; j < 15; ++j)
{
printf("%c", (*array)[k][j]);
}
printf("\n");
}
}
void fillseats(char (*array)[15][15])
{
memset(*array,'.',sizeof *array);
}
int main (void)
{
char seatingplan[15][15];
fillseats(&seatingplan);
printseatingplan(&seatingplan);
}

2D arrays using arrays of pointers or pointers to pointers in C?

I'm writing a C for which I need to create a 2D array. I've found a solution to my problem using double pointers (pointers to pointers) in the following way:
#include <stdio.h>
#include <stdlib.h>
int d = 3;
#define DIM_MAX 9
void changeArray(int d, int *array[d]);
int main()
{
//alocate array of 'd' colummns and 'd' row using malloc using array of pointers
int **array = malloc(d*sizeof(int *));
for(int count = 0; count < d; count++)
{
array[count] = malloc(d*sizeof(int *));
}
/* Call changeArray function */
changeArray(d, array);
for(int i = 0; i < d; i++)
{
for(int j = 0; j < d; j++)
{
printf("%d ", array[i][j]);
}
printf("\n");
}
for(int count = 0; count < d; count++)
{
free(array[count]);
}
return 0;
}
void changeArray(int n, int *array[d])
{
for(int i =0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
array[i][j] = i*j;
}
}
return;
}
The code above works pretty well (it seems), but I've read in the web that using pointer to pointer is not the correct way to create 2D arrays. So I've come up with the following code, which also works:
#include <stdio.h>
#include <stdlib.h>
#define DIM_MAX 9
int d = 3;
void changeArray(int d, int *array[d]);
int main()
{
//alocate array of 'd' colummns and 'd' row using malloc using array of pointers
int *array[DIM_MAX] = {0};
for(int count = 0; count < d; count++)
{
array[count] = (int *)malloc(d*sizeof(int *));
}
/* Call changeArray function */
changeArray(d, array);
for(int i = 0; i < d; i++)
{
for(int j = 0; j < d; j++)
{
printf("%d ", array[i][j]);
}
printf("\n");
}
for(int count = 0; count < d; count++)
{
free(array[count]);
}
return 0;
}
void changeArray(int n, int *array[d])
{
for(int i =0; i < n; i++)
{
for(int j = 0; j < n; j++)
{
array[i][j] = i*j;
}
}
return;
}
What is the difference in using any of the two ways above to write this code?
[Not an answer, but an alternative approach to achieve the desired result, namely defining a user-defined 2D array.]
Assuming the compiler in use supports VLAs you could do this:
#include <stddef.h> /* for size_t */
void init_a(size_t x, size_t y, int a[x][y]); /* Order matters here!
1st give the dimensions, then the array. */
{
for (size_t i = 0; i < x; ++i)
{
for (size_t j = 0; j < y; ++j)
{
a[i][j] = (int) (i * j); /* or whatever values you need ... */
}
}
}
int main(void)
{
size_t x, y;
/* Read in x and y from where ever ... */
{
int a[x][y]; /* Define array of user specified size. */
init_a(x, y, a); /* "Initialise" the array's elements. */
...
}
}
It is actually pretty simple. All you have to do is this:
int i[][];
You are overthinking it. Same as a normal array, but has two indexes.
Let's say you want to create a "table" of 4 x 4. You will need to malloc space for 4 pointers, first. Each of those index points will contain a pointer which references the location in memory where your [sub] array begins (in this case, let's say the first pointer points to the location in memory where your first of four arrays is). Now this array needs to be malloc for 4 "spaces" (in this case, let's assume of type INT). (so array[0] = the first array) If you wanted to set the values 1, 2, 3, 4 within that array, you'd be specifying array[0][0], array[0][1], array[0][2], array[0][3]. This would then be repeated for the other 3 arrays that create this table.
Hope this helps!

Return array allocated by malloc

I have the code in main.c:
int main(void)
{
int* sudokuBoard = getBoard();
printBoard(sudokuBoard, 9);
return 1;
}
and also I have next code in another file:
int* getBoard()
{
int i;
int **Board = (int**)malloc(9 * sizeof(int*));
for (i = 0; i < 9; i++)
{
Board[i] = (int*)malloc(9 * sizeof(int));
}
int prototype[9][9] =
{
{ 0,0,1,0,0,0,0,0,9 },
{ 0,3,0,0,0,0,5,4,0 },
{ 0,0,0,0,0,0,0,0,0 },
{ 0,0,0,2,0,0,0,8,0 },
{ 2,0,0,0,6,7,0,0,0 },
{ 0,0,0,0,0,0,0,1,0 },
{ 0,9,0,0,0,0,0,0,0 },
{ 0,0,0,9,0,0,2,0,0 },
{ 0,0,0,0,4,0,0,0,0 },
};
for (i = 0; i < 9; i++)
{
Board[i] = prototype[i];
}
return &Board[0][0];
}
void printBoard(int* arr, int size)
{
int i, j;
printf("BOARD:\n");
for (i = 0; i < size; i++)
{
for (j = 0; j < size; j++)
{
printf("%d ", *(arr + i*size + j));
}
printf("\n");
}
printf("\n----------------\n");
}
Problem is when I try to print my array (there are strange numbers instead of array values). How can I create array in one function and return it to another and then print it?
In this loop
for (i = 0; i < 9; i++)
{
Board[i] = (int*)malloc(9 * sizeof(int));
}
there are allocated 9 extents of memory and pointers Board[i] are initialized by their addresses.
In this loop
for (i = 0; i < 9; i++)
{
Board[i] = prototype[i];
}
the pointers are reassigned. As result there are memory leaks in the function.
Moreover the pointers now point to elements of a local array and will be invalid after exiting the function.
Instead of reassigning the pointers you have to copy elements of the local array to the newly allocated arrays.
Also it is entirely unclear why you are trying to declare the function as having the return type int * instead of the correct return type int **.
Also as the sizes of the arrays are fixed you could to allocate one two-dimensional array like
int ( *Board )[9] = malloc( int[9][9] );
I've been trying to learn C the past couple of months, so I took a stab at taking your code and sprucing it up a bit and fixing your issue. I've left comments that explain the changes / fixes. Looks like others have already provided answers but I had fun working with your code. If anyone sees any issues in my code please let me know, would love to learn more!
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <stdint.h>
#include <inttypes.h>
#include <assert.h>
// Instead of hard coding the board size, we can let the getBoard function
// inform the caller the number of rows and columns. Also, we can use
// int8_t instead of int to ensure cross platform consistency
int8_t *getBoard(int8_t *rows, int8_t *cols) {
// Make sure the caller passed in what we need
assert(rows /* rows should not be NULL*/);
assert(cols /* cols should not be NULL*/);
*rows = 9;
*cols = 9;
int8_t prototype[9][9] = {
{ 0,0,1,0,0,0,0,0,9 },
{ 0,3,0,0,0,0,5,4,0 },
{ 0,0,0,0,0,0,0,0,0 },
{ 0,0,0,2,0,0,0,8,0 },
{ 2,0,0,0,6,7,0,0,0 },
{ 0,0,0,0,0,0,0,1,0 },
{ 0,9,0,0,0,0,0,0,0 },
{ 0,0,0,9,0,0,2,0,0 },
{ 0,0,0,0,4,0,0,0,0 },
};
int8_t *board = malloc(sizeof(prototype));
// Instead of iterating through the prototype we can memmove the contents
memmove(board, prototype, sizeof(prototype));
return board;
}
// Because we don't have the row and column count hardcoded anymore, we have to
// pass in the count to our print function.
void printBoard(int8_t *arr, int8_t rows, int8_t cols) {
// puts gives you the "\n" at the end "for free"
puts("BOARD:");
// We don't have to pre-declare our iterator variables anymore in modern C.
for (int8_t y = 0; y < rows; y++) {
for (int8_t x = 0; x < cols; x++) {
// Seperating out the pointer math makes it easier to look at
int8_t *column = arr + y * cols;
int8_t n = *(column + x);
// We can use the formatters provided by inttypes.h to again ensure consistency
printf("%" PRId8 " ", n);
}
printf("\n");
}
}
int main(int argc, const char * argv[]) {
// getBoard now gives us the counts of the board
int8_t rows = 0;
int8_t cols = 0;
int8_t* sudokuBoard = getBoard(&rows, &cols);
// We'll pass the counts into the print function
printBoard(sudokuBoard, rows, cols);
// Because getBoard malloc'd the board, we need to free it
free(sudokuBoard);
return 0;
}

how to return 2 dim char array from function in C

I have some C code that works as:
int main(void)
{
printf("Height: ");
int height;
do
{
height = get_int();
} while (height < 0 || height > 23);
char mtn[height][2*height+2];
for(int i = 0;i <height+1;i++){
for (int j = 0;j<2+height+3;j++){
mtn[i][j] = ' ';
}
}
}
but would like to make the double for loops a function, something like:
char space_mtn(int height);
int main(void)
{
printf("Height: ");
int height;
do
{
height = get_int();
} while (height < 0 || height > 23);
char mtn[height][2*height+2];
strcpy(mtn,space_mtn(height);
}
char space_mtn(int height){
char mtn[height][2*height+2];
for(int i = 0;i <height+1;i++){
for (int j = 0;j<2+height+3;j++){
mtn[i][j] = ' ';
}
}
}
but it's not working.
Arrays cannot be returned by value in C. One way is to pass the array as a parameter. (Array parameters are adjusted to pointers so that it appears as if the array has been passed by reference, so the function can modify the original array).
void space_mtn(int height, char mtn[height][2*height+2])
{
for(int i = 0;i < height;i++)
for (int j = 0; j < 2*height+2 ;j++){
mtn[i][j] = ' ';
}
int main(void)
{
// ...
char mtn[height][2*height+2];
space_mtn(height, mtn);
}
Note, I adjusted the loop bounds on your filler loop - they were nonsense and/or writing out of bounds.
Also, passing arrays of runtime bound to functions does not have compile-time bounds checking available of course -- so you need to take extra care that the bound in the parameter matches the array you are passing.

Return a 2d array from a function

I am a newbie to C.
I am trying to return a 2d array from a function.
It is something like this
int *MakeGridOfCounts(int Grid[][6])
{
int cGrid[6][6] = {{0, }, {0, }, {0, }, {0, }, {0, }, {0, }};
int (*p)[6] = cGrid;
return (int*)p;
}
I know this causes an error, need help. thanks
The C language has a basic flaw: it is impossible to return arrays from functions.
There are many workarounds for this; i'll describe three.
Replace by a pointer to an array
Return a pointer instead of an array itself. This leads to another problem in C: when a function returns a pointer to something, it should usually allocate the something dynamically. You should not forget to deallocate this later (when the array is not needed anymore).
typedef int (*pointer_to_array)[6][6];
pointer_to_array workaround1()
{
pointer_to_array result = malloc(sizeof(*result));
(*result)[0][0] = 0;
(*result)[1][0] = 0;
(*result)[2][0] = 0;
(*result)[3][0] = 0;
(*result)[4][0] = 0;
(*result)[5][0] = 0;
return result;
}
Replace by a pointer to int
A 2-D array appears just as a sequence of numbers in memory, so you can replace it by a pointer to first element. You clearly stated that you want to return an array, but your example code returns a pointer to int, so maybe you can change the rest of your code accordingly.
int *workaround2()
{
int temp[6][6] = {{0}}; // initializes a temporary array to zeros
int *result = malloc(sizeof(int) * 6 * 6); // allocates a one-dimensional array
memcpy(result, temp, sizeof(int) * 6 * 6); // copies stuff
return result; // cannot return an array but can return a pointer!
}
Wrap with a structure
It sounds silly, but functions can return structures even though they cannot return arrays! Even if the returned structure contains an array.
struct array_inside
{
int array[6][6];
};
struct array_inside workaround3()
{
struct array_inside result = {{{0}}};
return result;
}
It sounds like you want a function returning pointer to array[6] of int:
int (*makeGrid())[6]
{
return calloc(6*6,sizeof(int)); //zeros the memory as in your example.
}
You would call and use it like so:
int (*arr)[6] = makeGrid();
arr[4][3] = 3; //etc...
Try this out, compiles fine with GCC on my mac..
typedef struct _intGrid_t{
int **data;
int width;
int height;
} *IntGrid;
IntGrid makeGridWithSize(int width, int height);
IntGrid makeGridWithSize(int width, int height)
{
IntGrid grid = malloc(sizeof(struct _intGrid_t));
int **data = (int **) malloc(sizeof(int *) * width);
for (int i = 0; i < width; i++) {
data[i] = malloc(sizeof(int) * height);
memset(data[i], 0, sizeof(int) * height);
}
grid->data = data;
grid->width = width;
grid->height = height;
return grid;
}
void printGrid(IntGrid grid);
void printGrid(IntGrid grid)
{
printf(" { \n");
for (int i =0; i < grid->width; i++) {
printf(" { ");
for (int j = 0; j < grid->height; j++) {
printf("%i", grid->data[i][j]);
if (j != grid->height - 1)
{
printf(", ");
}
}
printf(" } \n");
}
printf(" } \n");
}
void freeGrid(IntGrid grid);
void freeGrid(IntGrid grid)
{
for (int i = 0; i < grid->width; i++) {
free(grid->data[i]);
}
free(grid->data);
free(grid);
}
int main (int argc, const char * argv[])
{
srand((int) time(NULL));
IntGrid grid = makeGridWithSize(10, 10);
for (int i = 0; i < grid->width; i++) {
for (int j = 0; j < grid->height; j++) {
grid->data[i][j] = rand() % 10;
}
}
printGrid(grid);
freeGrid(grid);
return 0;
}

Resources