Finding Determinant of a matrix in C - c

This is the C code for determinant of matrix, But it gives compilation errors.
Code is:
#include<stdio.h>
#include<math.h>
int m;
float determinant(float b[][]);
int main(void)
{
int i,j,m;
printf("enter a no: ");
scanf("%d",&m);
//printf("%d",m);
float arr[m][m];
for(i=0;i<m;i++)
{
for(j=0;j<m;j++)
{
scanf("%f",&arr[i][j]);
//printf("%f",arr[i][j]);
}
}
for(i=0;i<m;i++)
{
for(j=0;j<m;j++)
{
printf("%f ",arr[i][j]);
}
printf("\n");
}
float det = determinant(arr);
printf("Determinant= %f ", det);
}
float determinant(float b[][])
{
int i,j;
int p;
float sum = 0;
float c[m][m];
for(i=0;i<m;i++)
{
for(j=0;j<m;j++)
{
printf("%f ",b[i][j]);
}
printf("\n");
}
if(m==2)
{
printf("Determinant for m=2");
sum = b[0][0]*b[1][1] - b[0][1]*b[1][0];
return sum;
}
for(p=0;p<m;p++)
{
int h = 0,k = 0;
for(i=1;i<m;i++)
{
for( j=0;j<m;j++)
{
if(j==p)
continue;
c[h][k] = b[i][j];
k++;
if(k == m-1)
{
h++;
k = 0;
}
}
}
m=m-1;
sum = sum + b[0][p]*pow(-1,p) * determinant(c);
}
return sum;
}
And the Compilation Errors are:
det.c:5:25: error: array type has incomplete element type
det.c: In function ‘main’:
det.c:36:2: error: type of formal parameter 1 is incomplete
det.c: At top level:
det.c:45:25: error: array type has incomplete element type
det.c: In function ‘determinant’:
det.c:91:3: error: type of formal parameter 1 is incomplete
det.c:99: confused by earlier errors, bailing out
Preprocessed source stored into /tmp/cc1Kp9KD.out file, please attach this to your bug report.
I think the error is in the passing of 2-D Array. when I passing it as a pointer then it gives warnings but no errors but it does not give the right result as in always gives determinant as Zero. So I guess the array is not being passed only and when I print it in the function determinant it doesn't print also.
Please help as I am stuck because of this in my project.

in your code,
scanf("%d",&m);
//printf("%d",m);
float arr[m][m];
here arr is a 2D array with static memory allocation so you can not read m at run time and declare arr like this.
so if you are want to define the array dynamically then use dynamic memory allocation methods like malloc() in C.

When you declare the prototype of a function as
int foo(int arr[], int n);
then compiler interprets it as
int foo(int (*arr), int n); // and that's why you can omit the first dimension!
i.e, your function is expecting first argument is of type int *. Similarly, when the parameter is a multidimensional array as
int foo(int arr[][col], int n); // Only first dimension can be omitted. You need to specify the second dimension.
then the compiler interprets it as
int foo(int (*arr)[col], int n);
i.e, your function is expecting first argument is of type int (*)[col] (a pointer to int array).
Since when passed to a function (in most cases) array names decay to pointer to its first element, in your case arr will be decayed to pointer to its first element, i.e, first row. Hence its type will become float (*)[m]. Its is compatible to your function parameter if you will declare it as
float determinant(int m, float b[][m]);
and the call should be like
float det = determinant(m, arr);

You can declare array dynamically like this in C99 (variable length arrays, pointed out by haccks), but not in the earlier version:
float arr[m][m];
So, if it troubles you then instead declare a pointer and malloc memory for it:
float* arr = malloc(sizeof(float)*m*m);
Also, the definition won't work (in either case):
float determinant(float b[][]);
you need to define the columns in the array that you pass to the function.
If you declare and allocate the pointer as I have shown then you can just pass a pointer in your function:
float determinant(float *b, int size); //here size is your row dimension, in this case equal to m
And inside the function, access your elements like:
*(b + size*i + j) = value // equivalent to b[i][j];

