Return a 2d array from a function - c

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;
}

Related

C, Segmentation fault while using dynamic array in struct

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 *.

No compile errors, issues with structs and 2D arrays, and I never reach my second print statement?

I'm new to C and trying to wrap my head around pointers, structs, and 2D arrays. Whenever I learn a new language, I try to write a small game in it.
I have a struct -- named Map -- which contains a pointer to a pointer to create a 2D array, and a function called createMap(), which should fill in the arrays with either 0's or 1's.
In my main() function, I have a few debug printf statements. The first one is fired, but the second one is not. I'm using the gcc compiler, and am not receiving any error messages.
What am I doing wrong?
The Map struct and the createMap() function:
typedef struct {
int x, y;
int **map;
} Map;
Map createMap(int size, int x, int y) {
Map m;
m.x = x;
m.y = y;
m.map = malloc(x * sizeof(int *));
for (int i=0; i<y; i++) {
m.map[i] = malloc(y * sizeof(int));
}
for (int i=0; i<x*y; i++) {
m.map[i][i] = randomInteger(i, 0, 1, 1);
}
return m;
}
The main() function:
int main() {
printf("Determining map size...");
int size, x, y;
x = 10;
y = 5;
if (x > y) {
size = x;
} else {
size = y;
}
Map map = createMap(size, x, y);
printf("Printing map...");
printMap(map);
for (int i=0; i<size;i++) {
free(map.map[i]);
}
return 0;
}
This code is wrong and invokes undefined behavior:
for (int i=0; i<x*y; i++) {
m.map[i][i] = randomInteger(i, 0, 1, 1);
}
It should be:
for (int i=0; i<x; i++) {
for (int j = 0; j<y; j++) {
m.map[i][j] = randomInteger(i*x+j, 0, 1, 1);
}
}
If you're using two dimensional arrays expect nested loops.
Also, you have a typo here:
for (int i=0; i<y; i++) {
m.map[i] = malloc(y * sizeof(int));
}
Should be
for (int i=0; i<x; i++) {
m.map[i] = malloc(y * sizeof(int));
}
That's i<x not i<y to agree with your allocation statement above.
In main you have some erroneous code here:
for (int i=0; i<size;i++) {
free(map.map[i]);
}
Should be
for (int i=0; i<x;i++) {
free(map.map[i]);
}
free(map.map);
to agree with your allocations.

Function to initialize two dimensional array

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 */

Why is my sorting method in qsort changing my array?

https://phoxis.org/2012/07/12/get-sorted-index-orderting-of-an-array/
I tried the method here under the section
Using qsort in C
to sort an array and return the indices, changing the array base_arr to be of type double*. However, when I print the arr[idx[i]] to the screen, half of the values have been changed to 0 and have been sorted as if they had always been 0. What could cause this to happen?
double *BASE_ARR;
int main(int argc, char *argv[]) {
int N = par->N;
int K = par->K;
double *ptr;
ptr = (double *) malloc(N*sizeof(ptr));
int *idx;
idx = (int *) malloc(N*sizeof(idx));
// generate the array to be sorted (ptr), in a separate file
for (int i = 0; i < N; i++) {
idx[i] = i;
}
BASE_ARR = ptr;
// sort
qsort(idx, N, sizeof(idx), idxSort);
for (int i = 0; i < N; i++) {
printf("%f\n",ptr[idx[i]]);
}
for (int i = 0; i < N; i++) {
printf("%d\n",idx[i]);
}
for (int i = 0; i < K; i++) {
idx[i] = -1;
}
return 0;
}
static int idxSort (const void *a, const void *b) {
int aa = *((int *)a), bb = *((int *)b);
if (BASE_ARR[aa] < BASE_ARR[bb]) {
return -1;
}
if (BASE_ARR[aa] == BASE_ARR[bb]) {
printf("what");tack
return 0;
}
if (BASE_ARR[aa] > BASE_ARR[bb]) {
return 1;
}
}
qsort(idx, N, sizeof(idx), idxSort);
should be
qsort(idx, N, sizeof(*idx), idxSort);
idx is a pointer. qsort doesn't need to know the size of a pointer; it needs to know the size of the array element.
Same about your malloc calls. You need to use sizeof(*idx) and sizeof(*ptr) in them. By the way, do not cast the result of malloc.

assigned value to dynamic array created in void function doesnt return the same value in main()

