Can't allocate memory for triple pointer - arrays

I'm doing a project for school and I have a problem and I can't figure out how to solve it. I'm trying to allocate memory for a triple pointer in a function that I will be able to use it as a 2D array, save data and then use it in a different function. But for some reason I can't use the data once I'm out of the function.
BTW I have to use the variables that is writing in the function (float m1[ROWS][COLS], float m2[ROWS][COLS], float ***C).
int mat_mul(float m1[ROWS][COLS], float m2[ROWS][COLS], float ***C)
{
int i, j, k;
C = (float ***)malloc(sizeof(float*) * 3);
for (i = 0; i < 3; i++) {
C[i] = (float **)malloc(sizeof(float*) * 3);
for (j = 0; j < 3; j++) {
C[i][j] = (float *)malloc(sizeof(float) *3);
}
}
for (i = 0; i < ROWS; i++) {
for (j = 0; j < COLS; j++) {
(*C)[i][j] = 0;
for (k = 0; k < ROWS; k++) {
(*C)[i][j] += m1[i][k] * m2[k][j];
}
}
}
printf_s("%.1f\n", (*C)[0][0]);
}
int i,j;
float Results[ROWS][COLS];
float Angle1[6], Angle2[6];
Angle_Reader("data_q.csv", &Angle1, &Angle2);
Angle_Converter(&Angle1, &Angle2);
for (i = 0; i < 1; i++) {
float Matrix1[ROWS][COLS] = { {cos(Angle1[i]),-sin(Angle1[i]),L1*cos(Angle1[i])},{sin(Angle1[i]),cos(Angle1[i]),L1*sin(Angle1[i])},{0,0,1} };
float Matrix2[ROWS][COLS] = { {cos(Angle2[i]),-sin(Angle2[i]),L2*cos(Angle2[i])},{sin(Angle2[i]),cos(Angle2[i]),L2*sin(Angle2[i])},{0,0,1} };
mat_mul(&Matrix1, &Matrix2, &Results);
}
printf_s("\n");
printf_s("%.1f\n", Results[0][0]);

