Array of Matrices with Different sizes in C - c

I am trying to make an array of say 3 matrices with different sizes:
Array ={ {{1, 2, 3}, {10, 20, 30}},
{{4, 5}, {40, 50}, {400, 500}},
{{6, 7}, {60, 70}} };
I need to use array indexing rather than pointer arithmetic for my codes.
I think I should create a 1-d array containing 3 pointers to matrices. Something like:
{ *ptr1[3], *ptr2[2], *ptr3[2]}
But how can I declare such an object? Also how can I assign values to that?
I am readying the actual data from a binary file using fread.
Thank you,

Jagged array is array of arrays such that member arrays can be of different sizes, i.e., we can create a 2-D array but with a variable number of columns in each row.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int Mat1row0[3] = { 1, 2, 3};
int Mat1row1[3] = {10, 20, 30};
int Mat2row0[2] = {4, 5};
int Mat2row1[2] = {40, 50};
int Mat2row2[2] = {400, 500};
int Mat3row0[2] = {6, 7};
int Mat3row1[2] = {60, 70};
int* jagged1[2] = {Mat1row0, Mat1row1 };
int* jagged2[3] = {Mat2row0, Mat2row1, Mat2row2};
int* jagged3[2] = {Mat3row0, Mat3row1 };
int** jaggedkk[3] = {jagged1, jagged2, jagged3};
printf("%d",jaggedkk[0][0][0]);
return 0;
}
The output is : 1

You could create a struct to represent a matrix and then create an array of that struct. Further, you would need a function for initializing a matrix (i.e. allocate memory) and also a function for deleting a matrix (i.e. free allocated memory).
Something like:
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
size_t rows;
size_t columns;
int **data;
} Matrix;
void initMatrix(size_t rows, size_t columns, Matrix *m)
{
if (rows == 0 || columns == 0) exit(1); // error
// Allocate row pointers
m->data = malloc(rows * sizeof m->data[0]);
if (m->data == NULL) exit(1); // error
// Allocate data area, i.e. rows x columns ints
m->data[0] = malloc(rows * columns * sizeof m->data[0][0]);
if (m->data[0] == NULL) exit(1); // error
// Initialize the remaining row pointers
for (size_t i=1; i < rows; ++i)
{
m->data[i] = m->data[0] + i * columns;
}
m->rows = rows;
m->columns = columns;
}
void deleteMatrix(Matrix *m)
{
free(m->data[0]);
free(m->data);
m->rows = 0;
m->columns = 0;
m->data = NULL;
}
void printMatrix(Matrix *m)
{
printf("---------------------------\n");
printf("rows=%zu columns=%zu\n", m->rows, m->columns);
for (size_t i=0; i < m->rows; ++i)
{
printf("row[%zu] at %p\t", i, (void*)m->data[i]);
for (size_t j=0; j < m->columns; ++j)
{
printf("%d\t", m->data[i][j]);
}
printf("\n");
}
printf("---------------------------\n");
}
int main(void)
{
Matrix m[2];
initMatrix(2, 5, &m[0]);
for(size_t i=0; i < 2; ++i)
{
for(size_t j=0; j < 5; ++j)
{
m[0].data[i][j] = 10*i + j;
}
}
initMatrix(3, 2, &m[1]);
for(size_t i=0; i < 3; ++i)
{
for(size_t j=0; j < 2; ++j)
{
m[1].data[i][j] = 100 + 10*i + j;
}
}
for(size_t i=0; i < 2; ++i)
{
printMatrix(&m[i]);
}
for(size_t i=0; i < 2; ++i)
{
deleteMatrix(&m[i]);
}
return 0;
}
Possible output:
---------------------------
rows=2 columns=5
row[0] at 0x1979030 0 1 2 3 4
row[1] at 0x1979044 10 11 12 13 14
---------------------------
---------------------------
rows=3 columns=2
row[0] at 0x1979080 100 101
row[1] at 0x1979088 110 111
row[2] at 0x1979090 120 121
---------------------------

A 'short/simple' solution could be just to write:
int *** Array =(int**[]){ (int*[]){(int[]){1, 2, 3}, (int[]){10, 20, 30}},
(int*[]){(int[]){4, 5}, (int[]){40, 50}, (int[]){400, 500}},
(int*[]){(int[]){6, 7}, (int[]){60, 70}} };
Now Array[0][0][0] will be 1, Array[2][1][1] will be 70, etc;
If you need to do it dynamically, you can do it the following way:
int *** Array;
Array = malloc(sizeof(int**)*3);
Array[0] = malloc(sizeof(int*)*2);
Array[0][0] = malloc(sizeof(int)*3);
Array[0][0][0] = 1;
...
(and so on)

