C - Pointer to a matrix - c

I am trying to pass a matrix to a function by reference. The function will replace every element A[i][j] of the matrix by -A[i][j]. I first create the matrix:
float a[3][4] =
{
{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{1.0f, 1.0f, 0.0f, 0.0f},
};
Then, I obtain the pointer to this matrix:
float*** pa = &a;
Then, I introduce the following function:
void process(float ***matrix, int nRows, int nCols){
short i;
short j;
for (i=0 ; i<nRows; i++){
for (j=0 ; j<nCols ; j++){
(*matrix)[i][j] *= -1;
}
}
}
which I call as follows:
process(pa,3,4);
My program fails to execute and returns:
Segmentation fault: 11
Any ideas?
Summary of the answers: Some notes based on the questions this question received:
I. The aforementioned function can be used, provided that a is initialized a bit differently so as to be a float**. In particular:
int numberOfRows = 3;
int numberOfColumns = 4;
float **a = (float **) malloc(sizeof (float *) * numberOfRows);
for (i = 0; i < numberOfRows; ++i) {
a[i] = (float *) malloc(sizeof (float) * numberOfColumns);
}
and then, it is passed to the function process as process(&a, 3,4);.
II. Alternatively, one may use the function:
void multi_by_minus(float *matrix, int nRows, int nCols) {
short i,j;
for (i = 0; i < nRows; i++) {
for (j = 0; j < nCols; j++) {
matrix[i * nCols + j] *= -1;
}
}
}
which treats the matrix as an one-dimensional array. In that case we simply invoke it as multi_by_minus(&a, 3, 4);
III. Finally, we may use the method:
void process2(int nRows, int nCols, float (*matrix)[nCols]) {
short i, j;
for (i = 0; i < nRows; i++) {
for (j = 0; j < nCols; j++) {
matrix[i][j] *= -1;
}
}
}
to which we provide a pointer to a, i.e., we invoke it like process2(3,4,&a);. In this way, we acquire access to the elements of the matrix in 2D.

There is no need for the triple pointer since you are already supplying the memory. You would use that if you were to allocate the memory inside de function.
You can't index a 2 dimension matrix without supplying at least the size of 1 dimension. The reason is that the compiler needs to generate code to access the correct offset taking into account both dimensions. In this particular case, I suggest passing a simple pointer and indexing as a 1D array, like this:
void process(float *matrix, int nRows, int nCols){
short i;
short j;
for (i=0 ; i<nRows; i++){
for (j=0 ; j<nCols ; j++){
matrix[i * nCols + j] *= -1;
}
}
}
You can then call it like this:
process((float*)a,3,4);
This way you manually index your buffer.

You have to change the signature of the function to this:
void process(float (*matrix)[3][4], int nRows, int nCols){
And when calling the function, use this:
process(&a, 3, 4);

If you put the nCols parameter before the matrix parameter, you can pass the two-dimensional matrix and use it in the natural way, without extra * operators or index arithmetic:
void process(int nRows, int nCols, float (*matrix)[nCols])
{
for (short i = 0 ; i < nRows; i++)
{
for (short j = 0; j < nCols; j++)
{
matrix[i][j] *= -1;
}
}
}
Then you call process like this:
process(3, 4, matrix);
Incidentally:
Unless there is special reason for making i and j short, you should declare them int. int is defined to be the “natural” size for integers on the target platform.

So easy, if you have a matrix:
int m[2][2]={{1,0},{0,1}};
and you want to define a pointer to m, so you must declare:
int (*mptr)[2][2];
mprt=m; // or mptr=&m; is the same.
and you can use it to point to elements of the matrix m.
(*mptr)[i][j]....

Related

(C programming) Segfault when combining 2 one-dimensional array into 1 multi-dimensional array

I am writing a program where I take 2 one dimensional arrays and generate a matrix in its most simplified form Ax=b.
This part of the function takes in the arrays A and b. A is A[n*n] and b is b[n]. In this section I tried to combine the two arrays so it looks like an actual matrix.
This code works, however, if n were to be greater than 1023 it would cause a segmentation fault when calling the main function. I was wondering if there is a better way in doing this. When I tried to use the GDB debugger, it stoped at the line Y[i][j] = A[k]; so I think this is the problem that requires fixing
int linsolve ( int n, double A[], double b[], double x []) {
double Y[n][n+1]; //Creating multidimensional matrix
int k = 0;
// Turns the two one dimensional array into one multidimensional
for (int i=0; i < n; i++){ //iterating row
for (int j=0; j < n; j++){ // per column
Y[i][j] = A[k]; // adding from array A to Y
k++;
}
Y[i][n] = b[i]; // adding from Array b to Y
}
I assume you are using a Unix/Linux type system. First find out the stack size by typing
ulimit -s
This is the stack size in kilobytes. On my system it is 8Mb. If you have a 1200x1200 matrix, that will require
1200x1201x8 appx 10Mb
This is why the program segvs. You are creating 10Mb array on an 8Mb stack. The question is, does A or b live on the stack too? You may be getting a segv because the item you are passing through was created on the stack and is larger than the allocated stack.
To solve it, create the array on the heap as #shirish has suggested. An alternative to #shirish's technique would be
int linsolve ( int n, double A[], double b[], double x []) {
double **Y = new double *[n];
double *Ybody = new double[n * (n + 1)];
for (int i = 0; i < n; i++) {
Y[i] = &Ybody[i * (n + 1)];
}
// Turns the two one dimensional array into one multidimensional
int k = 0
for (int i=0; i < n; i++){
for (int j=0; j < n; j++){
Y[i][j] = A[k++];
}
Y[i][n] = b[i];
}
// Do something
// Free up Y before returning
delete [] Y;
delete [] Ybody;
}
// Assuming A has n * n elements
int linsolve ( int n, double A[], double b[], double x []) {
double **Y = new double *[n];
for (int i = 0; i < n; i++) {
Y[i] = new double[n + 1];
}
int k = 0;
// Turns the two one dimensional array into one multidimensional
for (int i=0; i < n; i++){ //iterating row
for (int j=0; j < n; j++){ // per column
Y[i][j] = A[k++]; // adding from array A to Y
}
Y[i][n] = b[i]; // adding from Array b to Y
}
// Do something
// Free up Y before returning
for(int i = 0; i < n; i++) {
delete [] Y[i];
}
delete [] Y;
//Return int here
}

How to pass a 2D array to a function in C when the array is formatted like this?

I'd like to make an array (called Csend) and then create a function which modifies it slightly, such as by adding 0.05 to every element. The problem I'm having is with the formatting of the array, I'm not sure how to pass it into a function properly. I've allocated the memory in this way following this guide so that I can later put it in MPI_Send and MPI_Recv.
Here is my attempt:
#include "stdio.h"
#include "stdlib.h"
#include "mpi.h"
#include "math.h"
int main(int argc, char **argv) {
int N = 32;
int dim = 3;
float a = 10.0; // size of 3D box
int size, rank, i, j, k, q;
float **C, **Csend, **Crecv;
float stepsize = 0.05;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
float **alloc_2d_float(int rows, int cols) {
float *data = (float *)malloc(N*dim*sizeof(float));
float **array= (float **)malloc(N*sizeof(float*));
for(i=0; i<N; i++) {
array[i] = &(data[dim*i]);
}
return array;
}
C = alloc_2d_float(N,dim);
Csend = alloc_2d_float(N,dim);
Crecv = alloc_2d_float(N,dim);
if(rank == 0) {
for (i = 0; i < N; i++) {
for (j = 0; j < dim; j++) {
Csend[i][j] = (float)rand()/(float)(RAND_MAX/a);
}}
}
// FUNCTION TO MODIFY MATRIX //
float randomsteps(float *matrix, int N, int dim) {
int i, j;
for(i = 0; i < N; i = i+2) {
for (j = 0; j < dim; j++) {
*((matrix+i*N) + j) = *((matrix+i*N) + j) + stepsize;
}
}
return matrix;
}
C = randomsteps(Csend, 32, 3);
for (i=0; i<N; i++){
for (j=0; j<dim; j++){
printf("%f, %f\n", Csend[i][j], C[i][j]);
}
}
MPI_Finalize();
return 0;
}
The problem I'm having is that formatted like it is here, I get error messages, and formatted in ways that didn't give error messages, C was just empty.
Here is the error message:
test.c: In function ‘randomsteps’:
test.c:46: error: incompatible types when returning type ‘float *’ but ‘float’ was expected
test.c: In function ‘main’:
test.c:49: warning: passing argument 1 of ‘randomsteps’ from incompatible pointer type
test.c:39: note: expected ‘float *’ but argument is of type ‘float **’
test.c:49: error: incompatible types when assigning to type ‘float **’ from type ‘float’
Thanks for the help!
You are confusing between 1 dimensional representation of a matrix and a two dimensional pointer to pointer approach of it.
*((matrix+i*N) + j) = *((matrix+i*N) + j) + stepsize; -> This line implies that matrix is just linear collection and it is accessed like a matrix using index manipulation.
float **C; -> This implies you want a matrix which can be accessed as C[i][j].
Stick to any one of the representations. Also, since your function returns a matrix, the return type should be either float* (if the 2d matrix is considered linear with array manipulation) of float** if you want a 2d matrix without index manipulation access.
float* matrix = malloc(row * cols * sizeof(float)); // This is a linear version.
// matrix[i*cols + j] gives you the (i, j)th element.
float** matrix = malloc(rows * sizeof(float*));
for(int i = 0; i < rows; ++i)
matrix[i] = malloc(cols * sizeof(float));
// Now you can access matrix[i][j] as the (i, j)th element.
Here is a way to interconvert between the two formats.
float* linearize(float** matrix, unsigned int rows, unsigned int cols)
{
float* linear = malloc(rows * cols * sizeof(float));
if(linear)
{
for(unsigned int i = 0; i < rows; ++i)
for(unsigned int j = 0; j < cols; ++j)
linear[i*cols + j] = matrix[i][j] ;
}
return linear ;
}
float** unlinearize(float* linear, unsigned int rows, unsigned int cols)
{
float** matrix = malloc(rows * sizeof(float*));
if(matrix)
{
for(unsigned int i = 0; i < rows; ++i)
{
matrix[i] = malloc(cols * sizeof(float));
if(matrix[i])
{
for(unsigned int j = 0; j < cols; ++j)
matrix[i][j] = linear[i*cols + j] ;
}
}
}
return matrix ;
}

Segmentation fault in int matrix

I was experimenting some basic C code that defines an int matrix with pointers.
typedef int **Matrix;
Matrix createMatrix(int lines, int columns) {
int i, j;
Matrix m = (Matrix) malloc(sizeof(int) * lines * columns);
for (i = 0; i < lines; ++i) {
for (j = 0; j < columns; ++j) {
m[i][j] = 0;
}
}
return m;
}
int main(int argc, char**argv) {
Matrix m = createMatrix(5, 10);
// ...
if (m[2][3] == 20) {
// ...
}
return 0;
}
However, these m[i][j] accesses are throwing segmentation faults. What's wrong here? Too many asterisks?
I was convinced that a pointer to a pointer to an int was effectively the same as a matrix.
Your allocation of the Matrix data item assumes you're accessing it linearly with a single index. If you want to access it with two indices, e.g., m[1][1] you need to allocate each dimension:
Matrix m = malloc(sizeof(int *) * lines);
for ( int i = 0; i < lines; i++ )
m[i] = malloc(sizeof(int) * columns);
Note also that you should not type cast malloc.

Matrix product cause error: subscripted value is neither array nor pointer nor vector

I have a Java method that multiplies 2 matrices. I have tried to port the same method in C without success.
Here is my attempt to write a method that should multiply 2 matrices in C:
float **multiply(int m1, int n1, float Xy1[], int m2, int n2, float Xy2[]) {
int i, j, k;
float **result = allocate_mem_mtrx(m1, n2);
for (i = 0; i < m1; i++) {
for (j = 0; j < n2; j++) {
for (k = 0; k < n1; k++) {
result[i][j] = result[i][j] + Xy1[i][k] * Xy2[k][j];
}
}
}
return result;
}
At this line
result[i][j] = result[i][j] + Xy1[i][k] * Xy2[k][j];
I receive the error:
subscripted value is neither array nor pointer nor vector
Clearly my syntax is wrong, but I haven't understood how I should fix this line of code, to solve my problem.
In my main I have:
float matrix1[3][2] = {{0, 1}, {3, 4}, {6, 7}};
float matrix2[2][3] = {{5, 1, 2}, {3, 4, 5}};
with the actual signature I invoke the method in this way:
multiply(3, 2, &matrix1, 2, 3, &matrix2);
My original Java method
public static int[][] multiply(int[][] Xy1, int[][] Xy2) {
int rowsInXy1 = Xy1.length;
int columnsInXy1 = Xy1[0].length; // same as rows in B
int columnsInXy2 = Xy2.length;
int[][] result = new int[rowsInXy1][columnsInXy2];
for (int i = 0; i < rowsInXy1; i++) {
for (int j = 0; j < columnsInXy2; j++) {
for (int k = 0; k < columnsInXy1; k++) {
result[i][j] = result[i][j] + Xy1[i][k] * Xy2[k][j];
}
}
}
return result;
}
You have float Xy1[]
but you treat it as 2D
Xy1[i][k]
Same for Xy2.
You should change float Xy1[] to float** Xy1.
Also another thing, in your loop I feel that you are sure that result 2D array is initialized in your function that says allocate. If that functions just mallocs the array, then this array will have garbage inside.
For more.
[EDIT]
Also I see in one other answer that they cast what malloc returns. Ouch!
Do not cast the return value of malloc in C.
[EDIT.2]
SO, you could something like this:
#include <stdlib.h>
// We return the pointer
float **get(int N, int M) /* Allocate the array */
{
/* Check if allocation succeeded. (check for NULL pointer) */
int i;
float **table;
table = malloc(N*sizeof(float *));
for(i = 0 ; i < N ; i++)
table[i] = malloc( M*sizeof(float) );
return table;
}
void free2Darray(int** p, int N) {
int i;
for(i = 0 ; i < N ; i++)
free(p[i]);
free(p);
}
// do not forget to FREE what multiply returns
float **multiply(int m1, int n1, float** Xy1,int m2, int n2, float** Xy2) {
int i,j,k;
float **result = get(m1,n2);
for (i = 0; i < m1; i++) {
for (j = 0; j < n2; j++) {
for (k = 0; k < n1; k++) {
// this line is correct, the prototype of the function
// was not OK
result[i][j] = result[i][j] + Xy1[i][k] * Xy2[k][j];
}
}
}
return result;
}
int main(void) {
float** A = get(5, 5); // arrays declared as double pointers
float** B = get(5, 5);
float** C = get(5, 5);
C = multiply(5, 5, A, 5, 5, B);
// free2Darray function defined below
free2Darray(A, 5);
free2Darray(B, 5);
free2Darray(C, 5);
return 0;
}
[EDIT.3]
Another way, if you now the columns apriori, which you probably don't as your function implies, you could do that:
#include <stdlib.h>
#include <stdio.h>
// We return the pointer
float **get(int N, int M) /* Allocate the array */
{
/* Check if allocation succeeded. (check for NULL pointer) */
int i;
float **table;
table = malloc(N*sizeof(float *));
for(i = 0 ; i < N ; i++)
table[i] = malloc( M*sizeof(float) );
return table;
}
float **multiply(int m1, int n1, float Xy1[][2],int m2, int n2, float Xy2[][2]) {
int i,j,k;
float **result = get(m1,n2);
for (i = 0; i < m1; i++) {
for (j = 0; j < n2; j++) {
for (k = 0; k < n1; k++) {
result[i][j] = result[i][j] + Xy1[i][k] * Xy2[k][j];
}
}
}
return result;
}
int main() {
float matrix1[2][2] = {{0, 1}, {3, 4}};
float matrix2[2][2] = {{0, 1}, {3, 4}};
float** C;
C = multiply(2, 2, matrix1, 2, 2, matrix2);
free2Darray(C, 2);
printf("ok\n");
return 0;
}
I got the get() function from my pseudo-site.
float Xy1[]
is not a two dimensional array, so to write
Xy1[i][k]
is an error.
In C you can use a pointer to pointer notation:
float** multiply( int m1, int n1, float** Xy1,int m2, int n2, float** Xy2) {
//...
}
or you can take advantage of the variable-length array feature in the C language and write
functions that can take multidimensional arrays of varying sizes:
float** multiply( int m1, int n1, float Xy1[m1][n1],
int m2, int n2, float Xy2[m2][n2]) {
float **result, i, j;
result = malloc( m1 * sizeof *result); // remember to free this memory
for( i = 0; i < m1; ++i)
result[i] = malloc( n2 * sizeof float);
//... I don't continue since there seems to be an issue with your indices
// however now you can use result this way:
// result[i][j] = result[i][j] + Xy1[i][k] * Xy2[k][j]; i, j, k integers
return result;
}
In C++ use a std::vector< std::vector<float> >:
typedef std::vector<std::vector<float> > array; // shorten notation
array multiply( const array& Xy1, const array& Xy2) {
//...
}
In addition
int[][] result = new int[rowsInXy1][columnsInXy2];
is not correct way to create two dimensional array. Such array is an array of pointers and correct way to create this is:
C
int **a, i;
a = malloc( rowsInXy1 * sizeof *a);
for( i = 0; i < rowsInXy1; ++i)
a[i] = malloc( columnsInXy2 * sizeof int);
C++
int** result = new int*[rowsInXy1];
for( int i = 0; i < rowsInXy1; ++i)
result[i] = new int[columnsInXy2];
I see you have already chosen a solution but here is some additional info about arrays in C.
In C there is no equivalent of Java's int[][] type. Java array storage also includes storage of how many items are in the array. However, C's array storage is purely the values in the array contiguous in memory; and you have to keep track of the size either as compile-time constants, or by storing a variable that holds the length.
Further; originally in C, arrays (using the [] syntax) had to have their size known at compile-time. There is an optional feature called variable-length array which means that the array size can be specified at runtime -- however the size can't be changed once the array is created. The major compiler vendors all support VLA, I think.
The VLA uses contiguous storage, however it is not possible to return one via a function's return value. But you can "return" them using an "out" parameter.
It's probably going to turn into a jumble if your code sometimes uses VLAs and sometimes uses dynamically-allocated arrays of pointers.
Another point: in both cases you have to store both array dimensions separately from the array, so that's 3 variables to pass around for each matrix. I'd like to suggest wrapping all of this up in a struct. Since VLAs can't live in a struct, and the compiler might not support them anyway, your best bet may be to use the dynamic allocation version.
Even though we are in C, if you are planning to do more than just a throwaway program, my recommendation would be to use an object-oriented approach for the matrix. Here's an example framework (where all Matrices are to have the Matrix be dynamically allocated, as well as the cells):
// Matrix.h
typedef struct
{
size_t y_dim, x_dim;
float **cells;
} Matrix;
Matrix *matrix_construct(size_t y_dim, size_t x_dim);
void matrix_free(Matrix *m); // frees m as well as cells
void matrix_assign(Matrix *dst, Matrix const *src); // may re-size dst
void matrix_set_values(Matrix *dst, float *row_major);
bool matrix_is_equal(Matrix const *m1, Matrix const *m2);
typedef Matrix *MatrixBinaryOperator(Matrix const *m1, Matrix const *m2);
MatrixBinaryOperator matrix_multiply;
Example usage:
float mat1_array[3][2] = {{0, 1}, {3, 4}, {6, 7}};
float mat2_array[2][3] = {{5, 1, 2}, {3, 4, 5}};
Matrix *mat1 = matrix_construct(3, 2);
Matrix *mat2 = matrix_construct(2, 3);
matrix_set_values(mat1, (float *)&mat1_array);
matrix_set_values(mat2, (float *)&mat2_array);
Matrix *mat3 = matrix_multiply(mat1, mat2);
matrix_free(mat1);
matrix_free(mat2);
matrix_free(mat3);
See it working - disclaimer: this code doesn't check for malloc failure and I have only done the most basic testing; and a lot of optimization is possible.

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.

Resources