Declare your array with explicit bounds float b[m][m]; the compiler doesn't understand empty bounds in float b[][] (empty bounds are OK only for 1-D arrays, for reasons explained in the other answers).
So your determinant function should look like this:
float determinant(int m, float b[m][m])
{
...
}
There are other ways to make your code work, but I think this way is closest to what you already have.

I agree you can't move with this syntax of array initialization, u could have used
int *p=(int*)calloc(n*n,sizeof(float));
And then access your elements as :-
*(p+j+n*i);//for p[i][j] element
Hope it helps :)

Related

Matrix pointer in C

I will go straight to what I'm asking for, I also see some similar question but is not what I'm looking for...so it seems I have to ask with a new forum.
I'm preparing myself for a future examination, where is not required the pointer, but I would like to get some extra information and abilities.
Here's the code followed by the question...
I'm using Fedora 33, I know is different from some IDE on Windows (ex: Visual Studio or Dev C++)
/* It's just a simple test, if this work I will get myself into a more complicated one, as you could read in the
* forum, I'm getting ready ( just a recheck of my abilities ) for an universitary examinaton. */
#include <stdio.h>
#include <stdlib.h>
#define N 5
void casual_generation(int** mat);
void prompt_print(int** mat);
int main()
{
int **mat[N][N];
casual_generation(**mat);
prompt_print(**mat);
}
void casual_generation(int** mat)
{
int i=0,j=0;
for(i=0;i<N;i++)
for(j=0;j<N;j++)
mat[i][j] = rand() % 50;
}
void prompt_print(int** mat)
{
int i=0,j=0;
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
printf("%d ", mat[i][j]);
printf("\n");
}
}
Somebody else on the forum used malloc, struct or other stuff, as you can see in this picture, when I try to execute him it says "Segmentation fault (core dumped)"
screen error
Where is my error?
And if you want, can you also send me the version with the passed value pointer?
Thanks for whoever will give me an answer, and time dedicated.
This declaration
int **mat[N][N];
does not make a sense. It means that you have a matrix elements of which are pointers of the type int **. But you need a matrix elements of which are integer numbers of the type int. That is you need a declaration like this
int mat[N][N];
So now you have a two-dimensional array (or matrix) of integers.
As you are going to pass this two-dimensional array to functions then used as an argument expression it is converted to pointer to its first element of the type int ( * )[N].
Correspondingly the functions that accepts such an array should be declared like
void casual_generation( int mat[][N], size_t n );
void prompt_print( int mat[][N], size_t n );
or (that is fully equivalent) like
void casual_generation( int ( * mat )[N], size_t n );
void prompt_print( int ( *mat )[N], size_t n );
because the compiler adjusts function parameters having array types to pointers to array element types.
Now for example the first function can be defined the following way
void casual_generation( int ( * mat )[N], size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
mat[i][j] = rand() % 50;
}
}
}
And the function can be called like
casual_generation( mat, N );
A similar way can be defined the function prompt_print.
Using the second parameter makes the function more general. For example it can be called for two-dimensional arrays with different numbers of rows.
Now I will explain why you are getting a segmentation fault in your original code.
You have this declaration
int **mat[N][N];
a two dimensional array of pointers of the type int **.
Then you are using the expression **mat as an argument of function calls like this
casual_generation(**mat);
Then you are applying the dereference operator like *mat the array designator is converted to pointer to its first element (row) having the type int ** ( * )[N]. So dereferencing this pointer you get the first row of your array int **[N]. Applying the second time the dereferenced operator to this expression that has an array type the used expression is again is converted to pointer to its first element of the type int **( * ). That is it points to the first element of the first row of the original two-dimensional array. Dereferencing this pointer you get the first element of the type int **. This uninitialized pointer with indeterminate value the function accepts as its argument.
Thus dereferencing this first uninitialized element of the original matrix within the function
mat[i][j] = rand() % 50;
^^^
you get a segmentation fault. The reason of the fault is the incorrect matrix and the corresponding function parameter as it was shown above in tbe beginning of the answer.
Where is my error?
The "Segmentation fault" error happens because you define the variable mat as a pointer, but don't allocate any memory for it to point to.
int **mat[N][N];
You meant to do
Int mat[N][N];
and
casual_generation(mat);
prompt_print(mat);
By passing **mat you are passing mat[0][0] that is an int, but you want to pass the whole matrix which is a pointer to pointers to int (i.e. int **)
And you may want to introduce srand() in your code.
Just to make things clear:
mat is of type int ** and it's the whole matrix (or if you want it's a pointer to the first row)
*mat is of type int * and it's the first row of the matrix (or if you want it's a pointer to the first element of the first row)
**mat is of type int and it's the first element of the first row of the matrix
int **mat[N][N];
Here, you defined a double pointer to a 2D array. You only need to use one of those - a double pointer or a 2D array, like so:
int mat[N][N];
However, the bigger problem comes from trying to interchange 2D arrays and double pointers. This isn't possible in C since the 2D array is laid out flat in memory.
You need to create an array mat_ptr of pointers yourself and then pass that to casual_generation and prompt_print.
Finally, these casual_generation and prompt_print functions expect to be given a pointer, so you shouldn't dereference the pointer with ** before calling the function.
The final working code is:
int main()
{
int mat[N][N];
int *mat_ptr[N];
for (int i = 0; i < N; i++)
mat_ptr[i] = mat[i];
casual_generation(mat_ptr);
prompt_print(mat_ptr);
}
As you can find a detailed explanation why the code crashed in the other answer I will only propose a quite elegant solution that uses a neat though little known feature from C99 called Variable Length Arrays (aka VLA).
#include <stdio.h>
#include <stdlib.h>
void casual_generation(int n, int mat[n][n]);
void prompt_print(int n, int mat[n][n]);
int main()
{
const int N = 5;
int mat[N][N];
casual_generation(N, mat);
prompt_print(N, mat);
}
void casual_generation(int n, int mat[n][n])
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
mat[i][j] = rand() % 50;
}
void prompt_print(int n, int mat[n][n])
{
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
printf("%d ", mat[i][j]);
printf("\n");
}
}
It compiles in pedantic mode with no warnings and it works like a charm.
VLA were introduced to C to simplify numerical computation over multidimensional arrays.