I have a problem with dynamic arrays in C. My program was working perfectly, but I was asked to put the creation of dynamic array into a seperate void. I did it, and it still worked great, but then I had to assign a value to a certain point of the created array in void, and make it return the said value, however, what I get is a random value. The function works by sending a pointer and the lenght of required array into void, and then makes the pointer into a dynamic array.
#include <stdio.h>
#include <stdlib.h>
#define MAX 255
void ieskom (int skaiciai[],int n, int *de, int *me, int *n1, int *n2)
{
int i = 0;
int j = 0;
int nr1 = 0;
int nr2 = 0;
int temp = 0;
int temp1 = 0;
int eile = 0;
int eile1 = 0;
int *did;
did = (int*)calloc(n,sizeof(int));
if (did==NULL)
{
printf("Nepriskirta atminties.");
exit(0);
}
int *maz;
maz = (int*)calloc(n,sizeof(int));
if (maz==NULL)
{
printf("Nepriskirta atminties.");
exit(0);
}
i = 0;
for (i = 0; i < n; i++)
{
if (skaiciai[i] < skaiciai[i+1])
{
did[j] = did[j] + 1;
if (did[j] > temp)
{
eile = j;
temp = did[j];
nr1 = i+1;
}
}
else
{
did[j] = did[j] + 1;
if (did[j] > temp)
{
eile = j;
temp = did[j];
nr1 = i+1;
}
j = j + 1;
}
}
j = 0;
for (i = 0; i < n; i++)
{
if (skaiciai[i] > skaiciai[i+1])
{
maz[j] = maz[j] + 1;
if (maz[j] > temp1)
{
eile1 = j;
temp1 = maz[j];
nr2 = i+1;
}
}
else
{
maz[j] = maz[j] + 1;
if (maz[j] > temp1)
{
eile1 = j;
temp1 = maz[j];
nr2 = i+1;
}
j = j + 1;
}
}
*de = did[eile];
*me = maz[eile1];
*n1 = nr1;
*n2 = nr2;
free(did);
free(maz);
}
/*int masyvas(x)
{
int y;
y = (int*)malloc(x*sizeof(int));
return y;
}*/
void *masyvas (int *skaiciai, int n)
{
*skaiciai = (int*)malloc(n*sizeof(int));
skaiciai[2] = 5;
return skaiciai;
}
int main()
{
int n1 = 0;
int n2 = 0;
int de = 0;
int me = 0;
int i = 0;
int n = 0;
int *skaiciai;
scanf("%d", &n);
// skaiciai = masyvas(n); // naudojant int
masyvas(&skaiciai, n);
printf("2 = %d", skaiciai[2]);
if (skaiciai==NULL)
{
printf("Nepriskirta atminties.");
exit(0);
}
for (;i < n; i++)
{
scanf("%d", &skaiciai[i]);
}
ieskom (skaiciai, n, &de, &me, &n1, &n2);
if (de > me)
{
printf("Elementu numeriai:");
printf(" %d", n1-de+1);
printf(" %d\n", n1);
printf("\nAtstumas tarp ju: %d", de-2);
}
else
{
printf("Elementu numeriai:");
printf(" %d", n2-me+1);
printf(" %d\n", n2);
printf("\nAtstumas tarp ju: %d", me-2);
}
free(skaiciai);
getchar();
getchar();
return 0;
}
The problem is in void masyvas and printf skaicia[2] - I assign a certain value to skaiciai[2], yet it prints a random one. How do I fix it?
EDIT: Thank you for your answers and explanations, it really helped me a lot! I know have solved my problem, and most importantly, I know why it was a problem in the first place.
First of all, you should translate variables and texts to english (your code lack of comments, this should apply to them too).
Next your masyvas() function returns a pointer to the allocated array (why void* ?!) but when you call it you don't get the returned value.
You have to choose: either you pass a pointer to your function (an array is a pointer, to if you want an array to be allocated from a function you have to pass a pointer to the pointer, so a int **), or you use the returned value.
Allocating with returned value:
// this function allocates a int* tab of size n and set one value
int *allocate_tab(int n) {
int *tmp;
tmp = malloc(n*sizeof(int));
if (tmp == NULL) {
return(NULL); // failed
}
tmp[2] = 5;
return(tmp);
}
// in main (or other function)
int *mytab;
mytab = alloc_tab(45);
Allocating by passing a pointer to the array:
void alloc_tab(int **tab, int n) {
*tab = malloc(n*sizeof(int));
if (*tab == NULL) {
return;
}
(*tab)[2] = 5;
}
// in main (or other)
int *mytab;
alloc_tab(&mytab, 45);
If you can't understand this stuff I guess you should read more about memory, allocation and pointers.
You need to pass a pointer-to-pointer here and do not need to return anything.
void masyvas (int **skaiciai, int n)
{
*skaiciai = (int*)malloc(n*sizeof(int));
(*skaiciai)[2] = 5;
}
When you declare int *skaiciai, the variable is a pointer to type int. skaiciai holds the address that points to an int. When you pass &skaiciai, you're passing the address of the address that points to an int. So because this is an address of an address, its a double pointer.

Resources