Related

Printing a matrix causes a segmentation fault

I tried to print a matrix based on this code but somehow it causes a segmentation fault.
I want to transfer the given arrays to the struct member data and then print them out by referecing to data.
I scanned through it but I cannot find my mistake. Maybe I messed up when allocating memory for the structure.
#include "base.h"
struct Matrix {
int rows; // number of rows
int cols; // number of columns
double** data; // a pointer to an array of n_rows pointers to rows; a row is an array of n_cols doubles
};
typedef struct Matrix Matrix;
Matrix* make_matrix(int n_rows, int n_cols) {
Matrix* mat = xcalloc(n_rows,sizeof(double*));
mat->rows = n_rows;
mat->cols = n_cols;
return mat;
}
Matrix* copy_matrix(double* data, int n_rows, int n_cols) {
Matrix* mat = make_matrix(n_rows, n_cols);
for(int i = 0; i < (mat->rows); i++)
{
for(int j = 0; j < (mat->cols); j++)
{
mat->data[i][j] = data[i] + j;
}
}
return mat;
}
void print_matrix(Matrix* m)
{
for(int i = 0; i < (m->rows); i++)
{
for(int j = 0; j < (m->cols); j++)
{
printf("%g", m->data[i][j]);
}
}
}
void matrix_test(void) {
double a[] = {
1, 2, 3,
4, 5, 6,
7, 8, 9 };
Matrix* m1 = copy_matrix(a, 3, 3);
print_matrix(m1);
double a2[] = {
1, 2, 3,
4, 5, 6 };
Matrix* m2 = copy_matrix(a2, 2, 3);
print_matrix(m2);
double a3[] = {
1, 2,
3, 4,
5, 6 };
Matrix* m3 = copy_matrix(a3, 3, 2);
print_matrix(m3);
}
In this particular example, there is no obvious reason why you should allocate the struct itself dynamically, since it's just 3 items. Because this is plain wrong:
Matrix* mat = xcalloc(n_rows,sizeof(double*));
Either you have to allocate room for the struct and its pointer array separately, or you can just skip dynamic allocation of the struct and then only allocate room for the data member.
Furthermore xcalloc(n_rows,sizeof(double*)); only allocates room for an array of pointers, not what those pointers point at. So you need to allocate room for each data item too, in a separate loop.
Furthermore, using a pointer array for a matrix is almost certainly needlessly obscure and inefficient practice. Instead you should use a 2D array as shown here: Correctly allocating multi-dimensional arrays
You should also free() all memory that you allocated.
Here is a cleaned up example where I replaced the pointer to pointer with a so-called "flexible array member". This has the advantage of allocating the struct together with the data for faster access. Also all the problems with fragmented allocation will be gone.
The down side is that a flexible array member has to to be regarded as a flat 1D array, so we have to cast to a pointer to 2D array type before using it with array[i][j] syntax.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
size_t rows;
size_t cols;
double data[];
} Matrix;
Matrix* make_matrix (size_t n_rows, size_t n_cols) {
Matrix* mat = malloc(sizeof(Matrix) + sizeof(double[n_rows][n_cols]));
if(mat == NULL)
{
return NULL;
}
mat->rows = n_rows;
mat->cols = n_cols;
return mat;
}
Matrix* copy_matrix (const double* data, size_t n_rows, size_t n_cols) {
Matrix* mat = make_matrix(n_rows, n_cols);
double (*new_data)[mat->cols];
new_data = (double(*)[mat->cols]) mat->data;
for(size_t i = 0; i < mat->rows; i++)
{
for(size_t j = 0; j < mat->cols; j++)
{
new_data[i][j] = data[i] + j;
}
}
return mat;
}
void print_matrix (const Matrix* mat)
{
double (*data)[mat->cols];
data = (double(*)[mat->cols]) mat->data;
for(size_t i = 0; i < mat->rows; i++)
{
for(size_t j = 0; j < mat->cols; j++)
{
printf("%g ", data[i][j]);
}
printf("\n");
}
}
int main (void) {
double a[] = {
1, 2, 3,
4, 5, 6,
7, 8, 9 };
Matrix* m1 = copy_matrix(a, 3, 3);
print_matrix(m1);
puts("");
double a2[] = {
1, 2, 3,
4, 5, 6 };
Matrix* m2 = copy_matrix(a2, 2, 3);
print_matrix(m2);
puts("");
double a3[] = {
1, 2,
3, 4,
5, 6 };
Matrix* m3 = copy_matrix(a3, 3, 2);
print_matrix(m3);
free(m1);
free(m2);
free(m3);
}