This:
for (i = 0; i < 1; i++) {
float Matrix1[ROWS][COLS] = { {cos(Angle1[i]),-sin(Angle1[i]),L1*cos(Angle1[i])},{sin(Angle1[i]),cos(Angle1[i]),L1*sin(Angle1[i])},{0,0,1} };
float Matrix2[ROWS][COLS] = { {cos(Angle2[i]),-sin(Angle2[i]),L2*cos(Angle2[i])},{sin(Angle2[i]),cos(Angle2[i]),L2*sin(Angle2[i])},{0,0,1} };
mat_mul(&Matrix1, &Matrix2, &Results);
}
Should not be in a loop as is.
Either move the declaration above the loop, then in the loop, use index values ( i.e. Matrix2[i][j] ) instead of ROWS, COLS,
float Matrix1[ROWS][COLS] = {0};
float Matrix2[ROWS][COLS] = {0};
//Note: these initializers work only for 3x3 array
//Forcing ROWS == 3 and COLS == 3
float data1[ROWS][COLS] = { {cos(Angle1[0]),-sin(Angle1[1]),L1*cos(Angle1[2])},{sin(Angle1[0]),cos(Angle1[1]),L1*sin(Angle1[2])},{0,0,1} };
float data2[ROWS][COLS] = { {cos(Angle2[0]),-sin(Angle2[1]),L2*cos(Angle2[2])},{sin(Angle2[0]),cos(Angle2[1]),L2*sin(Angle2[2])},{0,0,1} };
...
if(Results)
{
for (i = 0; i < 1; i++)
{
Matrix1[i][j] = data1[i][j];
Matrix2[i][j] = data2[i][j];
...
mat_mul(&Matrix1, &Matrix2, &Results);
}
...or remove the for loop altogether and modify the i and j indexes from Angle1[i] to hard-coded values eg: Angle1[0], Angle1[1],... so that the initializers will populate the 2D arrays.
float Matrix1[ROWS][COLS] = { {cos(Angle1[0]),-sin(Angle1[1]),L1*cos(Angle1[2])},{sin(Angle1[0]),cos(Angle1[1]),L1*sin(Angle1[2])},{0,0,1} };
float Matrix2[ROWS][COLS] = { {cos(Angle2[0]),-sin(Angle2[1]),L2*cos(Angle2[2])},{sin(Angle2[0]),cos(Angle2[1]),L2*sin(Angle2[2])},{0,0,1} };
mat_mul(&Matrix1, &Matrix2, &Results);
Regarding creating memory, Nothing in your code indicates the need for a 3D array. As stated in comments, the reason for float ***C in the mat_mul(., ., float ***C) function prototype is to accommodate passing the address of a 2D matrix ( eg. &Results ), when calling function so that it can be modified. Even then, it would be an improvement to move the logic necessary to create the memory for that variable into its own function, and allocate the memory before it is passed as a variable:
float **Results = Create2D(COLS, ROWS);
if(Results)
{
for (i = 0; i < 1; i++)
{
...
...
mat_mul(&Matrix1, &Matrix2, &Results);
}
//When finished using, free Results
free2D(Results, COLS)
The functions Create2D() and its companion could be implemented as:
float ** Create2D(int c, int r)
{
float **arr;
int y;
arr = calloc(c, sizeof(float *));
for(y=0;y<c;y++)
{
arr[y] = calloc(r, sizeof(float));
}
return arr;
}
void free2D(float **arr, int c)
{
int i;
for(i=0;i<c;i++)
{
free(arr[i]);
}
free(arr);
}

Related

2D array is used uninitialized in this function

I'm getting a warning:
matrixResult' is used uninitialized in this function [-Wuninitialized]
in this function:
int **addMatrices(int **matrixA, int **matrixB, int *rows, int *cols) {
int **matrixResult = initializeMatrix(matrixResult, rows, cols);
for (int i = 0; i < *rows; i++)
for (int j = 0; j < *cols; j++)
matrixResult[i][j] = matrixA[i][j] + matrixB[i][j];
return matrixResult;
}
But its is getting initialized here:
int **initializeMatrix(int **matrix, int *rows, int *cols) {
matrix = (int **)malloc((*rows) * sizeof(int*));
checkNullPointer(matrix);
for(int i = 0; i < *rows; i++) {
matrix[i] = (int *)calloc(*cols, sizeof(int));
}
return matrix;
}
isn't it? I was trying to find an answer, but everyone just says that 2D array needs to get allocated . But I think that it gets in my code. Anyone has a clue what's going on in here?
You have passed the uninitialised pointer, unnecessarily, and used it as a local variable. If you remove that and use a true local variable, like this:
int **initializeMatrix(int *rows, int *cols) {
int **matrix = malloc((*rows) * sizeof(int*));
checkNullPointer(matrix);
for(int i = 0; i < *rows; i++) {
matrix[i] = calloc(*cols, sizeof(int));
}
return matrix;
}
int **addMatrices(int **matrixA, int **matrixB, int *rows, int *cols) {
int **matrixResult = initializeMatrix(rows, cols);
for (int i = 0; i < *rows; i++)
for (int j = 0; j < *cols; j++)
matrixResult[i][j] = matrixA[i][j] + matrixB[i][j];
return matrixResult;
}
then the warning should go away.
Aside: I also removed the unnecessary casts.

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.

return a fixed size array in c

I would like a function to return an array, or a pointer to an array, in either c or c++, that does something like the following:
double[][] copy(double b[][], int mx, int my, int nx, int ny)
{
double[nx][ny] a;
int i,j;
for(i = mx; i<= nx; ++i)
for(j = my; j<= ny; ++j)
a[i][j] = b[i][j];
return a;
}
void main(void){
double A[2][3];
double B[2][3] = {{1,2}{3,4}{5,6}};
A = copy(B,0,0,1,2);
}
This is the proper method for returning an array from a function is as follows:
#define NUM_ROWS (5)
#define NUM_COLS (3)
char **createCharArray(void)
{
char **charArray = malloc(NUM_ROWS * sizeof(*charArray));
for(int row = 0; row < NUM_ROWS; row++)
charArray[row] = malloc(NUM_COLS * sizeof(**charArray));
return charArray;
}
In this example, the above function can be called like this:
char **newCharArray = createCharArray();
newCharArray can now be used:
char ch = 'a';
for(int row = 0; row < NUM_ROWS; row++)
for(int col = 0; col < NUM_COLS; col++)
newCharArray[row][col] = ch++;
An array can be passed as an argument to function similarly:
void freeCharArray(char **charArr)
{
for(int row = 0; row < NUM_ROWS; row++)
free(charArr[row]);
free(charArr);
}
You can return the double ** from your copy function like this.
double ** copy(double *src, int row, int col)
{
// first allocate the array with required size
double **copiedArr = (double **) malloc(sizeof(double *)*row);
for(int i=0;i<row;i++)
{
// create space for the inner array
*(copiedArr+i) = (double *) malloc(sizeof(double)*col);
for(int j=0; j<col; j++)
{
// copy the values from source to destination.
*(*(copiedArr+i)+j) = (*(src+i+j));
}
}
// return the newly allocated array.
return copiedArr;
}
call to this function is done like this.
double src[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
double **dest = copy(&src[0][0],3,3); //here is your new array
Here you have to assign returned value of copy() to double** not to double[][].
If you try to assign the returned value to array then it will generate "Incompatible types" error (detail).
As memory allocated to copiedArray on the heap so you have to take responsibility to clear the memory.
void freemem(double **mem, int row)
{
for(int i=0;i<row; i++)
{
free(*(mem+i));
}
free(mem);
}
I also want to point out some correction in your sample code:
return type of main should be int.
one should put the return statement at the end of main.
you can't return the stack allocated value, it is cause of crash
in most of cases.

2D Dynamic Array Allocation and Passing by Reference in C

Can someone wiser than I please explain to me why the following code segment faults? There is no problem allocating the memory by reference, but as soon as I try to assign anything or free by reference, segfault occurs.
I'm sure I'm missing some fundamental concept about pointers and passing by reference, hopefully some light can be shed.
#include <stdlib.h>
#include <stdio.h>
void allocateMatrix(float ***);
void fillMatrix(float ***);
void freeMatrix(float **);
int main() {
float **matrix;
allocateMatrix(&matrix); // this function calls and returns OK
fillMatrix(&matrix); // this function will segfault
freeMatrix(matrix); // this function will segfault
exit(0);
}
void allocateMatrix(float ***m) {
int i;
m = malloc(2*sizeof(float*));
for (i = 0; i < 2; i++) {
m[i] = malloc(2*sizeof(float));
}
return;
}
void fillMatrix(float ***m) {
int i,j;
for (i = 0; i < 2; i++) {
for (j = 0; j < 2; j++) {
(*m)[i][j] = 1.0; // SEGFAULT
}
}
return;
}
void freeMatrix(float **m) {
int i;
for (i = 0; i < 2; i++) {
free(m[i]); // SEGFAULT
}
free(m);
return;
}
One set of problems is here:
void allocateMatrix(float ***m) {
int i;
m = malloc(2*sizeof(float*));
for (i = 0; i < 2; i++) {
m[i] = malloc(2*sizeof(float));
}
return;
}
You need to assign to *m to get the information back to the calling code, and also you will need to allocate to (*m)[i] in the loop.
void allocateMatrix(float ***m)
{
*m = malloc(2*sizeof(float*));
for (int i = 0; i < 2; i++)
(*m)[i] = malloc(2*sizeof(float));
}
There's at least a chance that the other functions are OK. The fillMatrix() is written and invoked correctly, though it could be simplified by losing the third * from the pointer:
void fillMatrix(float **m)
{
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
m[i][j] = 1.0;
}
}
It might be advisable to pass the triple-pointer to freeMatrix() so that you can zero the pointer in the calling function:
void freeMatrix(float ***m)
{
for (int i = 0; i < 2; i++)
free((*m)[i]);
free(*m);
*m = 0;
}
Calling then becomes:
allocateMatrix(&matrix);
fillMatrix(matrix);
freeMatrix(&matrix);
Good use of indirection. Just try to be consistent with format. It improves readability and reduces errors. e.g.
function calls:
allocateMatrix &matrix
fillMatrix &matrix
freeMatrix &matrix
declarations
void allocateMatrix float ***m
void fillMatrix float ***m
void freeMatrix float ***m
handling
(*m)[i] = malloc(2 * sizeof(float))
(*m)[i][j] = 1.0
free (*m)[i]
Returning of pointer from your function is probably the better way to allocate memory:
float **allocateMatrix() {
int i;
float **m;
m = malloc(2*sizeof(float *));
for (i = 0; i < 2; i++) {
m[i] = malloc(2*sizeof(float));
}
return m;
}
int main() {
float **m;
m = allocateMatrix();
/* do other things
fillMatrix(matrix);
freeMatrix(&matrix);
*/
}

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