im currently trying to write a program to find the determinant for an NxN matrix but im having an issue with recursion for N larger than 2. Basically from what i can tell, it isn't doing it, it just runs the function once as using my debug option shows that the function runs through the columns but the order never goes down, and it then gives me zero for my determinant no matter what. Ive tried looking all over the place for any idea as to what im doing wrong but i cant seem to find any answers, ive even found examples which do basically the same thing as me and using them gives me zero no matter what as well, so im very confused :(. id be very grateful if someone could have a quick look through my code and tell me where im being an idiot! (sorry about the formatting, it looks ok in my editor but i cant seem to get the hang of it on here)
Code:
#include<stdlib.h>
#include<stdio.h>
#include<math.h>
double det(double **mat, int order);
int main (int argc, char* argv[])
{
FILE* input;
int row,column,N;
double **matrix;
N=3;
matrix=(double**)malloc(N*sizeof(double));
input=fopen("matrix.dat", "r");
if(input !=(FILE*) NULL)
{
for(row=0; row<N; row++)
{
matrix[row]=(double*)malloc(N*sizeof(double));
}
for(row=0; row<N; row++)
{
printf("| ");
for(column=0; column<N; column++)
{
fscanf(input,"%lf ", &matrix[row][column]);
printf("%g ", matrix[row][column]);
}
if(row != (N/2))
{
printf("|\n");
}
else
{
printf("|= %lf \n", det(matrix, N) );
}
}
return(EXIT_SUCCESS);
}
else
{
printf("*********************ERROR*********************\n");
printf("** Cannot open input file 'matrix.dat' make **\n");
printf("** sure file is present in working directory **\n");
printf("***********************************************\n");
return(EXIT_FAILURE);
}
}
double det(double **mat, int order)
{
int debug;
double cofact[order], determinant, **temp;
determinant = 0;
debug=0;
if(order==1)
{
determinant=mat[0][0];
if(debug==1)
{
printf("order 1 if\n");
}
}
else if(order==2)
{
determinant= ((mat[0][0]*mat[1][1])-(mat[0][1]*mat[1][0]));
if(debug==1)
{
printf("order 2 if\n");
}
}
else
{
int column, rowtemp, coltemp, colread;
for (column=0; column<order; column++)
{
/* Now create an array of size N-1 to store temporary data used for calculating minors */
temp= malloc((order-1)*sizeof(*temp));
for(rowtemp=0; rowtemp<(order-1); rowtemp++)
{
/* Now asign each element in the array temp as an array of size N-1 itself */
temp[rowtemp]=malloc((order-1)*sizeof(double));
}
for(rowtemp=1; rowtemp<order; rowtemp++)
{
/* We now have our empty array, and will now fill it by assinging row and collumn values from the original mat with the aprroriate elements excluded */
coltemp=0;
for(colread=0; colread<order; colread++)
{
/* When the collumn of temp is equal to the collumn of the matrix, this indicates this row should be exlcuded and is skiped over */
if(colread==column)
{
continue;
}
temp[rowtemp-1][coltemp] = mat[rowtemp][colread];
coltemp++;
}
}
if(debug==1)
{
printf("column =%d, order=%d\n", column, order);
}
determinant+=(mat[0][column]*(1 - 2*(column & 1))*det(temp, order-1));
}
}
return(determinant);
}
temp= (double **)malloc((order-1)*sizeof(double));
This will not cause a crash as long as sizeof(double*) <= sizeof(double), which is the case on the usual 32 or 64-bit systems, but it is conceptually wrong. You are allocating space for an array of double*, so the factor should be sizeof(double*) or, better since it is invariant when the type changes, sizeof *temp,
temp = malloc((order-1) * sizeof *temp);
(And you don't need to cast the result of malloc in C, it is even better not to, since the cast could hide errors like forgetting to #include <stdlib.h>.)
The same holds for the allocation
matrix=(double**)malloc(N*sizeof(double));
in main.
In the calculation of the determinant,
for(coltemp=0; coltemp<order; coltemp++)
{
for(colread=0; colread<order; colread++)
{
/* When the collumn of temp is equal to the collumn of the matrix, this indicates this row should be exlcuded and is skiped over */
if(colread==column)
{
continue;
}
temp[rowtemp-1][coltemp] = mat[rowtemp][colread];
coltemp++;
}
}
You are looping twice through the columns, once for coltemp == 0, and then in the inner loop, coltemp is incremented order-1 times, so the inner loop runs a second time with coltemp == order-1 at the start. Then coltemp is again incremented multiple times in the loop, and you're writing out of bounds of the allocated memory.
The outer loop should be removed, coltemp = 0; and the inner loop are what you need.
pow(-1,column))
is not a good way to determine a sign.
(1 - 2*(column & 1))
is faster than a call to pow.
Finally, in main
for(row=0; row<N; row++)
{
printf("| ");
for(column=0; column<N; column++)
{
fscanf(input,"%lf ", &matrix[row][column]);
printf("%g ", matrix[row][column]);
}
if(row != (N/2))
{
printf("|\n");
}
else
{
printf("|= %lf \n", det(matrix, N) );
}
}
You are printing the determinant at row N/2, which looks nice, but at that time, you have not yet scanned in the entire matrix, so rows N/2 + 1 to N-1 contain uninitialised data, which is not unlikely to be all zeros. If you change the if (row != N/2) to if (row != N-1), it will work, however, the proper way to handle it is to separate the scanning of the matrix from the computation and the printing. These are all independent operations that should be handled in their own separate functions.
Related
I have an assignment from my uni where I have to print a triangle using recursion in C language. I have tried writing my code as follows but I am not able to find my mistake. Kindly can anyone point out where I have to edit.
int tri(int x, int org);
int dreick(int x) {
return tri(x,x);
}
int tri(int x,int org) {
if (x == 0) {
return 0;
}
else {
return (x - 1, org);
}
for (int i = 0; i < (org - x); i++) {
printf("");
}
for (int j = 0; j <= x; j++) {
printf("*");
}printf("\n");
}
int main() {
int a = dreick(5);
printf("%d",a);
}
Recursion works as follows: each step receives a parameter which specifies what work still needs to be done; if no work needs to be done, then it returns without doing anything; otherwise, it does one step of the work, and then invokes itself with a new value for the parameter which specifies the remaining work to be done.
In your case, the parameter specifying what work still needs to be done can be the row number.
Your triangle-printing code can print the top (single star at row 0) and the bottom (row of stars at row N) outside of recursion, so as to keep things simple. Use recursion to print each line of text from 1 to N-1.
On each step of the recursion you print a number of spaces, an asterisk, some more spaces, and then another asterisk. The number of spaces depends on the row number. (How deep down the triangle you are.) You are done when you reach N-1.
void interclas(int *ptr,int *vec, int *c, int n) {
int i,j,tmp;
tmp=0;
for (i=0;i++;i<n)
for (j=0;i++;j<n)
{
if (vec[j]<=ptr[i])
c[tmp]=vec[j];
else
c[tmp]=ptr[i];
tmp++;
}
}
int main() {
int i,n;
int *ptr,*vec,*c;
printf("Nr. of elements of initial arrays : 5 \n");
n=5;
vec=(int*)malloc( n * sizeof(int));
ptr=(int*)malloc( n * sizeof(int));
c=(int*)malloc( 2 * n * sizeof(int));
for (i=0;i<n;i++) {
scanf("%d",&ptr[i]);
}
for (i=0;i<n;i++) {
scanf("%d",&vec[i]);
}
printf("\n");
printf("Initial arrays are : ");
for (i=0;i<n;i++) {
printf("%d ",ptr[i]);
}
printf("\n");
for (i=0;i<n;i++) {
printf("%d ",vec[i]);
}
interclas(ptr,vec,&c,n);
printf("Merged array is : ");
for (i=0;i<10;i++) {
printf("%d ",c[i]);
}
return 0;
}
So I'm trying to merge two sorted arrays into one new one using pointers with the function 'interclas'. I tried using the same method to sort an array with a pointer in a function and it worked just fine. Now as you can see, it stores the adress of the variable rather than the variable itself.
If I run this, it stores the adresses of the arrays. How can I fix this? (I'm still new to pointers)
In your method's body, change:
for (i=0;i++;i<n)
for (j=0;i++;j<n)
to this:
for (i=0; i<n; i++)
for (j=0; j<n; j++)
and then change the call to your method, from this:
interclas(ptr, vec, &c, n);
to this:
interclas(ptr, vec, c, n);
since the prototype expects a pointer to an int, for the third parameter.
The logic of your method is also flawed, try to put some printfs (e.g. printf("here i = %d, j = %d, ptr[i] = %d, vec[j] = %d, tmp = %d\n", i, j, ptr[i], vec[j], tmp);) to see what values your variables have at its iteration - you only get the first two elements of the first array to be merged!
If you think about it, what you'd like to do is to go through the first element of array ptr and vec, and store the minimum of this two. If now that min was of array ptr, you'd like the next element of ptr to be taken into account, otherwise the next element of vec.
Take a pencil and a paper and sketch that algorithm - you'll see that it goes out nicely, but some leftover elements might be left behind, and not get inserted in the output array.
Driven from that observation, after traversing both the arrays and comparing elements, we will loop over the first array, if needed, to collect elements that were not visited. Similarly for the second array.
Coding that thought gives something like this:
void interclas(int *ptr,int *vec, int *c, int n) {
int i = 0, j = 0, tmp = 0;
// Traverse both arrays simultaneously,
// and choose the min of the two current elements.
// Increase the counter of the array who had
// the min current element.
// Increase the counter for the output array in
// any case.
while(i < n && j < n)
{
if(ptr[i] < vec[j])
{
c[tmp++] = ptr[i++];
}
else
{
c[tmp++] = vec[j++];
}
}
// Store remaining elements of first array
while (i < n)
c[tmp++] = ptr[i++];
// Store remaining elements of second array
while (j < n)
c[tmp++] = vec[j++];
}
Not the source of your problem, but Do I cast the result of malloc? No.
I have a homework problem that asks for my code to read a 10-length vector, order it in ascendant order and then print it. I'm trying to do this using a variable int k as a countable index, where the code verifies whether a particular position in the vector is greater than the other positions, and adds 1 to k for each smaller variable. Then, I create a second vector, and atrribute for its kth position this value of the first vector.
The compilation isn't pointing out any mistakes. The code runs, I inform the 10 values of the vector, then it returns a big number and crashes.
Could anyone help me? Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main ()
{
setlocale(LC_ALL, "Portuguese");
//creates two double vectors
double v[10], w[10];
//creates a int variable to be a countable index
int k = 0;
//asks for the user to inform the values of the vector
for (int i=0; i<=9; i++)
{
printf("Digite um nĂºmero:\n");
scanf("%lf", &v[i]);
}
//Here, I create this loop to verify whether each position of the vector v is greater than the other positions.
for (int j=9; j>=0; j--)
{
//For the case j=9, I verify if it is greater than all the predecessor values, and add 1 to k for each case
if (j==9)
{
for (int t=j-1; t>=0; t--)
{
if (v[j]>v[t])
{
k+=1;
}
}
//I attribute this value of v to the kth position of the new vector, and restart the countable index
w[k]=v[j];
k=0;
continue;
}
//I do the same for the case in which j=0, verifying whether it is greater than the subsequent values
else if (j==0)
{
for (int s=j+1; s<=9; s++)
{
if (v[j]>v[s])
{
k+=1;
}
}
w[k]=v[j];
k=0;
continue;
}
//For all the other values of the vector, I test both whether they are greater than the
//predecessors and the subsequent values, and add 1 to k for each case
else
{
for (int t=j-1; t>=0; t--)
{
if (v[j]>v[t])
{
k+=1;
}
}
for (int s=j+1; s<=9; s--)
{
if (v[j]>v[s])
{
k+=1;
}
}
//I attribute this value to the kth position of the new vector and restart the countable index
w[k]=v[j];
k=0;
}
//Here my loop ends
}
//I print the new vector
for (int p=0; p<=9; p++)
{
printf(" %lf ",w[p]);
}
system("pause");
return 0;
}
for (int s=j+1; s<=9; s--) should have s++. I don't see anything else wrong but I'll check with gdb if that doesn't fix it.
The following code is to find the number of Islands by considering 1 as island and 0 as water in a 2d array. Adjacent 1s belong to the same island and the island can be of any shape.It means
1 0 1
0 1 0
1 0 1
should give the number of islands as 1.This code runs and prints something for a 2 x 2 matrix, but shows "Abnormal termination error" for any higher order matrix.Whats wrong with the code and how to overcome the error? I just tried to make adjacent element zero recursively but ended up in this error.
#include <stdio.h>
#include <conio.h>
int a[10][10],m,n;
int islands=0;
void MakeZero(int,int);
void main()
{
int i,j;
clrscr();
printf("Enter the number of rows and columns :");
scanf("%d%d",&m,&n);
printf("Enter the matrix of 0s and 1s\n");
for(i=0;i<m;i++){
for(j=0;j<n;j++){
scanf("%d",&a[i][j]);
}
}
printf("Input Matrix is :\n");
for(i=0;i<m;i++){
for(j=0;j<n;j++){
printf("%d ",a[i][j]);
}printf("\n");
}
printf("The Number of Islands is :\n");
for(i=0;i<m;i++){
for(j=0;j<n;j++){
if(a[i][j])
{islands++;
MakeZero(i,j); }
}
}
printf("%d",islands);
getch();
}
void MakeZero(int i,int j)
{
if(i>m-1||j>n-1)
return;
else if(i==0&&j==0)
{
if(a[i][j+1]==1)MakeZero(i,j+1);
if(a[i+1][j+1]==1)MakeZero(i+1,j+1);
if(a[i+1][j]==1)MakeZero(i+1,j);
a[i][j+1]=a[i+1][j+1]=a[i+1][j]=0;
}
else if(i==m-1&&j==0)
{
if(a[i-1][j]==1)MakeZero(i-1,j);
if(a[i][j+1]==1)MakeZero(i,j+1);
if(a[i-1][j+1]==1)MakeZero(i-1,j+1);
a[i-1][j]=a[i][j+1]=a[i-1][j+1]=0;
}
else if(i==0&&j==n-1)
{
if(a[i][j-1]==1)MakeZero(i,j-1);
if(a[i+1][j-1]==1)MakeZero(i+1,j-1);
if(a[i+1][j]==1)MakeZero(i+1,j);
a[i][j-1]=a[i+1][j-1]=a[i+1][j]=0;
}
else if(i==m-1&&j==n-1)
{
if(a[i][j-1]==1)MakeZero(i,j-1);
if(a[i-1][j]==1)MakeZero(i-1,j);
if(a[i-1][j-1]==1)MakeZero(i-1,j-1);
a[i][j-1]=a[i-1][j]=a[i-1][j-1]=0;
}
else if(i==0&&(j>0&&j<n-1))
{
if(a[i][j-1]==1)MakeZero(i,j-1);
if(a[i][j+1]==1)MakeZero(i,j+1);
if(a[i+1][j-1]==1)MakeZero(i+1,j-1);
if(a[i+1][j+1]==1)MakeZero(i+1,j+1);
if(a[i+1][j]==1)MakeZero(i+1,j);
a[i][j-1]=a[i][j+1]=a[i+1][j-1]=a[i+1][j+1]=a[i+1][j]=0;
}
else if(i==m-1&&(j>0&&j<n-1))
{
if(a[i][j-1]==1)MakeZero(i,j-1);
if(a[i][j+1]==1)MakeZero(i,j+1);
if(a[i-1][j-1]==1)MakeZero(i-1,j-1);
if(a[i-1][j+1]==1)MakeZero(i-1,j+1);
if(a[i-1][j]==1)MakeZero(i-1,j);
a[i][j-1]=a[i][j+1]=a[i-1][j-1]=a[i-1][j+1]=a[i-1][j]=0;
}
else if(j==0&&(i>0&&i<m-1))
{
if(a[i-1][j]==1)MakeZero(i-1,j);
if(a[i+1][j]==1)MakeZero(i+1,j);
if(a[i-1][j+1]==1)MakeZero(i-1,j+1);
if(a[i+1][j+1]==1)MakeZero(i+1,j+1);
if(a[i][j+1]==1)MakeZero(i,j+1);
a[i-1][j]=a[i+1][j]=a[i-1][j+1]=a[i+1][j+1]=a[i][j+1]=0;
}
else if(j==n-1&&(i>0&&i<m-1))
{
if(a[i-1][j]==1)MakeZero(i-1,j);
if(a[i+1][j]==1)MakeZero(i+1,j);
if(a[i-1][j-1]==1)MakeZero(i-1,j-1);
if(a[i+1][j-1]==1)MakeZero(i+1,j-1);
if(a[i][j-1]==1)MakeZero(i,j-1);
a[i-1][j]=a[i+1][j]=a[i-1][j-1]=a[i+1][j-1]=a[i][j-1]=0;
}
else
{
if(a[i-1][j]==1)MakeZero(i-1,j);
if(a[i+1][j]==1)MakeZero(i+1,j);
if(a[i-1][j-1]==1)MakeZero(i-1,j-1);
if(a[i+1][j-1]==1)MakeZero(i+1,j-1);
if(a[i][j-1]==1)MakeZero(i,j-1);
if(a[i][j+1]==1)MakeZero(i,j+1);
if(a[i-1][j+1]==1)MakeZero(i-1,j+1);
if(a[i+1][j+1]==1)MakeZero(i+1,j+1);
a[i-1][j]=a[i+1][j]=a[i-1][j-1]=a[i+1][j-1]=a[i][j-1]=a[i][j+1]=a[i-1][j+1]=a[i+1][j+1]=0;
}
}
As M Oehm already said the problem is the time you mark a square as zero (or let's say "visited").
Your function MakeZero calls itself whenever it finds a square with a one in at least one of the neighbouring squares. Since you mark the square as 0 after calling MakeZero this results in a stack overflow whenever there are two neighbouring squares containing a 1 within your matrix. Since the first MakeZero finds a neighbouring 1and calls MakeZero which also finds a neighbouring 1and calls MakeZero again ... (you can see this if you look at the call stack from within the debugger).
Another thing about your MakeZero implementation: You are explicitly handling all special cases within MakeZero which make the code quite lengthy and harder to understand. I recommend to modify the function to only check if the input values are valid and the square is a one. If so set the value to zero and call MakeZero for all neighbouring squares (regardless of the current location within the matrix). An implementation would look like the following:
void MakeZero(int i, int j)
{
int x, y;
if ((i >= 0) && (i < m) && /* i index valid? */
(j >= 0) && (j < n) && /* j index valid? */
(a[i][j] == 1)) /* square is an island? */
{
a[i][j] = 0; /* remove 1 from matrix !!! */
/* iterate all surrounding squares */
for (x = (i - 1); x <= (i + 1); x++)
{
for (y = (j - 1); y <= (j + 1); y++)
{
MakeZero(x, y);
}
}
}
}
Your program provokes a stack overflow because your recursive function MakeZero() never reaches the base case. Using the same input example that you provide and just adding a printf ("%d %d\n", i, j); in the last else condition of Makezero, the program will output 1 1 indefinitely and you will never reach the condition (i > m-1 || j > n-1) that stops the program, since the values of m-1 and n-1 are 2 and i = 1 and j = 1 ad eternum.
Suggestion: try to find out what's going on when at least one of the values in the matrix a is 0, because the stack overflow seems to be happening only in this case.
I have currently learning backtracking and got stuck on the 8-queen problem, I am using a 8x8 matrix and I think I've got some problems regarding the matrix passing to functions, any help would be highly apreciated.I wouldn't mind if anyone would bring any optimisation to the code, thanks.
here is my code.
#include <stdio.h>
#include <stdlib.h>
#define MAX 7
//void azzera(int **mat);
void posiziona(int **mat, int r,int c);
void stampa(int **mat);
int in_scacchi(int **mat,int r ,int c);
int main(int argc, char *argv[])
{
int i=0,j=0;
int **mat=(int **)malloc(sizeof(int *)*MAX);
for(i=0;i<=MAX;i++){
mat[i]=(int *)malloc(MAX*sizeof(int));
for(j=0;j<=MAX;j++){
mat[i][j]=-1;
}
}
printf("insert pos of the first queen on the first row (1-8) :");
scanf("%d",&i);
i-=1;
mat[0][i]=1;
posiziona(mat,1,0);
stampa(mat);
system("PAUSE");
return 0;
}
/*void azzera(int **mat){
int i=0,j=0;
for(i=0;i<=MAX;i++){
for(j=0;j<=MAX;j++){
mat[i][j]=-1;
}
}
}*/
void stampa(int **mat){
int i,j;
for(i=0;i<=MAX;i++){
for(j=0;j<=MAX;j++){
printf(" %d",mat[i][j]);
}
printf("\n");
}
}
void posiziona(int **mat, int r,int c){
int i=0,riga=1,flag_col=-1,flag_riga=-1;
if(riga<=7&&flag_riga!=1){
if(flag_riga==1){
flag_riga=-1;
posiziona(mat,r+1,0);
}
else if(in_scacchi(mat,r,c)==1){
if(c==MAX)
posiziona(mat,r-1,0);
posiziona(mat,r,c+1);
}
else{
flag_riga=1;
}
}
}
int in_scacchi(int **mat,int r ,int c){
int i,j,k,m;
int flag=0;
//col
for(i=0;i<r;i++){
for(j=0;j<=c;j++){
if(((mat[i][j]==1)&&(c==j)))
return 1;
}
}
//diag \
for(i=0;i<MAX-r;i++){
for(j=0;j<=MAX-c;j++){
if(mat[MAX-r-i][MAX-c-j]==1)
return 1;
}
}
//antidiag
for(i=r+1;i<=MAX;i++){
for(j=c+1;j<=MAX;j++){
if(mat[r-i][c+j]==1) {
return 1;
}
}
}
return 0;
}
1. One glaring problem is the memory allocation:
int **mat=(int **)malloc(sizeof(int *)*MAX);
for(i=0;i<=MAX;i++){
mat[i]=(int *)malloc(MAX*sizeof(int));
Given that MAX is 7, both mallocs are allocating too little memory for the matrix (seven elements instead of eight).
To be honest, I'd rename MAX to SIZE or something similar, and change all your loops to use strict less-than, i.e.
for(i = 0; i < SIZE; i++) {
I would argue that this is slightly more idiomatic and less prone to errors.
2. I haven't tried to debug the logic (I don't think it's fair to expect us to do that). However, I have noticed that nowhere except in main do you assign to elements of mat. To me this suggests that the code can't possibly be correct.
3. Beyond that, it may be useful to observe that in a valid solution every row of the chessboard contains exactly one queen. This means that you don't really need an 8x8 matrix to represent the solution: an 8-element array of column positions will do.
edit In response to your question in the comments, here is a complete Python implementation demonstrating point 3 above:
def can_place(col_positions, col):
row = len(col_positions)
for r, c in enumerate(col_positions):
if c == col or abs(c - col) == abs(r - row): return False
return True
def queens(n, col_positions = []):
if len(col_positions) >= n:
pretty_print(n, col_positions)
return True
for col in xrange(n):
if can_place(col_positions, col):
if queens(n, col_positions + [col]):
return True
return False
def pretty_print(n, col_positions):
for col in col_positions:
print '.' * col + 'X' + '.' * (n - 1 - col)
queens(8)
Your matrix must iterate from 0 to MAX-1,
i.e
int **mat= malloc(sizeof(int *)*MAX);
for(i=0;i< MAX;i++){ //see for i<MAX
mat[i]= malloc(MAX*sizeof(int));
for(j=0;j<MAX;j++){ //see for j<MAX
mat[i][j]=-1;
}
}
malloc must be called with sizeof(...) * (MAX+1) in both the i- and j-loop.
Moreover, when I ran your program I got an access violation in the antidiag portion of in_scacchi(...) due to the fact that the code tries to access mat[r-i][c+j] which evaluates to mat[-1][1] because r==1 and i==2.
So there seems to be a logical error in your description of the anti-diagonal of the matrix.