pointer to pointer as 2d array

My background is Java therefore I'm not used to pointers, the following code throws error and I can't see way:
#include <stdio.h>
#define DIM 2
void sort_intervals(int** intervals, int n);
int main()
{
int a[3][DIM] = {
{1, 6} ,
{4, 9} ,
{3,17} };
sort_intervals(a, 3);
return 0;
}
void sort_intervals(int** intervals, int n)
{
printf("%d ", intervals[0][0]);//<--- error here
}
Error: Access violation reading location
I'm not allowed to change the function signiture
Then you need an array of pointers that point to arrays.
int a_1[DIM] = {1, 6};
int a_2[DIM] = { ... };
int a_3[DIM] = { ... };
int *a[3] = { a_1, a_2, a_3, }; // array of 3 pointers
sort_intervals(a, 3);
or exactly equivalent using compound literals you can:
int *a[3] = { (int[DIM]){1, 6}, (int[DIM]){2, 7}, (int[DIM]){3, 17}};
sort_intervals(a, 3);
even:
sort_intervals((int*[3]){
(int[DIM]){1, 6},
(int[DIM]){2, 7},
(int[DIM]){3, 17},
}, 3);
I am assuming you can change main function.
You could also initialize a as double pointer such as:
int **a = (int**)calloc(3, sizeof(int*)); //setting a as array of 3 pointers
for (int i = 0; i < 3; i++)
*a = (int*) calloc(DIM, sizeof(int)); //assigning pointer to a[0], a[1] and a[2]
Here a is array of 3 integer pointers. a[0],a[1] and a[2] are int pointers.
You can modify a as a[0][0] = 5;
If you can't change the signature as you explained in your comment, then you can get it done using a jagged array:
#define DIM 2
void sort_intervals(int** intervals, int n);
int main()
{
int **a = malloc(3 * sizeof(int*));
for (int i = 0; i < 3; i++) {
a[i] = malloc(DIM * sizeof(int));
}
a[0][0] = 1; a[0][1] = 6;
a[1][0] = 4; a[1][1] = 9;
a[2][0] = 3; a[2][1] = 17;
sort_intervals(a, 3);
for (int i = 0; i < 3; i++) {
free(a[i]);
}
free(a);
return 0;
}
void sort_intervals(int** intervals, int n)
{
printf("%d ", intervals[2][0]);//<--- error here
}

Transpose Matrix Using Pointer in C