How to use pointer type in C?

I am recently studying pointers and arrays.
Suppose I initialize an array like
int a[4]={6,2,3,4};
Now after reading a lot ,I understand that
1) a and &a will point to same location.But they aren't pointing to the same type.
2) a points to the first element of the array which is an integer value so the type of a is int*.
3) &a points to an entire array(i.e an integer array of size 4) therefore the type is int (*)[].
Now what I actually don't get is how to use these type??
For Example:
CODE 1:
#include<stdio.h>
void foo(int (*arr)[4],int n)
{
int i;
for(i=0;i<n;i++)
printf("%d ",*(*arr+i));
printf("\n");
}
int main()
{
int arr[4]={6,2,3,4};
foo(&arr,4);
return 0;
}
CODE 2:
#include<stdio.h>
void foo(int *arr,int n)
{
int i;
for(i=0;i<n;i++)
printf("%d ",*(arr+i));
printf("\n");
}
int main()
{
int arr[4]={6,2,3,4};
foo(&arr,4);
return 0;
}
In code 2 we are passing &arr so its type should be of int (*)[],then how come we are getting the correct output even though we are having a type int *.
I really don't understand what is the meaning of type and how to use it?
Kindly explain with some examples.
Code 2 is not valid C, because a conversion between an array pointer and a pointer to int is not a valid pointer conversion - they are not compatible types. If it works, it is because of some non-standard extension of your compiler, or possibly you just "got lucky".
Please note that the best way to pass an array to a function in modern C is this:
void foo(int n, int arr[n])
{
for(int i=0;i<n;i++)
printf("%d ",arr[i]);
printf("\n");
}
As part of a function parameter list, arr will get adjusted to a pointer to the first element of the array, type int*.
The pedantically correct version would also replace int n and int i with size_t, which is the most proper type to use when describing the size of an object.
The best way to pass arrays in to functions is a pointer and the number of elements.
Note you can pass arr in to the function as arr or &arr[0]; both resolve to the same address.
#include<stdio.h>
void foo(int *arr,int n)
{
int i;
for(i=0;i<n;i++)
printf("%d ",arr[i]);
printf("\n");
}
int main()
{
int arr[4]={6,2,3,4};
foo(arr,4);
return 0;
}
Also, it's better to index the array, rather than addition and dereference. e.g. *(arr+i) becomes arr[i].

