By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,647 Members | 1,706 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,647 IT Pros & Developers. It's quick & easy.

Reading from a file into an array of structures

suzee_q00
P: 16
I will admit that lots of times the obvious eludes me and this is most likely one of those times but if anyone has any ideas on what I can do to make this code work, I would greatly appreciate it. Here's the code:
Expand|Select|Wrap|Line Numbers
  1.  
  2. while ( ( fgets ( buf, BUFLEN, fin ) ) != NULL ) /* pulls a line from "fin" up to the length of BUFLEN and stores it in "buf" */
  3.     rmNl ( buf ); /* remove new line */
  4. if ( !lineWithBlanks ( buf ) )
  5.     {
  6. for (i = 0; buf[i] != '\0'; i++) /* start at index 0 and go through buf until you reach the null character */
  7. {
  8. if (sscanf (buf, "%s %s %s", stuArr[i].fName, stuArr[i].lName, errstr) != 2)
  9.      {
  10.      fprintf (stderr, "ERROR: Incorrect number of entries for the name field of %s, %s, not written to file\n", stuArr[i].lName, stuArr[i].fName);
  11.      continue;
  12.      }
  13.      if (sscanf (buf, "%d %d", &stuArr[i].id, errnum) != 1)
  14.      {
  15.      fprintf (stderr, "ERROR: Incorrect number of entries for the ID field of %s, %s", stuArr[i].lName, stuArr[i].fName);
  16.      continue;
  17.      }
  18.      /* read homework scores into seperate fields of hw */     
  19.      if (sscanf (buf, "%d %d %d %d %d %d", &stuArr[i].hw[0], &stuArr[i].hw[1], &stuArr[i].hw[2], &stuArr[i].hw[3], &stuArr[i].hw[4], &errnum) != NUM_HW)
  20. {     
  21.          fprintf (stderr, "ERROR: Incorrect number of entries for the homework field of %s, %s", stuArr[i].lName, stuArr[i].fName);
  22.          continue;
  23.          }
  24.      if (sscanf (buf, "%d %d %d %d", &stuArr[i].exm[0], &stuArr[i].exm[1], &stuArr[i].exm[2], &errnum) != NUM_EXM)
  25.          {
  26.          fprintf (stderr, "ERROR: Incorrect number of entries for the exam field of %s, %s", stuArr[i].lName, stuArr[i].fName);
  27.          continue;
  28.          }
  29.          stuArr[i].hwAvg = figureAverages (stuArr[i].hw, NUM_HW);
  30.          stuArr[i].exmAvg = figureAverages (stuArr[i].hw, NUM_EXM);
  31.          stuArr[i].grade = ltrGrade(stuArr[i].hwAvg + stuArr[i].exmAvg);
  32.  
  33. } /* end for */
  34.     }
  35. else
  36.  
and what it is supposed to do is read "fin" which has information in the form of: firstname lastname
ID
grades
other grades stores the output of fin into a student structure and takes the grades and figures an average for each line and then figures a letter grade based on the averages.

I have myself convinced that if I get this program to fill the structure correctly I could actually do the rest. I know that I need to get rid of my first for statement but I am not sure what to do in it's place so I am leaving it there as symbol of my ineptitude.
Mar 1 '06 #1
Share this Question
Share on Google+
9 Replies


Banfa
Expert Mod 5K+
P: 8,916
You haven't made it clear if the data is all on one line in the file or on multiple lines

firstname lastname ID HW_grades EXM_grades

or

firstname lastname
ID
HW_grades
EXM_grades

In the first case (everything on the same line) you can get rid of the for loop and just use 1 big sscanf.

The second case is a bit more tricky, you have to know which line you are on, also if the is a bad record then it becomes hard to locate the start of the next record. The solutions the these are make every record start with known header, for instance the word STUDENT on a line by it self and use a state machine to record what line of the current record you are reading. So assuming that the records appear in the file like so

STUDENT
firstname lastname
ID
HW_grades
EXM_grades

You might have some code of this structure