I was doing the assignment to use pointer to transpose matrices. My code can successfully transpose the first row of the matrix but fail to transpose other rows and columns. I suspect there's some problems with for loops but I cannot find where the problem is. The following attached is my code.
void transposeMatrix(int matrix[ROWS][COLS]){
int** transpose=(int **)malloc(ROWS*sizeof(int*));
for(int i=0; i< ROWS; i++)
transpose[i]=(int*)malloc(COLS*sizeof(int));
for(int i=0; i<ROWS;i++){
puts("");
for(int j=0; j<COLS;j++){
*(transpose+i*ROWS+j)= *(matrix+j*COLS+i);
printf("%d ",transpose[j][i]);
}
puts("");
}
}
The matrix generates random numbers and the problems looks like this:
Original Matrix:
10 20 30
40 50 60
70 80 90
Transpose Matrix:
10 0 43009213
20 3401401 910429
30 0 134910124
I cannot attach the image so the above is just an elaboration of the problem I faced, the real situation is not exactly like that but very similar.
Thank you for your help!
*(transpose+i*ROWS+j) is not the correct way to access elements of an array of pointers. That's the way to access a 2-dimensional array that's stored contiguously in row-major order in an int[] array or through an int* pointer.
The way to access an element of a 2-dimensional array that's implemented as an array of pointers is with *(*(transpose + i)+j). *(transpose + i) returns the pointer to row i, adding j to that returns the address of the j'th column in the row, and deferencing that gets or sets the value.
This will also work with an array declared as
int matrix[ROWS][COLS];
because of the way arrays decay to pointers.
So your assignment line should be:
*(*(transpose + i)+j) = *(*(matrix + j)+i);
Then you need to change the printf() line, because it's not printing the same element you just assigned. It should be:
printf("%d ", transpose[i][j]);
The full working function is:
void transposeMatrix(int matrix[ROWS][COLS]){
int** transpose=(int **)malloc(ROWS*sizeof(int*));
for(int i=0; i< ROWS; i++)
transpose[i]=(int*)malloc(COLS*sizeof(int));
for(int i=0; i<ROWS;i++){
puts("");
for(int j=0; j<COLS;j++){
*(*(transpose + i)+j) = *(*(matrix + j)+i);
printf("%d ",transpose[i][j]);
}
puts("");
}
}
You have problem with identifying memory location for row and col of each cells
Here is the way using them:
i-th rows of transpose = *(transpose + i)
j-th col in i-th row of transpose = *(*(transpose+i) + j)
Similar to matrix:
i-th rows of matrix= *(matrix + i)
j-th col in i-th row of matrix = *(*(matrix+i) + j)
So here is my solution:
void transposeMatrix(int matrix[ROWS][COLS]) {
int** transpose = (int **)malloc(ROWS * sizeof(int*));
for (int i = 0; i < ROWS; i++)
transpose[i] = (int*)malloc(COLS * sizeof(int));
for (int i = 0; i < ROWS; i++) {
puts("");
for (int j = 0; j < COLS; j++) {
*(*(transpose + i) + j) = *(*(matrix + j) + i);
printf("%d ", transpose[i][j]);
}
puts("");
}
}
It's not necessary for you to allocate a new matrix row by row. Also, the functions that do the transpose and printing can be passed straight int * rather than preshaped arrays like int [3][2] etc.
It's even possible to reshape the matrix in place (i.e. without allocating new space). If you like I can post example code for that later.
For instance:
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
int M[2][3] = { {1, 2, 3}, {7, 8, 9} };
int N[3][3] = { {1, 2, 3}, { 4, 5, 6 }, {7, 8, 9} };
int *alloc_transpose(const int *matrix, size_t rows, size_t cols);
void print_matrix(const int *matrix, size_t rows, size_t cols);
int main()
{
int *t_matrix;
print_matrix(&M[0][0], 2, 3);
fprintf(stderr, "----\n");
t_matrix = alloc_transpose(&M[0][0], 2, 3);
if (t_matrix) {
print_matrix(t_matrix, 3, 2);
}
free(t_matrix);
t_matrix = alloc_transpose(&N[0][0], 3, 3);
if (t_matrix) {
fprintf(stderr, "----\n");
print_matrix(t_matrix, 3, 3);
}
free(t_matrix);
return 0;
}
void print_matrix(const int *matrix, size_t rows, size_t cols)
{
size_t r, c;
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
printf("%d ", *((matrix + r * cols) + c));
}
putchar('\n');
}
}
int *alloc_transpose(const int *matrix, size_t rows, size_t cols)
{
int *tm;
int r, c; /* relative to transposed matrix */
tm = malloc(sizeof(int) * cols * rows); /* contiguous is okay */
if (!tm)
return NULL;
for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) {
*((tm + c * rows) + r) =
*((matrix + r * cols) + c);
}
}
return tm;
}

How to initialize an array of arrays with non-constant length?