C feeding array to function [duplicate]

Having looked around I've built a function that accepts a matrix and performs whatever it is I need on it, as follows:
float energycalc(float J, int **m, int row, int col){
...
}
Within the main the size of the array is defined and filled, however I cannot passs this to the function itself:
int matrix[row][col];
...
E=energycalc(J, matrix, row, col);
This results in a warning during compilation
"project.c:149: warning: passing argument 2 of ‘energycalc’ from
incompatible pointer type project.c:53: note: expected ‘int **’ but
argument is of type ‘int (*)[(long unsigned int)(col +
-0x00000000000000001)]’
and leads to a segmentation fault.
Any help is greatly appreciated, thank you.
The function should be declared like
float energycalc( float J, int row, int col, int ( *m )[col] );
if your compiler supports variable length arrays.
Otherwise if in declaration
int matrix[row][col];
col is some constant then the function can be declared the following way
float energycalc(float J, int m[][col], int row );
provided that constant col is defined before the function.
Your function declaration
float energycalc(float J, int **m, int row, int col);
is suitable when you have an array declared like
int * matrix[row];
and each element of the array is dynamically allocated like for example
for ( int i = 0; i < row; i++ ) matrix[i] = malloc( col * sizeof( int ) );
If the array is declared as
int matrix[row][col];
then change the function declaration to
float energycalc(float J, int m[][col], int row, int col){
The name of a two dimensional array of type T does not decay to T**.
If col is a local variable, then you need to call the function with the col parameter before matrix. This is done so that col is visible in the function.
Passing two dimensional array to a function in C is often confusing for newbies.
The reason is that they assume arrays are pointers and having lack of understanding how arrays decays to pointer.
Always remember that when passed as an argument arrays converted to the pointer to its first element.
In function call
E = energycalc(J, matrix, row, col);
matrix is converted to pointer to its first element which is matrix[0]. It means that passing matrix is equivalent to passing &matrix[0]. Note that the type of &matrix[0] is int(*)[col] (pointer to an array of col int) and hence is of matrix. This suggest that the second parameter of function energycalc must be of type int(*)[col]. Change the function declaration to
float energycalc(int col, int (*m)[col], int row, float J);
and call your function as
E = energycalc(col, matrix, row, J);
I think you can do something like this in C
float function_name(int mat_width, int mat_height, float matrix[mat_width][mat_height]) {
... function body...
}
A pointer-to-pointer is not an array, nor does it point to a two-dimensional array. It has nothing to do with arrays, period, so just forget you ever heard about pointer-to-pointers and arrays together.
(The confusion likely comes from the hordes of confused would-be programming teachers/authors telling everyone that they should use pointer-to-pointer when allocating dynamic 2D arrays. Which is just plain bad advice, since it will not allocate a real array allocated in adjacent memory cells, but rather a fragmented look-up table exploded in pieces all over the heap. See this for reference about how to actually allocate such arrays.)
Assuming that your compiler isn't completely ancient, simply use a variable length array (VLA), which is a feature introduced in the C language with the C99 standard.
#include <stdio.h>
void print_matrix (size_t row, size_t col, int matrix[row][col]);
int main (void)
{
int matrix[2][3] =
{
{1,2,3},
{4,5,6}
};
print_matrix(2, 3, matrix);
return 0;
}
void print_matrix (size_t row, size_t col, int matrix[row][col])
{
for(size_t r=0; r<row; r++)
{
for(size_t c=0; c<col; c++)
{
printf("%d ", matrix[r][c]);
}
printf("\n");
}
}

Max number in array

I know many solutions exist for this one, but after looking around I haven't found any that involves pointers
Right now it keep throwing warnings and there's no output at all, what am I doing wrong?
#include <stdio.h>
int findbig (int a[], int n)
{
int max = a[0];
for (int i = 1; i < n; i++)
{
if (a[i] > max)
{
max = a[i];
}
}
return max;
}
int main (void)
{
int n;
printf("How many numbers? \n");
scanf("%d", &n);
int a[n];
printf("Now enter those %d numbers: \n", n);
for (int i = 1; i < n; i++)
{
scanf("%d", &a[i]);
}
int biggest = findbig (a[n], n);
printf("The biggest number is: %d\n", biggest);
return 0;
}
My compiler is complaining that:
-warning: passing argument 1 of 'findbig' makes pointer from integer without a cast [enabled by default]
-note: expected 'int *' but argument is of type 'int'
a[n] (as well as its equivalent *(a + n) form) is an int, not a pointer to int. It's also one past the boundary of your array. You need to turn your warnings into errors. You pass an int, whose value is converted to a pointer (address), which is, well, no good.
You need to call your function like so:
findbig(a, n);
Regardless of your signature, findbig receives a pointer to int. You cannot pass arrays to (or return them from) functions in C. They degrade to pointers to their first element.
On a side note, you're always skipping the first element when populating the array, so the user says "I want to enter N numbers", but you only allow them to enter n-1. The is also problematic as you use a[0] as your initial max number, but the value of that element is indeterminate.
It could be anything, i.e., some huge number, and then your function will give strange results. Either initialize the array to 0 (int a[n] = {0};) or start your loop at 0 (better).
By indexing a, doing a[n], you get the value of the array a in the n-th index, which is of int type. You need to invoke findbig(....); function using the array "pointer" variable, without indexing it, by doing:
findbig(a, n);
This line is wrong.
int a[n]
Array should be initialized with constant value, because the space of array is allocated before execution of the program. So, variables won't work.

Sum of two arrays

The exercise says "Make a function with parameters two int arrays and k which is their size. The function should return another array (size k) where every element of it is the sum of the two arrays of the same position. That's what I wrote, but it crashes. Do I have to do it with pointers?
#include <stdio.h>
#include <stdlib.h>
void sumarray(int k,int A[k],int B[k]){
int sum[k],i;
for(i=0;i<k;i++){
sum[i]=A[i]+B[i];
printf("sum[%d]=%d\n",i,sum[i]);}
}
main(){
int i,g,a[g],b[g];
printf("Give size of both arrays: ");
scanf("%d",&g);
for(i=0;i<g;i++){
a[i]=rand();
b[i]=rand();
}
sumarray(g,a,b);
system("pause");
}
Example: If i have A={1,2,3,4} and B={4,3,2,1} the program will return C={5,5,5,5).
This:
int i,g,a[g],b[g];
causes undefined behaviour. The value of g is undefined upon initialisation, so therefore the length of a and b will be undefined.
You probably want something like:
int i, g;
int *a;
int *b; // Note: recommend declaring on separate lines, to avoid issues
scanf("%d", &g);
a = malloc(sizeof(*a) * g);
b = malloc(sizeof(*b) * g);
...
free(a);
free(b);
Its impossible to first do a[g] when dynamically getting g.
Your first lines in main should be:
int i,g;
int *a,*b;
printf("Give size of both arrays: ");
scanf("%d",&g);
a = (int *)malloc(g*sizeof(int));
b = (int *)malloc(g*sizeof(int));
int sum[k] ;
k is a variable but the size of the array should be a constant.
The function should return another array (size k) ...
But the function you wrote returns void which is clearly wrong.
Do I have to do it with pointers?
Yes.
One issue is that you've attempted to declare dynamically sized arrays on the stack (e.g. a[g]). You need to declare pointers for each array and then dynamically allocate your variable sized array once you've read in the value of g.
change the function summary signature (the definition part of the declaration) to this and try it out:
void sumarray(int k,int* A,int* B){

Resources