2

I'm working on a code to read in a file and store the numbers in an array. The code itself is working, but the numbers are not being stored in the array properly and as such, I'm not getting the desired output. Here is my code:

/* code to solve a nxn system using the Gauss-Seidel method */
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <malloc.h>

#define MAX_DIM 100
#define MAX_ITER 500
#define TOLERANCE 1.e-6
void gauss_seidel(double **a, double b[], double x[], int n);
void main()
{
   int i, j, n;
   int violation_counter, answer;
   double sum;
   /* read in data */
   n = MAX_DIM + 1;
   FILE *inf, *onf;
   char fileName[256];
   printf("Enter file Name: ");
   scanf("%s", fileName);
   inf = fopen(fileName, "r");
   if(inf != NULL){
       while (n > MAX_DIM) {
           fscanf(inf, "%d", &n);
       }
       int *violation_rows = (int *)malloc(sizeof(int) * n);
       double **a = (double **)malloc(sizeof(double *) * n);
       double *b = (double *)malloc(sizeof(double) * n);
       double *x = (double *)malloc(sizeof(double) * n);
       for(i = 0; i < n; ++i){
           a[i] = (double *)malloc(sizeof(double) * n);
       }
       for (i = 0; i < n; i++) {
           for (j = 0; j < n; j++) {
               fscanf(inf, "%lf", &a[i][j], sizeof(a[i][j]));
               printf("%.2lf ", a[i][j]);
           }
           fscanf(inf, "%lf", &b[i], sizeof(b[i]));
           printf("-> %.2lf\n", b[i]);
       }
       printf("\n");
       /* test the convergence criterion */
       violation_counter = 0;
       for (i = 0; i < n; i++) {
           sum = 0.0;
           for (j = 0; j < n; j++)
               if (i != j)
                   sum = sum + fabs(a[i][j]);
           if (fabs(a[i][i]) < sum) {
               violation_rows[violation_counter] = i;
               violation_counter = violation_counter + 1;
           }
           if (a[i][i] == 0.0) {
               printf("Found diagonal element equal to zero; rearrange equations; exiting ...\n");
               exit(0);
           }
       }

       if (violation_counter > 0) {
           printf("The Gauss-Seidel convergence criterion is violated in %d rows out of %d\n", violation_counter, n);
           printf("Specifically, it was violated in rows:\n");
           for (i = 0; i < violation_counter; i++)
               printf("%d ", violation_rows[i]);

           printf("\n");

           printf("Enter 1 if you want to continue; any other number to abort : ");
           scanf("%d", &answer);

           if (answer != 1)
               exit(1);
           printf("Check results carefully\n\n");
       }
       /* initialize the solution vector -- initial guesses */
       for (i = 0; i < n; i++) {
           fscanf(inf, "%lf", &x[i], sizeof(x[i]));
           printf("x[%d] = %.2lf\n", i, x[i]);
       }

       fclose(inf);
       /* solve the system */
       gauss_seidel(a, b, x, n);
       /* output solution */

       printf("Enter file Name: ");
       scanf("%s", fileName);
       onf = fopen(fileName, "w");
       for (i = 0; i < n; i++)
           fprintf(onf, "x[%d]=%f\n", i, x[i]);
       fprintf(onf, "\n");
       fclose(onf);
   }
   else{
       printf("Can not open %s to read\n", fileName);
   }
   return;
}

The output of the code isn't storing the numbers properly. For example, my text file is as follows:

4

2   -1  0   0
-1  3   -2  0
0   -2  5   -3
0   0   -3  3

1
1.5
2.5
1.5

0
0
0
0

And the result I'm getting is

2 -1 0 0 -> -1
3 -2 0 0 -> -2
5 -3 0 0 -> -3
3 1 1.5 2.5 -> 1.5

As well as a diagonal convergence error. What's causing the file to not be stored properly?

EDIT: The numbers after the row of 4x4 (the four in the third block: 1, 1.5, 2.5, 1.5) are supposed to be on the other side of the arrow.

  • 1
    What should the `sizeof` parameters in the `fscanf` calls do? They are superflous. – M Oehm Apr 08 '16 at 06:21
  • 1
    I think you have a nesting error. You should read all `a[j][i]` first with a nested loop and then read all `b[i]` in a separate loop. You read `b[i]` in the same lop where you read the `a[j][i]`, but the input file doesn't seem to be organised like that. (Unless is misinterpret the input format.) – M Oehm Apr 08 '16 at 06:23
  • @MOehm I thought that they would perhaps help define the size of each line so the code would know when to break. Also, are you suggesting a completely separate `for` loop for the `b[i]` ? – Christian Littner Apr 08 '16 at 06:27
  • Switch on warnings and you will learn that the `sizeof` parameter isn't needed. Plain `fscanf` is a rather crude scanning function; the size of the data to scan must be given via the size modifiers, in your case the `l` in `%lf`. – M Oehm Apr 08 '16 at 06:30
  • And yes, I'm suggesting a separate loop. The stream is in line wise, left to right. Your code must read the data in the same way. I also suggest to separate printing from scanning and to scann everything, including `x` up front. – M Oehm Apr 08 '16 at 06:31
  • @MOehm your suggestion worked and now my code compiles and runs perfectly. Thank you so much for your help. If you want to mark an answer, I'd be more than willing to give you the points. – Christian Littner Apr 08 '16 at 06:37
  • Voting to close as why isn't my code working. Please first minimize with printf / gdb. – Ciro Santilli OurBigBook.com Apr 08 '16 at 06:43

2 Answers2

2

The way you read in the data doesn't match your input file. The file looks like

n

a11 a12 a13 
a21 a22 a23
a31 a32 a33

b1
b2
b3  

but you read it as if it were

n

a11 a12 a13 b1 
a21 a22 a23 b2
a31 a32 a33 b3

So you should read the b vector in a separate vector. I also suggest to read everything up front and to print it seperately after you have read in everything:

   // Scan first ...
   for (i = 0; i < n; i++) {
       for (j = 0; j < n; j++) {
           fscanf(inf, "%lf", &a[i][j]);
       }
   }

   for (i = 0; i < n; i++) {
       fscanf(inf, "%lf", &b[i]);        
   }

   for (i = 0; i < n; i++) {
       fscanf(inf, "%lf", &x[i]);
   }

   // ... then print
   for (i = 0; i < n; i++) {
       for (j = 0; j < n; j++) {
           printf("%.2lf ", a[i][j]);
       }
       printf("-> %.2lf\n", b[i]);
   }
   printf("\n");

   for (i = 0; i < n; i++) {
       printf("x[%d] = %.2lf\n", i, x[i]);
   }
   printf("\n");
M Oehm
  • 28,726
  • 3
  • 31
  • 42
0

I'm sorry to write this as an answer, not a comment (don't have the reputation yet), but I think that when you

fscanf(inf, "%lf", &a[i][j], sizeof(a[i][j])); 

there might be something wrong with the pointer to the two-dimensional array. (also I would try omitting the sizeof() here.)

This post talks about pointers to two dimensional arrays:

Create a pointer to two-dimensional array

all the best!

Community
  • 1
  • 1
curious_weather
  • 194
  • 1
  • 7