I am trying to make an array which contains 1D arrays of varying length. Due to the variation in length, I cannot use a 2D array. My code is as follows:
int ROW = 6;
int COL = 4;
int faceverts[6][4] = {{3,2,1,0}, {4,5,1,0}, {2,6,5,1}, {2,3,5,6}, {7,3,0,4}, {1,6,7,4}};
int (*q)[4] = faceverts;
int main(){
for (int i = 0; i < ROW; i++){
for (int k = 0; k < COL; k++)
printf("%d ", *(*(q+i)+k));
printf("\n");
}
}
My goal is to be able to get rid of those ROW and COL variables, as well as not have a fixed 2D array, but rather an array of 1D arrays of varying length. I have been told that using pointers is key to doing this task, but I do not know how to do this myself.
One approach is to create an array of structures. Each structure element contains a pointer and count to an array.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int *a;
size_t n;
} TwoD;
#define AN(a) (sizeof (a)/sizeof (a)[0])
int smallest[1] = { 1 };
int smaller[2] = { 2, 3 };
int small[3] = { 4, 5, 6 };
int big[4] = { 7, 8, 9, 10 };
int bigger[5] = { 11, 12, 13, 14, 15 };
int biggest[6] = { 16, 17, 18, 19, 20, 21 };
TwoD faceverts[6] = {
{ smallest, AN(smallest) }, { smaller, AN(smaller) }, { small, AN(small) },
{ big, AN(big) }, { bigger, AN(bigger) }, { biggest, AN(biggest) } };
int main(void) {
// Let us change things a bit at run time
int change[] = { 22,23,24,25,26,27,28 };
faceverts[0] = (TwoD) {change, AN(change)}; // compound literal
for (size_t row = 0; row < AN(faceverts); row++) {
for (size_t col = 0; col < faceverts[row].n; col++) {
printf(" %d", faceverts[row].a[col]);
}
printf("\n");
}
return 0;
}
Output
22 23 24 25 26 27 28
2 3
4 5 6
7 8 9 10
11 12 13 14 15
16 17 18 19 20 21
There is only 1D array in memory. (2D array is actually a long 1D array)
Allocate a 2D array (rows, cols)
int *arr;
int size;
size = width * height;
arr = (int *) malloc(sizeof(int) * size);
Access element (x, y) in the array
int e;
int offset;
offset = x * cols + y;
e = *(arr + offset);
Free the array
free(arr);
Allocate a irregular 2D array (col_0, col_2, ...., col_n-1);
int arr;
int size = 0;
// size = col_0 + ... + col_n-1;
arr = (int *) malloc(sizeof(int) * size);
Access element (x_row, y_col) in the array
int e;
int offset;
// offset = col_1 + ... + col_x-1 + y_col;
e = *(arr + offset);

C - structures and lists

I want to save the cartesian product of two arrays into one multidimentional array.
arr[number][0] - number from the first array
arr[number][1] - number from the second array
number = sizeof(array1)*sizeof(array2)
int main() {
int arr1[4] = {1, 4, 2, 3};
int arr2[4] = {4, 1, 3, 3};
int **outcomes = getProduct(arr1, 4, arr2, 4);
int i;
for(i = 0; i < 16; i++)
printf("%d", outcomes[i][0]);
getchar();
}
int* getProduct(int arr1[], int size1, int arr2[], int size2) {
int **outcomes = (int *)malloc(sizeof(int)*16), count = 0, i, j;
for(i = 0; i < size1; i++) {
for(j = 0; j < size2; j++) {
outcomes[count][0] = arr1[i];
outcomes[count][1] = arr2[j];
count++;
}
}
return outcomes;
};
However, this code strangly breaks while being in the nested loop inside getProduct() function. The logic is ok, I thing the problem might be with pointers.
Why do I need to initialize multidimentional arrays with two pointers?
Why isn't this code working?
Do u have any advices for me on how can I improve this code? ( I didn't code in C too much so I don't know which structures a "good" code uses).
The function getProduct would fail because you are assigning a pointer to an int( ie int*) to a pointer to an int pointer (ie int**).
Why do I need to initialize multidimentional arrays with two pointers?
Because
int** (pointer to int pointer) - with this, we can access an element of any row and any column which is not possible with a single pointer(or single dimensional array)
Similarly int*** can be used for three dimensional array or in other words pointer to pointer to an int pointer
To improve the code
I think your cartesian product function should look something like this
int** getProduct(int arr1[], int size1, int arr2[], int size2) {
int **outcome = malloc(sizeof(int*)*size1);
int i,j;
for(i = 0;i<size1;i++)
outcome[i] = malloc(sizeof(int)*size2);
for(i = 0; i < size1; i++) {
for(j = 0; j < size2; j++) {
outcome[i][j] = arr1[i] * arr2[j];
}
}
return outcome;
}
And your main() like this
int main() {
int arr1[4] = {1, 4, 2, 3};
int arr2[4] = {4, 1, 3, 3};
int **outcomes = getProduct(arr1, 4, arr2, 4);
int i,j;
for(i = 0; i < 4; i++){
for(j = 0;j <4; j++){
printf("%d ", outcomes[i][j]);
}
printf("\n");
}
getchar();
}

Resources