C programming, help!

Started by A Twig, December 03, 2007, 02:03:02 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

A Twig

Basically I'm writing a program that carries out circuit analysis. The circuit is a load of resistors connected in parallel. The idea is that you calculate the values at each node, anyway thats kind of by the by.

The point is I need to read these values in from a text file, put them into a matrix, carry out Gaussian elimination and then print the answers to a file. I have three files that I'm doing at the moment, and then will hopefully put them together. However, they won't compile, and I'm not sure why, plus I'm not even sure that they are going to do what I want when they do compile!

So if anyone's bored at work and wants to run their eyes over them, would be much appreciated.


File 1 - file reader#include<stdio.h>
int main (void)
{
char string [4][256];
int c_node_1[4], c_node_2[4], i, j, numberofelements;
double R[3][3], I[3], V[3], value[4];

FILE *fp; /* create a pointer to the file */
fp=fopen(&quot;cct.txt&quot;, &quot;r&quot;);  /* open the file*/
if (fp == NULL)
{
printf(&quot;Could not open the file.&quot;);
return(1);
  }
i=0;

while (fscanf(fp, &quot;%s %d %d %1f&quot;, string[i], &c_node_1[i], &c_node_2[i], &value[i])!=EOF){
printf(&quot;%s %d %d %1f %d\n&quot;, string[i], c_node_1[i], c_node_2[i], value[i], i);
i++;

numberofelements=i;

for (i=0;i<3;i++)
{
I[i]=0.0;
V[i]=0.0;
for(j=0;j<3,j++)
{
R[i][j]=0.0;
}
}

for(i=0;i<numberofelements;i++)

if string[i][0]=='R')
{
R[c_node_1[i]][c_node_1[i]]+=1.0/value[i];
R[c_node_2[i]][c_node_2[i]]+=1.0/value[i];
R[c_node_2[i]][c_node_1[i]]+=1.0/value[i];
R[c_node_1[i]][c_node_2[i]]+=1.0/value[i];
}
//if(string[i][0]=='I')
//{
//I[c_node_1[i]][c_node_2[i]]+=1.0/value[i];
//I[c_node_2[i]][c_node_2[i]]-=1.0/value[i];
//}
}

printf(&quot;%1f %1f %1f /n&quot; &quot;%1f %1f %1f /n&quot; &quot;%1f %1f %1f /n&quot;,R[1][1], R[1][2], R[1][3], R[2][1], R[2][2], R[2][3], R[3][1], R[3][2], R[3][3]);
return (0)
}

File 2 - Gaussian with hard-wired matrix to test it
#include
#include