Expand|Select|Wrap|Line Numbers
  1. typedef enum read_state {
  2.   RS_STUDENT,
  3.   RS_NAME,
  4.   RS_ID,
  5.   RS_HW_GRADES,
  6.   RS_EXM_GRADES
  7. } READ_STATE;
  8.  
  9. bool ReadRecords( FILE *fin )
  10. {
  11.   READ_STATE state = RS_STUDENT;
  12.   char buf[BUFLEN];
  13.  
  14.   while ( ( fgets ( buf, BUFLEN, fin ) ) != NULL )
  15.   { 
  16.     rmNl ( buf ); /* remove new line */
  17.     if ( BlankLine( buf ) )
  18.       continue;
  19.  
  20.     switch( state )
  21.     {
  22.     case RS_STUDENT:
  23.       if ( <buf contains STUDENT> )
  24.       {
  25.         state = RS_NAME;
  26.         locate next record to fill
  27.       }
  28.       break;
  29.  
  30.     case RS_NAME:
  31.       Parse Name from buf
  32.       if ( Name Parsed OK )
  33.         state = RS_ID;
  34.       else
  35.       {
  36.         print error message
  37.         state = RS_STUDENT;
  38.       }
  39.       break;
  40.  
  41.     case RS_ID:
  42.       Parse ID from buf
  43.       if ( ID Parsed OK )
  44.         state = RS_HW_GRADES;
  45.       else
  46.       {
  47.         print error message
  48.         state = RS_STUDENT;
  49.       }
  50.       break;
  51.  
  52.     case RS_HW_GRADES:
  53.       Parse HW Grades from buf
  54.       if ( HW Grades Parsed OK )
  55.         state = RS_EXM_GRADES;
  56.       else
  57.       {
  58.         print error message
  59.         state = RS_STUDENT;
  60.       }
  61.       break;
  62.  
  63.     case RS_EXM_GRADES:
  64.       Parse Exm Grades from buf
  65.       if ( Exm Grades Parsed OK )
  66.       {
  67.         complete calculated parts of record (create averages etc)
  68.       }
  69.       else
  70.       {
  71.         print error message
  72.       }
  73.       state = RS_STUDENT;
  74.       break;
  75.     }
  76. }
  77.  
Note that you are using i to indicate which record in the stuArr array to use but this variable should only be incremented every time you start a new record (from the RS_STUDENT state).

Also note in this structure if a parse error occurs then we always go back to the RS_STUDENT state, that is if there is an error in the data for a record then the whole record is skipped and we start again at the next record.
Mar 1 '06 #2

suzee_q00
P: 16
Sorry I was not clear in my earlier post. Banfa you did a great job in devining what my structure should look like. I have it declared as:

typedef struct student
{
char fName [NAME_LEN];
char lName [NAME_LEN];
int id;
int hw [NUM_HW];
int exm [NUM_EXM];
float hwAvg;
float exmAvg;
char grade;
} STUDENT;
I thought of using one scanf but then I was unsure of how to do the error checking. This is what a good student record from the input file would look like:

John Doe
1111
98 87 69 97 89
85 91 88

a bad record might look like

54 59 57 53 51
59 53 57
Jane Doe_ErrorInAcct
1111

I don't think the case statements will work since I am reading blind. I have tried a few different things but I am still not getting what I need. I don't understand how such a simple task can go so very wrong. In the beginning I was having the trouble that if a bad line was encounted the code was grabbing the very next line and starting over. The problem with that is, that the next line might be mid record so after it encounters the first bad line that doesn't happen to be at the end of a record it will never come out right again. I created 4 character arrays to read the lines into then I sscanf them into my structure and check them for error. The code looks like this:
while ( ( fgets ( buf, BUFLEN, fin ) ) != NULL ) /* pulls a line from "fin" up to the length of BUFLEN and stores it in "buf" */
{
rmNl ( buf ); /* remove new line */
if ( !lineWithBlanks ( buf ) )
{
strcpy (firstline, buf);
fgets ( buf, BUFLEN, fin );
strcpy (secondline, buf);
fgets ( buf, BUFLEN, fin );
strcpy (thirdline, buf);
fgets ( buf, BUFLEN, fin );
strcpy (fourthline, buf);

if (sscanf (firstline, "%s %s %s", stuArr[i].fName, stuArr[i].lName, errstr) != 2)
{
fprintf (stderr, "ERROR: Incorrect number of entries for the name field of %s, %s, not written to file\n", stuArr[i].lName, stuArr[i].fName);
continue;
}
if (sscanf (secondline, "%d, %d", &stuArr[i].id, &errnum) != 1)
{
fprintf (stderr, "ERROR: Incorrect number of entries for the ID field of %s, %s\n", stuArr[i].lName, stuArr[i].fName);
continue;
}
/* read homework scores into seperate fields of hw */
if (sscanf (thirdline, "%d %d %d %d %d %d", &stuArr[i].hw[0], &stuArr[i].hw[1], &stuArr[i].hw[2], &stuArr[i].hw[3], &stuArr[i].hw[4], &errnum) != NUM_HW)
{
fprintf (stderr, "ERROR: Incorrect number of entries for the homework field of %s, %s\n", stuArr[i].lName, stuArr[i].fName);
continue;
}
if (sscanf (fourthline, "%d %d %d %d", &stuArr[i].exm[0], &stuArr[i].exm[1], &stuArr[i].exm[2], &errnum) != NUM_EXM)
{
fprintf (stderr, "ERROR: Incorrect number of entries for the exam field of %s, %s\n", stuArr[i].lName, stuArr[i].fName);
continue;
}
stuArr[i].hwAvg = figureAverages (stuArr[i].hw, NUM_HW); /* NUM_HW is defined to be 5 */
stuArr[i].exmAvg = figureAverages (stuArr[i].hw, NUM_EXM); /* NUM_EXM is defined to be 3 */
stuArr[i].grade = ltrGrade(stuArr[i].hwAvg + stuArr[i].exmAvg);
i++
} /* end if !lineWithBlanks */


If an error line is found I am thinking that it will break out of the if() and go back up to while() and start again with the next record. Instead it processes the first record and maybe part of another then it quits. During runtime I get error messages with numbers instead of names so I know it is still off some how in its looping ERROR: Incorrect number of entries for the name field of 73, 69, not written to file. I also get lines with out numbers or names like the following which I certainly should not get because if it's a line with a blank it should not make it beyond the first if. ERROR: Incorrect number of entries for the name field of , , not written to fileFor some odd reason it prints the 1st and then 13th or so record. Finally it prints a couple of the records, the 1st and the 14th.
================================================== ===
PRINTING ALL RECORDS
================================================== ===
Student Name Id HAvg EAvg Grade
------------------------------------------------------------------------------

John Doe 1111 -241717232.000000 -241717184.000000 F
Troy Marshall 1113 -215262912.000000 -215262880.000000 F
89 73 5552 0.000000 0.000000
0 0.000000 0.000000
Mar 12 '06 #3

Banfa
Expert Mod 5K+
P: 8,916
Do I take it then that you have not control of the format of the input file?

This will make your task extremely hard, the problem is that when you get corrupted data not only will you sscanf not work but a situation could easily occur that puts you out of sync in the file.

The problem is that if a record is corrupted then you have absolutely no garuntee about what it contains. A consequence of this is that you have no guaranttee that it even contains the correct number of lines, after all the end of line character is just another character and as easily corrupted, missed or inserted by accident as any other character.

I have a couple of suggestions
  1. Make all you error messages output the line of the file where the error occured. While this wont actually help solve the problem this sort of information is always useful. (and posting the output error messages (or the first 10 or so) would be useful.
  2. The way you read the lines from the file, i.e. skip any blank lines and starting with the first non-blank line found read 4 lines assuming they contain the data is prone to errors if there are blank lines between the lines of data in a record because you will not end up with your 4 line buffers with actual data in them. You could perhaps think about putting a wrapper round the function fgets that will return the next non-blank line in the file and call that from the while loop.
  3. I talked about trying to located the start of a record by inserting a record start marked ("STUDENT" in my original post). However if you can't then you should examine the data for unique features of the first line of the record. The the case of your data there is something very obvious, the first line of the record is a name and contains only letters and the other 3 lines contain only digits. The code will be more complex but you need to write something that will find the first line that contains only letters and white space then read the next 3 non-blank lines checking they contain only numbers, if they don't then if any of them contain only letters and white space it could be the start of the next record otherwise start looking again for a non blank line containing only letters and numbers. PSEUDO code something like

    Expand|Select|Wrap|Line Numbers
    1. while( not EOF )
    2. {
    3.   Line1 = GetNotBlankLine()
    4.  
    5.   do
    6.   {
    7.     if ( Line1 Contains Only Letters and White Space )
    8.     {
    9.       Line2 = GetNotBlankLine()
    10.  
    11.       if ( Line2 Does Not Contain only Digits and White Space )
    12.       {
    13.         if ( Line2 Contains Only Letters and White Space )
    14.         {
    15.           Line1 = Line2
    16.           continue;   /* Start looking for digit data lines */
    17.         }
    18.         else
    19.         {
    20.           break;   /* Start looking for letter data lines */
    21.         }
    22.       }
    23.  
    24.       Line3 = GetNotBlankLine()
    25.  
    26.       if ( Line3 Does Not Contain only Digits and White Space )
    27.       {
    28.         if ( Line3 Contains Only Letters and White Space )
    29.         {
    30.           Line1 = Line3
    31.           continue;   /* Start looking for digit data lines */
    32.         }
    33.         else
    34.         {
    35.           break;   /* Start looking for letter data lines */
    36.         }
    37.       }
    38.  
    39.       Line4 = GetNotBlankLine()
    40.  
    41.       if ( Line4 Does Not Contain only Digits and White Space )
    42.       {
    43.         if ( Line4 Contains Only Letters and White Space )
    44.         {
    45.           Line1 = Line4
    46.           continue;   /* Start looking for digit data lines */
    47.         }
    48.         else
    49.         {
    50.           break;   /* Start looking for letter data lines */
    51.         }
    52.       }
    53.  
    54.       Parse Data in Line1, Line2, Line3 and Line4
    55.     }
    56.   }
    57.   while( not EOF and not Data Parsed );
    58. }
    59.  
    You can see that this code attempts to make sure that the line buffers contain something that stands a chance of being valid before trying to parser them.

I don't understand how such a simple task can go so very wrong.
lol, the problem here is that the task is simple only in the working case. As with almost all computing tasks coding the working case is 10% - 20% of the task and coding to protect against all the interesting and varied error cases is 80% - 90% of the task. So a task that at first site appears to be very simple can be extremely complex.

And finally, when posting code in order to preserve the white space and make it more readable enclose it in the forum tags
Expand|Select|Wrap|Line Numbers
  1.  and 
so

for( x=0; x<200; x++ )
{
if ( (x % 7) == 0 )
{
printf( "%d is a multiple of 7\n", x );
}
}

becomes

Expand|Select|Wrap|Line Numbers
  1. for( x=0; x<200; x++ )
  2. {
  3.   if ( (x % 7) == 0 )
  4.   {
  5.     printf( "%d is a multiple of 7\n", x );
  6.   }
  7. }
  8.  
Mar 13 '06 #4

suzee_q00
P: 16
I do have limited guarantees as to the format. I am allowed to assume that each account will consist of 4 lines of data though there may be empty lines in between. The name may not always come first, they may try to include an extra name on the same line (Jane Doe - OK, Mary Jane Doe - Not OK) they may have more or less than the allowable homework and exam grades so I need to be able to handle those sorts of things. I don't have to worry about records with less than 4 lines. I thought the temporary storage would work to store things so that I could throw out all for line if one was bad. I guess I was wrong.

I think my problem is in my placement of the fgets after the strcpy's. The lines that it gets at the point won't hit the lineWithBlanks test. I think I have a handle on the problem but have no idea how to get new lines, keep my code from becoming cumbersome and get rid of bad data. :confused: I was trying not to make this any longer than necessary. I am so wrapped up in it maybe I am leaving out something that might make it all make sense to someone with better perspective. Here is my actual output. The first error I should not get (in theory) because if the line is blank, it should not make if by if(!lineWithBlanks). I am not seeing how that line sneaks in. I guess that's why all the rest of the lines are goofed up.

ERROR: Incorrect number of entries for the name field of , , not written to file
ERROR: Incorrect number of entries for the name field of 73, 69, not written to file
ERROR: Incorrect number of entries for the name field of 91, 73, not written to file
ERROR: Incorrect number of entries for the name field of 89, 91, not written to file
ERROR: Incorrect number of entries for the name field of 0, 67, not written to file
ERROR: Incorrect number of entries for the name field of 69, 75, not written to file
ERROR: Incorrect number of entries for the name field of 69, 8888, not written to file
ERROR: Incorrect number of entries for the name field of 69, 9999, not written to file
ERROR: Incorrect number of entries for the exam field of Doe_ErrorInAcct, Jane
ERROR: Incorrect number of entries for the name field of 33, 54, not written to file
ERROR: Incorrect number of entries for the name field of 82, 83, not written to file
ERROR: Incorrect number of entries for the name field of 78, 77, not written to file
ERROR: Incorrect number of entries for the name field of 123, 4442, not written to file
ERROR: Incorrect number of entries for the ID field of Palmer_ErrorInAcct, Brandon
ERROR: Incorrect number of entries for the name field of 59, 54, not written to file
ERROR: Incorrect number of entries for the name field of 59, 1114, not written to file
ERROR: Incorrect number of entries for the name field of 59, 4445, not written to file
ERROR: Incorrect number of entries for the name field of 59, 1115, not written to file
ERROR: Incorrect number of entries for the homework field of Monty_ErrorInAcct, Gage
ERROR: Incorrect number of entries for the exam field of Nibert_ErrorInAcct, Laura
ERROR: Incorrect number of entries for the name field of Nibert_ErrorInAcct, Laura, not written to file
ERROR: Incorrect number of entries for the name field of 90, 83, not written to file
ERROR: Incorrect number of entries for the name field of 78, 77, not written to file
ERROR: Incorrect number of entries for the name field of 79, 83, not written to file
ERROR: Incorrect number of entries for the name field of 90, 83, not written to file
ERROR: Incorrect number of entries for the name field of 73, 89, not written to file

================================================== ===
PRINTING ALL RECORDS
================================================== ===
Student Name Id HAvg EAvg Grade
------------------------------------------------------------------------------

John Doe 1111 -241643504.000000 -241643456.000000 F
Troy Marshall 1113 -216027248.000000 -216027216.000000 F
89 73 5552 0.000000 0.000000
0 0.000000 0.00000

This is the sample input file I am working from:
John Doe
1111
98 87 69 97 89
85 91 88

Bill Doe
2222
77 78 87 79 85
69 73 89
John Peterson
3333
98 87 91 88 85
73 91 88
Mary Smith
4444
77 78 69 97 0
91 89 73

Larry White
5555
67 0 43 0 80
57 63 55
Tricia Nelson
7777
75 69 73 78 80
63 68 73
Mary Tuttle

8888
82 85 79 80 83
78 83 79
Ray Nelson
9999

54 59 57 53 51
59 53 57
Jane Doe_ErrorInAcct
1111
50 45 0 43 25

54 33 45
Tricia_ErrorInAcct Marie Black
1112
77 0 73 79 83
83 82 0

Paul Parmalee
1112
77 78 69 0 0

78 83 89
Janice Nece_ErrorInAcct
4442 123 ErrorInIdLine
97 99 93 91 0

83 90 89
Troy Marshall
1113
67 0 43 56 59
70 65 63
Brandon Palmer_ErrorInAcct

4443

54 59 43

59 53 65
Lynn Palmer
1114
45 62 43 33 0
45 0 43
Rick Meeker_ErrorInAcct
4445
75 69 73 78 97
79 88
Heather Brown
1115
85 83 89 80 87
90 89 85

Gage Monty_ErrorInAcct
5551
91 89 73 91 0 75
89 73 88
Laura Nibert_ErrorInAcct
5552
63 68 73 63 55
77 78 69 99

Brandon Harth
2223
91 89 73 78 97
83 90 89
Laura_ErrorInAcct
5552
63 68 73 63 55
77 78 69 99
Brian Walker
2224
75 69 73 79 83
83 79 88
Natalie Smith
2225
91 89 73 78 97
83 90 89
Ellen Palmer
2227
97 99 93 91 0
89 73 85
Mar 13 '06 #5

Banfa
Expert Mod 5K+
P: 8,916
I thought the temporary storage would work to store things so that I could throw out all for line if one was bad. I guess I was wrong.
No you are right this is not an unreasonably idea, get all lines then if there are any unrecoverable errors discard them all. But the way you have coded it will only work if you are absolutely sure that
  1. Each record always has 4 data lines
  2. There are no blank lines between the lines in a single record

Remember I have no view of the original problem specification and the constraints and assumptions that you are allowed to make so all my suggestions take the most generalised form. You have a better view of the problem and can therefore pick a more specialised solution.

Clearly you must have some test data that you are running through your code, like I said if you add output the output line to your error messages then you will be able to locate in the test data where you code is going wrong. You will then be able to tell if it is reasonable that it fails to parse at this point and work out where it is that it manages to start parsing the records again (I would add a success output line for each record successfully parsed to aid debugging). Examining the data at the point where parsing fails will give you a better idea of why it fails and, additionally, may give some indications of why your code fails to start parsing again.


I think you may have some errors in the sscanf calls in the way that you try to detect errors, for instance

taking your example record

John Doe
1111
98 87 69 97 89
85 91 88

Expand|Select|Wrap|Line Numbers
  1. if (sscanf (secondline, "%d, %d", &stuArr[i].id, &errnum) != 1)
  2. {
  3.   fprintf (stderr, "ERROR: Incorrect number of entries for the ID field of %s, %s\n", stuArr[i].lName, stuArr[i].fName);
  4.   continue;
  5. }
  6.  
The format string is "%d, %d", we are not expecting a comma, actually we are not expecting anything, if there is anything perhaps you should just put it in another string like so

Expand|Select|Wrap|Line Numbers
  1. if (sscanf (secondline, "%d %s", &stuArr[i].id, &errstring) != 1)
  2. {
  3.   fprintf (stderr, "ERROR: Incorrect number of entries for the ID field of %s, %s\n", stuArr[i].lName, stuArr[i].fName);
  4.   continue;
  5. }
  6.  
I do not know that this sort of thing is actually causing a problem I just thing this is a slightly better form of what you are already trying to do.
Mar 13 '06 #6

Banfa
Expert Mod 5K+
P: 8,916
Wait let me process the file and your code.
Mar 13 '06 #7

suzee_q00
P: 16
Thanks banfa that was my error. There should not be a comma between the %d's when scanf'ing the second line. I am considering going back to an immediate sscanf without error checking then seeing if I can develop some sort of post error checking. If a line has an error I can decrement my incrementor then move on to test the next structure in the array.
Mar 13 '06 #8

Banfa
Expert Mod 5K+
P: 8,916
I just tried you code and the problem is something I have already mentioned.

Look at you test data around the entry for "Mary Tuttle". It is quite clear from this bit of the file that your assumption "records can not have blank lines between the lines of data in a single record" is wrong. Blank lines can appear anywhere in the file.

In this case my suggestion that you use a wrapper for fgets to only return lines that are not blank is a good one. Here is the code I used

Expand|Select|Wrap|Line Numbers
  1. static char *GetNonBlankLine( char *buf, int len, FILE *fin )
  2. {
  3.     char *ret;
  4.  
  5.     do
  6.     {
  7.         ret = fgets( buf, BUFLEN, fin );
  8.         if ( ret == NULL )
  9.           return ret;
  10.         rmNl(buf);
  11.     }
  12.     while(lineWithBlanks(buf));
  13.  
  14.     return ret;
  15. }
  16.  
Replacing all fgets in your code with this function (and altering the loop code slightly because this function returns a line of text that isn;t blank and already has the newline removed) and making the change I suggested to the sscanf lines results in the file being parsed completely and nearly correctly.
There are 2 errors
  1. The first is minor, your error output if the name doesn't parse correctly assumes that both parts of the name have actually been parsed. However for Laura_ErrorInAcct this is not true because there is only 1 name on the line. Thus you get a lot of garbage output.
  2. For some reason the account for Jane Doe_ErrorInAcct parses correctly even though the name suggests it shouldn't but I don't know why that is.
Mar 13 '06 #9

suzee_q00
P: 16
This is what the finished piece of code looks. It reads the files correctly and kicks out the errors line. (some of the problem I was having was because there were spaces at the end of the lines in my datafile) I wish I could say that I am thrilled with my work but I still have a math error in figureAverages. I think it's because I am putting a character string into an integer variable and then trying to do math with it. I am ready to let it go at this point. I have spent way to much time with it.

Thanks for all your help and patience.
Expand|Select|Wrap|Line Numbers
  1. while ( ( fgets ( buf, BUFLEN, fin ) ) != NULL )   /*   pulls a line from "fin" up to the length of BUFLEN and stores it in "buf"   */
  2.  {
  3.       rmNl ( buf );   /*   remove new line   */
  4.       if ( !lineWithBlanks ( buf ) )
  5.       {
  6.          strcpy (firstline, buf);
  7.  
  8.          fgets ( buf, BUFLEN, fin );   /*   get a line, remove new line character, if line is empty get another line until you get a non-empty line.  remove new line from non-empty line   */
  9.          rmNl ( buf );   /*   remove new line   */
  10.          while ( lineWithBlanks ( buf ) )   
  11.             fgets ( buf, BUFLEN, fin );   /*   as long as you get a line with blanks, get a new line   */
  12.          rmNl ( buf );
  13.          strcpy (secondline, buf);
  14.  
  15.          fgets ( buf, BUFLEN, fin );
  16.          rmNl ( buf );  
  17.          while ( lineWithBlanks ( buf ) )
  18.             fgets ( buf, BUFLEN, fin );
  19.          rmNl ( buf );
  20.          strcpy (thirdline, buf);
  21.  
  22.          fgets ( buf, BUFLEN, fin );
  23.          rmNl ( buf );  
  24.          while ( lineWithBlanks ( buf ) )
  25.                     fgets ( buf, BUFLEN, fin );
  26.          rmNl ( buf );
  27.          strcpy (fourthline, buf);
  28.  
  29.          if (sscanf (firstline, "%s %s %s", stuArr[i].fName, stuArr[i].lName, errstr) != 2)
  30.               {
  31.                  fprintf (stderr, "ERROR: Incorrect number of entries for the name field of %s, %s, not written to file\n", stuArr[i].lName, stuArr[i].fName);
  32.                  continue;
  33.          }
  34.          if (sscanf (secondline, "%d, %d", &stuArr[i].id, &errnum) != 1)
  35.               {
  36.                  fprintf (stderr, "ERROR: Incorrect number of entries for the ID field of %s, %s\n", stuArr[i].lName, stuArr[i].fName);
  37.                  continue;
  38.               }
  39.               /*   read homework scores into seperate fields of hw  */
  40.               if (sscanf (atoi(thirdline), "%d %d %d %d %d %d", &stuArr[i].hw[0], &stuArr[i].hw[1], &stuArr[i].hw[2], &stuArr[i].hw[3], &stuArr[i].hw[4], &errnum) != NUM_HW)
  41.          {
  42.              fprintf (stderr, "ERROR: Incorrect number of entries for the homework field of %s, %s\n", stuArr[i].lName, stuArr[i].fName);
  43.                  continue;
  44.               }
  45.          if (sscanf (fourthline, "%d %d %d %d", &stuArr[i].exm[0], &stuArr[i].exm[1], &stuArr[i].exm[2], &errnum) != NUM_EXM)
  46.               {
  47.             fprintf (stderr, "ERROR: Incorrect number of entries for the exam field of %s, %s\n", stuArr[i].lName, stuArr[i].fName);
  48.                       continue;
  49.               }
  50.          stuArr[i].hwAvg = figureAverages (stuArr[i].hw, NUM_HW);
  51.          stuArr[i].exmAvg = figureAverages (stuArr[i].hw, NUM_EXM);
  52.          stuArr[i].grade = ltrGrade(stuArr[i].hwAvg + stuArr[i].exmAvg);
  53.          i++;
  54.       }   /*   end if !lineWithBlanks   */
  55.  
Mar 17 '06 #10

Post your reply

Sign in to post your reply or Sign up for a free account.