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;
}
Related
I am trying to make a program that first creates an array in another function, returns it and then calls another function that shuffles the contents of the array and returns it. However I am struggling to do this in C since I do not quite understand the array pointer system that has to be used here.
So far my code doesnt return the values 1-20 from makeArray() but instead returns an array full of 0s and I have a feeling it has to do with the c's array pointer system.
Any help would greatly be appreciated! Thank you in advance
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int arrShuffle();
int arrShuffle(int * arr) {
int arr[21];
// shuffle array
for(int j=0; j<20; j++) {
int randInd = (rand() % 20) + 1;
int temp = arr[j];
arr[j] = arr[randInd];
arr[randInd] = temp;
}
return arr;
}
int makeArray() {
int arr[21];
// make array of 1-20
for(int i=0; i < 20; i++) {
arr[i] = i + 1;
}
return arr;
}
void main() {
int *orgArr;
int *modArr;
srand(time(NULL));
orgArr = makeArray();
for(int i=0; i < 20; i++) {
printf("OrgArr: %d\n", orgArr);
}
modArr = arrShuffle(orgArr);
}
You cannot use variables with automatic storage (aka local ones). You must allocate the array so the memory remains valid after the function ends:
int* makeArray() {
int *arr = calloc(21, sizeof *a);
// make array of 1-20
for(int i=0; i < 20; i++) {
arr[i] = i + 1;
}
return arr;
}
Remember to release the array when it is no longer used:
int main() {
int *orgArr;
...
orgArr = makeArray();
...
free(orgArr);
}
As tstanisl pointed out in their answer, a possible solution is to use dynamic memory allocation. My answer, instead, will give you yet another solution: using an array passed by the caller.
NOTE: both solutions are valid and their usefulness depends on the specific needs of your program. There's no "right" universal solution.
void makeArray(int arr[], size_t len) {
for (size_t i = 0; i < len; i += 1) {
arr[i] = (int) (i + 1);
}
}
void cloneAndModifyArray(const int orig[], int new[], size_t len) {
for (size_t i = 0; i < len; i += 1) {
new[i] = orig[i] * 2; // or some other modification
}
}
And you use it like this:
#define ARR_LEN (100)
int main(void) {
int arr[ARR_LEN];
makeArray(arr, ARR_LEN);
int modified_arr[ARR_LEN];
cloneAndModifyArray(arr, modified_arr, ARR_LEN);
return 0;
}
I'm trying to add new element to dynamic array in C (I know that I must free all memory. I will do it later), but I get this error every time:
But, what is strange, if I compile from terminal, like that, code works properly.
So, where is the error and how i can beat it?
Thank you!
All my code:
main.c
#include <stdio.h>
#include <stdlib.h>
typedef struct vector
{
int size;
int *array;
int alreadyIn;
}vector;
vector *vectorInit(int size)
{
vector *newVec = (vector *)malloc(sizeof(vector));
if(!newVec){printf("No memory!\n"); return NULL;}
newVec->size = size;
newVec->array = (int *)malloc(size * sizeof(int));
return newVec;
}
void allocNewMemory(vector *vect, int howMuch)
{
vect->array = (int *)realloc(vect->array ,(vect->size + howMuch) * sizeof(int));
vect->size += howMuch;
}
void pushBack(vector *vect, int number)
{
int howMuch = 5;
if(vect && vect->alreadyIn < vect->size)
{
vect->array[vect->alreadyIn] = number;
vect->alreadyIn++;
}
else
{
printf("Alloc new memory for %d elements...\n", howMuch);
allocNewMemory(vect, howMuch);
pushBack(vect, number);
}
}
void printVector(vector *vect)
{
for (int i = 0; i < vect->alreadyIn; i++)
{
printf("%d ", vect->array[i]);
}
printf("\n");
}
int main()
{
int startSize = 4;
vector * vec = vectorInit(startSize);
for (int i = 0; i < 6; i++)
{
pushBack(vec, i+1);
}
printVector(vec);
return 0;
}
You never initialize the alreadyIn member in the structure. That means its value will be indeterminate (and seemingly garbage or random).
You need to explicitly initialize it to zero:
vector *vectorInit(int size)
{
vector *newVec = malloc(sizeof(vector));
if(!newVec)
{
printf("No memory!\n");
return NULL;
}
newVec->size = size;
newVec->array = malloc(size * sizeof(int));
newVec->alreadyIn = 0; // Remember to set this to zero
return newVec;
}
This problem should have been easy to detect in the debugger.
Also note that I removed the casts from malloc. One should not cast the result of malloc, or really any function returning void *.
I have a c program in which I want to initialize a 2 dimensional array.
So I made this function :
void initLayer(int **layer, int *dimensions) {
printf("initLayer\n");
layer = malloc(sizeof(int*) * dimensions[0]);
for (int i = 0; i < dimensions[0]; i++) {
layer[i] = malloc(sizeof(int) * dimensions[1]);
}
}
When I use this function there is no problem, but when I try to read the 2D array later I always get a segmentation fault.
I think it may be because the initialization made in the function are not saved when its finished.
Do you know how I could correct my function ? Thank you in advance.
To passing pointer to function you need one more pointer.
int **matrix; is an array of arrays, so to fill it you need to pass it as a pointer, which is int ***layer. but it is weird.
also for changing data by pointer you need to add a star * before it. *layer = ...
#include <stdlib.h>
void initLayer(int ***layer, int *dimensions)
{
*layer = malloc(sizeof(int *) * dimensions[0]);
for (int i = 0; i < dimensions[0]; i++)
{
*(*layer + i) = malloc(sizeof(int) * dimensions[1]);
}
}
int main()
{
int **matrix;
int dimensions[2] = { 4, 6 };
initLayer(&matrix, dimensions);
// then do whatever you want
for (int i = 0; i < dimensions[0]; i++)
{
for (int j = 0; j < dimensions[1]; j++)
{
matrix[i][j] = i * j;
}
}
}
as for me, better to use typedef to make code more readable:
#include <stdlib.h>
typedef int * Array;
typedef int ** Matrix;
void initLayer(Matrix *layer, Array dimensions)
{
*layer = malloc(sizeof(Array) * dimensions[0]);
for (int i = 0; i < dimensions[0]; i++)
{
(*layer)[i] = malloc(sizeof(int) * dimensions[1]);
}
}
int main()
{
Matrix matrix;
int dimensions[2] = { 4, 6 };
initLayer(&matrix, dimensions);
// then do whatever you want
for (int i = 0; i < dimensions[0]; i++)
{
for (int j = 0; j < dimensions[1]; j++)
{
matrix[i][j] = i * j;
}
}
}
When you call the function, the int **layer pointer is copied. So, when you do layer = malloc(...) what actually happens is the function sets its local copy to the malloc result. What you want is to mutate the variable which you called the function with. You can do this by taking a int ***layer and passing in &layer when calling initLayer. Note that you must then use *layer instead of layer in your code.
You have two approaches here:
to pass a reference to the double pointer (***int in this case)
or to return the allocated pointer as the result of your function:
in the first case:
void initLayer(int ***layer, int *dimensions) {
printf("initLayer\n");
*layer = malloc(sizeof(int*) * dimensions[0]);
for (int i = 0; i < dimensions[0]; i++) {
layer[i] = malloc(sizeof(int) * dimensions[1]);
}
}
you pass a reference to a pointer, instead of passing the (uninitialized) pointer. Remember, in C, all parameters are passed by value. In this case, you can call your function as:
...
int**vector;
...
initLayer(&vector, dims); /* you pass the address of your double pointer */
In the second case:
int** initLayer(int *dimensions) {
printf("initLayer\n");
int **layer = malloc(sizeof(int*) * dimensions[0]);
for (int i = 0; i < dimensions[0]; i++) {
layer[i] = malloc(sizeof(int) * dimensions[1]);
}
return layer;
}
in this case, you call it as:
...
int**vector;
...
vector = initLayer(dims); /* you receive your double pointer as a return value */
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].
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;
}