/* int gauss(int nunknown, double matrix[3][3], double rhs[3], double ans[3]); */
int main(void)
{
double **mmm, *data, *ansss, *rhsss, tmp_matrix;
int nunknown, i;

/* assume you kow how many unknowns there are in the system */

nunknown = 3;

data = (double *)malloc(nunknown*nunknown*sizeof(double));
mmm = (double **)malloc(nunknown*sizeof*(double*));

for(i=0; i{
mmm[i]=data+(i*nunknown);
}
rhsss=(double *) malloc(nunknown * sizeof(double));
ansss=(double *) malloc(nunknown * sizeof(double));

mmm[0][0] = 1;
mmm[0][1] = 2;
mmm[0][2] = 1;
mmm[1][0] =1;
mmm[1][1] = 2;
mmm[1][2] = 3;
mmm[2][0] = -1;
mmm[2][1] = -3;
mmm[2][2] = 0;

ansss[0] = 0;
ansss[1] = 3;
ansss[2] = 2;

gauss(nunknown, mmm, rhsss, ansss);
return 0;
}
int gauss (int nunknown, double matrix[], double rhs[], double ans[])
{
double ttt, diag_term fact, **tmp_matrix, tmp_matrix;
int i, j, irow, icol, irow_1, n;

data = (double *)malloc(n*n*sizeof(double*));
tmp_matrix = (double **)malloc(nunknown*sizeof*(double *));


for(i=0; i<(nunknown); i++)
{
tmp_matrix = data+(i*nunknown);
File 3 - Gaussian which will take its values from file input (lots of compile errors...)#include
#include
 
 
int main(void)
{
double **mmm, *data, *ansss, *rhsss;
int nunknown, i;
 
/* Assume you know how many unkowns there are in the system */
nunknown = 3;
 
 
data = (double *)malloc(nunknown*nunknown*sizeof(double));
mmm = (double **) malloc(nunknown*sizeof*(double*));
 
for(i=0; i{
mmm[i] = data+(i*nunknown);
}
rhs = (double *) malloc(unknown*sizeof(double));
ans = (double *) malloc(unknown*sizeof(double));
 
gauss (nunknown, mmm, rhs[3], ans[3]);
return 0;
 
}
 
 
 
int gauss(int nunknown, double *tmp_matrix, double rhs[], double ans[])
{
 
double ttt, diag_term, fact, **tmp_matrix;
int i, j, irow, icol, irow_1, n, nunknown;
 
data=(double *)malloc(n*n*sizeof(double));
tmp_matrix=(double **) malloc(unknown * sizeof*(double*));
 
for (i=0; i{
tmp_matrix[i]=data+(i*unknown);
}
for (i=0; i{
    for (j=0; j{
tmp_matrix[i][j]=matrix[i][j];
 
ans[i] = rhs[i];
}
 
 
/*==========================================================*/
for(irow=0; i<(n-1); irow++)
    {    
    diag_term = tmp_matrix[irow][irow]
    for(irow_1=irow+1; irow_1        {
            fact = tmp_matrix[irow_1][irow]/diag_term;
            ans[icol] = ans[icol] / diag_term;
        }
    for(icol=1row+1; icol        {
        tmp_matrix[irow_1][icol] = tmp_matrix[irow_1][icol]-(tmp_matrix[irow]icol]*fact);            
        }
        ans[irow_1] = ans[irow_1]-(ans[irow] * fact);
        tmp_matrix[irow_1][irow]=0.0;
}
}
/*===========================================================*/
 
ans[nunknown-1] /= tmp_matrix[nunknown-1][nunknown-1]
 
/*===========================================================*/
/*--Back Substitution--*/
for (irow = nunknown-2; irow>0; irow--)
    {
    ttt=0.0;
     
    for (icol = nunknown-1; icol>irow; icol--)
        {
            ttt = ttt + tmp_matrix[irow][icol]*ans[icol];
        }
    ans[irow] - ans[irow] - ttt;
    ans[irow]=ans[irow]/tmp_matrix[irow][irow];
    }
return 0  
}
I'm programming in Ubuntu if that helps anyone...
[N~@] - Ninja Association
Although we may fade from life, life does not fade from our memories


A Twig

And this is the input text file:
Is 2 0 6
R1 1 0 2
R2 1 2 12
R3 1 3 12
R4 2 3 12
R5 3 0 8
[N~@] - Ninja Association
Although we may fade from life, life does not fade from our memories


Aquilifer

#2
It would help if you said what error message you get when trying to compile it. Anyway by quickly looking through it, seems... file 1... that

for(i=0;i
There is no opening { after the above statement, but there is the closing } some lines after it (few lines after //if(string
  • =='I') ).

So just add { after it the for(...)

There could be other errors too, but see if that fixes it.

Side note: I assume the indentation is not good just because you copied the files here. If not, I suggest indenting your files...lot easier to spot errors like that.

note 2: maybe check situations when dividing that the divisor is not zero.

EDIT:
- File 2, last lines. Again } missing in for loop plus the function ending }
- File 1, 2 and 3 all have 'main' function !? Have only 1 main (=the program entry point) and call other fucntions from it.
- Some returns are mising ; at teh end fo the line.
- If you write pure C, the compiler might not accept // comments (C++ style comments). /* */ comments are C style
- If you call a function in a file, the prototype for it has to visible. This is done usually so that if you split your program into several C files you have one header file per C file. E.g myfunc.c and myfunc.h and then you include the myfunc.h in the files where you call the functions in myfunc.c (#include "myfunc.h")

EDIT2: some more what I spotted...
- If you have a function parameter/argument like "int nunknown", you must not define a variable with the same name inside the fucntion like "int nunknown;", because it masks the parameter sent via the function call.
- If you use malloc to allocate memory you should make it a habit to free it after it is no longer needed. Even if the program is just one run type (the mem is freed anyway when the program quits, but it is a good habbit).
- ; missing from some other line ends too.
- File 3: At the bottom... "ans[irow] - ans[irow] - ttt;" What's this? Legal, but the answer is not saved anywhere.

EDIT3: Suggestions
- Use good variable, constant, function etc names. For example I find names like 'mmm' or 'ttt' are hard to understand and they really don't tell anything to me. Names like 'ans' or 'icol' are ok because a person who didn't write the program can understand them well. Meaningless names should be used only like loop variables (usually i, j and k).
- Use more comments. They are useful not for just other people who might have to look at your code, but also for yourself if you look at it much later when you don't remember it so well anymore.

A Twig

Awesome cheers, I'll implement those alterations and probably get back to you with more errors!

I'm eventually going to copy the gaussian function across and assimilate it into one big file, I was just doing it as seperate files to try and get them working individually (I suppose I could ahve just commented out a section at a time but I didn't think of that. I might go with the calling a function from another file idea now you mention it).
[N~@] - Ninja Association
Although we may fade from life, life does not fade from our memories


Aquilifer

I don't know how much you've done C programming but this is what I ment with the function prototypes or splitting into different files (the earlier explanation was bit hard to understand if you don't know the terms). I made a very simple example:

Example:


/* main.c */

#include <stdio.h>
#include &quot;happy.h&quot;  /* <--- include happy.h  */

int main(int argc, char *argv[])
{
   if( argc > 1 )
      happy(argv[1]);
   else
      printf(&quot;Give me a name as the param\n&quot;);

   return 0;
}



/* happy.c */

/* I'm a happy function */
void happy(const char *name)
{
   printf("Merry xmas and happy new year %s!!!\n", name);
}




/* happy.h */

/* List here function prototypes and other global definitions done in happy.c */
void happy(const char *name); /* I'm a function prototype for happy */




Function happy can be called in main.c because it is visible there after you have included the happy.h which has the happy prototype. Another way to make happy function usable in main.c would be to write it directly there. But in this case it has to be before any fucntion where it is called. For example it can be defined where the #include "happy.h" is now, but not after the main function because it is called from main. If you don't want that there is this sort of ordering limitation, you can just type the prototype where the include line is now. Actually you can think those #include lines as a synonyme for pasting the file contents into that place.

Carr0t

#5
Just as a thought, what sort of IDE/compiler are you using for this? If I try to compile something using gcc (the GNU C Compiler) it gives me helpful error messages about what it thinks is actually wrong with the code.

For example, I just tried to compile Aquilifier's code, and got the following error message:

$ gcc happy.c main.c
happy.c: In function &#8216;happy&#8217;:
happy.c:6: warning: incompatible implicit declaration of built-in function &#8216;printf&#8217;

Which tells me it couldn't find printf, one of the basic C functions. On checking, this was because although I was including stdio.h (the basic C input/output functions library) in main.c, it wasn't included in happy.c. Ater fixing this:

meyersd@mustrum ~/test
$ gcc happy.c main.c
meyersd@mustrum ~/test
$ ls
./  ../  a.out  happy.c  happy.h  main.c
meyersd@mustrum ~/test
$ ./a.out Foo
Merry xmas and happy new year Foo!!!

Voila. What kind of error messages are you getting when compiling?
[imga=right]http://77.108.129.49/fahtags/ms10.jpg[/imga]Wash: This is going to get pretty interesting.
Mal: Define interesting...
Wash: Oh god, oh god, we\'re all going to die?

Carr0t

For example, on trying to compile your first file, it initially throws up some basic syntax errors:

$ gcc main.c
main.c: In function ‘main’:
main.c:27: error: expected ‘;’ before ‘)’ token
main.c:35: error: expected ‘(’ before ‘string’
main.c:35: error: expected statement before ‘)’ token
main.c:52: error: expected ‘;’ before ‘}’ token

Check your code on those lines. Line 27 you've used a ',' instead of a ';' in your for statement. Line 35 you haven't opened your if statement with a '(', etc etc...

Also, what editor are you using? I'm using vim for this, and find it's syntax highlighting, auto-indentation, ability to jump straight to a line the compiler is complaining about etc etc to be very handy.
[imga=right]http://77.108.129.49/fahtags/ms10.jpg[/imga]Wash: This is going to get pretty interesting.
Mal: Define interesting...
Wash: Oh god, oh god, we\'re all going to die?

A Twig

I'm using gedit - I take it that there are better alternatives? I would prefer something that picks up possible errors in "real-time" rather than waiting until I compile. I know my MATLAB does this.

Cheers for the help guys, I'm having another crack at it today, need to get it sorted by Friday :(
[N~@] - Ninja Association
Although we may fade from life, life does not fade from our memories


Carr0t

I've not heard of an IDE/editor for any language that will pick up syntax errors before compilation i'm afraid. Even interpreted languages like Perl or Ruby only give errors when you actually try to run the code, rather than when you're writing it, at least in any editor i've used. Otherwise you'd end up with it constantly flagging an error if you were in the middle of writing an if block, for example, and thus hadn't closed it yet.

What language does MATLAB use? Isn't that R, or something of that sort? I've never used it so i'm not sure. Possibly some paid for Windows IDEs do on-the-fly syntax checking, and Eclipse may do it for Java, but i've not heard fo a free one for C that I would think would do it.

As to what editor to use, I *would* suggest vim, as i'm a bit of a vim zealot. However learning how to effeciently use vim would probably take more time than you have to spare if this has to be in by Friday (and gvim would be better, then you have graphical menus and such instead of having to remember all the keyboard shortcuts). Emacs is more bloated, but that's only comparative. It's not slow or anything, and is probably easier to get to grips with than vim. It'll also do stuff like jump-to-line, syntax highlighting, code indentation etc etc.
[imga=right]http://77.108.129.49/fahtags/ms10.jpg[/imga]Wash: This is going to get pretty interesting.
Mal: Define interesting...
Wash: Oh god, oh god, we\'re all going to die?

A Twig

I've got it to compile but the terminal won't recognise the command to run the file?
I've used:
 ./fileinput and it says I don't have permission, so I used:
sudo ./fileinput and it says no such command exists...
[N~@] - Ninja Association
Although we may fade from life, life does not fade from our memories


A Twig

#10
Right, I've got the file input bit to compile (reproduced below), I ran it, but....

#include<stdio.h>
int main (void)
{
char string [4][256];
int c_node_1[4], c_node_2[4], i, j, numberofelements;
double R[3][3], I[3], V[3], value[4];

FILE *fp; /* create a pointer to the file */
fp=fopen(&quot;cct.txt&quot;, &quot;r&quot;);  /* open the file*/
if (fp == NULL)
{
printf(&quot;Could not open the file.&quot;);
return(1);
  }
i=0;

while (fscanf(fp, &quot;%s %d %i %1f&quot;, string[i], &c_node_1[i], &c_node_2[i], &value[i])!=EOF){
printf(&quot;%s %d %i %1f %d\n&quot;, string[i], c_node_1[i], c_node_2[i], value[i], i);
i++;

numberofelements=i;

for (i=0;i<3;i++)
{
I[i]=0.0;
V[i]=0.0;
for(j=0;j<3;j++)
{
R[i][j]=0.0;
}
}

for(i=0;i<numberofelements;i++)

if (string[i][0]=='R')
{
R[c_node_1[i]][c_node_1[i]]+=1.0/value[i];
R[c_node_2[i]][c_node_2[i]]+=1.0/value[i];
R[c_node_2[i]][c_node_1[i]]+=1.0/value[i];
R[c_node_1[i]][c_node_2[i]]+=1.0/value[i];
}
//if(string[i][0]=='I')
//{
//I[c_node_1[i]][c_node_2[i]]+=1.0/value[i];
//I[c_node_2[i]][c_node_2[i]]-=1.0/value[i];
//}
}

printf(&quot;%1f %1f %1f \n&quot; &quot;%1f %1f %1f \n&quot; &quot;%1f %1f %1f \n&quot;,R[1][1], R[1][2], R[1][3], R[2][1], R[2][2], R[2][3], R[3][1], R[3][2], R[3][3]);
return (0);
}

The output was:

//This bit should be the scanned in values from the input file (which don't match up at the mo)
Is 2 0 -0.000000 0
R1 1 0 0.000000 1
R2 1 2 0.000000 2
2 134519140 1 0.000000 3
R1 1 0 0.000000 1
2 1 2 0.000000 2
R4 2 3 0.000000 3
2 4 3 0.000000 4
R5 3 0 0.000000 5
//This bit below should be the values stored in a matrix
0.000000 0.000000 0.000000
0.000000 0.000000 inf
0.000000 0.000000 inf

It is just supposed to initially print the scanned in values from the input file again, then put them into a matrix which can then be manipulated using gaussian elimination.
I'm really obviously not getting something pretty key here...
[N~@] - Ninja Association
Although we may fade from life, life does not fade from our memories


Aquilifer

#11
About why the code I gave didn't compile was that I had forgotten #include from the happy.c file. I didn't try compile it, I only typed it straight into this forum. There you see how easy it is to make mistakes or forget some simple thing :rolleyes:

@Twig

It is hard to follow the code when the indentation is not used.

You could get inf (infinite) at least when you divide by zero (value=0.0) in places like...
R[c_node_1][c_node_2]+=1.0/value;

...but normally you should get division by zero exception. So that's why I suspect that the R array is not initialized in the beginning and it can contain just about anything (uninitialzed variables are not necessarily 0). :g:


That is also bit suspicious. I'm not sure what you are/are supposted to put at those c_node_1 and c_node_2, because if they are too big you can easily point outside the R array. What happens then is pure luck. It can crash or your program can behave oddly.

Are you trying to count the number of elements by counting the lines in the file by incrementing i? If this is so, the code should be...


while (fscanf(fp, &quot;%s %d %i %1f&quot;, string[i], &c_node_1[i], &c_node_2[i], &value[i])!=EOF){
   printf(&quot;%s %d %i %1f %d\n&quot;, string[i], c_node_1[i], c_node_2[i], value[i], i);
   i++;
} /* <---- THIS WAS MISSING!!!! */

If this is the case, you have again one example why it is a very good idea to use indentation


When you have finished reading the file put fclose(fp); at the end (closes the file).

EDIT: Actually R was initialized...Damn...it's hard to follow...maybe I should try tabulate it.

Carr0t

Right, to start with you're trying to scan in a double using '%1f'. This is meaningless. A double is a double length floating point precision number, so it's '%lf' for 'long float', not '%1f'. Took me yonks to spot that, as the two are very similar when typed ;) That'll get rid of your input errors, when combined with Aqui's added close brace on your while loop (and close your file!).

Do the same on your printf at the end that prints the contents of R, and you'll get some values output, with no inf values suggesting a divide by zero error or similar (though you should probably still check for it, just in case). Whether they're the *right* values, I have no idea ;)

Be aware that a double, while it will store a value to the maximum precision it allows, will still only display it by default to 6 decimal places. Use the '%X.Ylf' format string to change the number of digits it displays before and after the decimal point by default (I think that's how it works, anyways. My C is *very* rusty. I've not coded in it at all for 5 years now...).
[imga=right]http://77.108.129.49/fahtags/ms10.jpg[/imga]Wash: This is going to get pretty interesting.
Mal: Define interesting...
Wash: Oh god, oh god, we\'re all going to die?

Aquilifer

#13
I tryed to tabulate/indent the file as I understood you ment it. Also aded some comments and few changes. This is how I would do it, except I would also split it more into different functions.


#include<stdio.h>

/*
You should use this macro when defining the arrays, but I'm not sure why you have sometimes 4 cells (is it number of elements+1 or what) - e.g int R[MAX_ELEMENTS][MAX_ELEMENTS];*/
#define MAX_ELEMENTS    3

int main (void)
{
   char    string [MAX_ELEMENTS+1][256];
   int     c_node_1[MAX_ELEMENTS+1], c_node_2[MAX_ELEMENTS+1]; /* WHAT AN EARTH ARE THESE? MAYBE ADD A COMMENT? */
   int     i, j, numberofelements;
   double  R[MAX_ELEMENTS][MAX_ELEMENTS], I[MAX_ELEMENTS], V[MAX_ELEMENTS], value[MAX_ELEMENTS+1];

   FILE *fp; /* create a pointer to the file */
   fp=fopen(&quot;cct.txt&quot;, &quot;r&quot;);  /* open the file*/
   if (fp == NULL)
   {
      printf(&quot;Could not open the file.\n&quot;);
      return 1;
   }

   /* Scans the initial values from the file */
   i=0;
   while (fscanf(fp, &quot;%s %d %i %lf&quot;, string[i], &c_node_1[i], &c_node_2[i], &value[i]) != EOF){
      printf(&quot;%s %d %i %lf %d\n&quot;, string[i], c_node_1[i], c_node_2[i], value[i], i);
      i++;
   }
   numberofelements = i;
   fclose(fp); /* Don't forget to close the file */

   /* Aquilifer added as a simple error trap */
   if( numberofelements == 0 ){
      printf(&quot;No elements found\n&quot;);
      return 1;
   } else if( numberofelements > MAX_ELEMENTS ){
      printf(&quot;Too many elements (has %d)\n&quot;, numberofelements);
      return 1;
   }

   /* Clears the R, V, and I tables */
   for (i=0; i<MAX_ELEMENTS; i++){
      I[i] = 0.0; V[i] = 0.0;
      for(j=0; j<MAX_ELEMENTS; j++)
         R[i][j] = 0.0;
   }

   /* Forks the resistance values in the R table */
   for(i=0; i<numberofelements; i++){
      if( string[i][0] == 'R'){
         if( value[i] == 0.0 ){
            printf(&quot;Oh dear...we are trying to divide by zero...program stopped\n&quot;);
            return 2;
         }
         if( c_node_1[i] > numberofelements || c_node_2[i] > numberofelements ||
               c_node_1[i] < 0 || c_node_2[i] < 0 ){
            printf(&quot;Oh dear...getting out of array...program stopped\n&quot;);
            return 2;
         }
         R[c_node_1[i]][c_node_1[i]] += 1.0/value[i];
         R[c_node_2[i]][c_node_2[i]] += 1.0/value[i];
         R[c_node_2[i]][c_node_1[i]] += 1.0/value[i];
         R[c_node_1[i]][c_node_2[i]] += 1.0/value[i];
      }
      //if(string[i][0]=='I')
      //{
        //I[c_node_1[i]][c_node_2[i]]+=1.0/value[i];
        //I[c_node_2[i]][c_node_2[i]]-=1.0/value[i];
      //}
   }

   /* prints the R table */
   /* ERROR WAS HERE!? array indexes gor from 0 to 2... e.g R[0][0], not R[1][1] */
   printf(&quot;%g %g %g \n&quot;
          &quot;%g %g %g \n&quot;
          &quot;%g %g %g \n&quot;,
          R[0][0], R[0][1], R[0][2],
          R[1][0], R[1][1], R[1][2],
          R[2][0], R[2][1], R[2][2]);

   return 0;
}


EDIT:
@Carrot
"Right, to start with you're trying to scan in a double using '%1f'. This is meaningless. A double is a double length floating point precision number, so it's '%lf' for 'long float', not '%1f'. Took me yonks to spot that, as the two are very similar when typed ;)"

:doh: I missed that too. Fixed in the code :)

A Twig

Awesome cheers guys, with those changes made it all works, and I think the numbers are about right.

Aquilifer, when I compiled and ran your final version I got Segmentation Error(core dumped)!?

I've tabbed it properly, I realised I'd missed another { as well, but its all good now. Right, just got to get this Gaussian elimination working now! Argh!!!! As I never seem to make the LAN when this is all sorted I'll send you guys some beer money!
[N~@] - Ninja Association
Although we may fade from life, life does not fade from our memories